virtualbox 0.6.1 → 0.7.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/.yardopts +0 -1
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/lib/virtualbox/abstract_model/attributable.rb +1 -0
- data/lib/virtualbox/abstract_model/validatable.rb +133 -10
- data/lib/virtualbox/abstract_model.rb +3 -3
- data/lib/virtualbox/appliance.rb +5 -2
- data/lib/virtualbox/audio_adapter.rb +11 -3
- data/lib/virtualbox/bios.rb +10 -4
- data/lib/virtualbox/com/abstract_enum.rb +6 -5
- data/lib/virtualbox/com/abstract_implementer.rb +4 -2
- data/lib/virtualbox/com/abstract_interface.rb +6 -4
- data/lib/virtualbox/com/base_interface.rb +38 -0
- data/lib/virtualbox/com/ffi/interface.rb +14 -5
- data/lib/virtualbox/com/ffi/interfaces.rb +36 -32
- data/lib/virtualbox/com/ffi/util.rb +22 -4
- data/lib/virtualbox/com/ffi_interface.rb +39 -8
- data/lib/virtualbox/com/implementer/base.rb +2 -2
- data/lib/virtualbox/com/implementer/ffi.rb +55 -44
- data/lib/virtualbox/com/implementer/mscom.rb +2 -4
- data/lib/virtualbox/com/interface/3.1.x/appliance.rb +22 -0
- data/lib/virtualbox/com/interface/3.1.x/audio_adapter.rb +15 -0
- data/lib/virtualbox/com/interface/3.1.x/audio_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/audio_driver_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/bios_boot_menu_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/bios_settings.rb +21 -0
- data/lib/virtualbox/com/interface/3.1.x/clipboard_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/console.rb +50 -0
- data/lib/virtualbox/com/interface/3.1.x/cpu_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/device_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/dhcp_server.rb +22 -0
- data/lib/virtualbox/com/interface/3.1.x/firmware_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/guest_os_type.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/host.rb +42 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface.rb +30 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface_medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface_status.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/host_network_interface_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/host_usb_device.rb +13 -0
- data/lib/virtualbox/com/interface/3.1.x/host_usb_device_filter.rb +13 -0
- data/lib/virtualbox/com/interface/3.1.x/hw_virt_ex_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/machine.rb +105 -0
- data/lib/virtualbox/com/interface/3.1.x/machine_state.rb +14 -0
- data/lib/virtualbox/com/interface/3.1.x/medium.rb +50 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_attachment.rb +18 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_format.rb +18 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/medium_variant.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/network_adapter.rb +30 -0
- data/lib/virtualbox/com/interface/3.1.x/network_adapter_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/network_attachment_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/nsiexception.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/nsisupports.rb +15 -0
- data/lib/virtualbox/com/interface/3.1.x/parallel_port.rb +17 -0
- data/lib/virtualbox/com/interface/3.1.x/port_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/progress.rb +63 -0
- data/lib/virtualbox/com/interface/3.1.x/serial_port.rb +19 -0
- data/lib/virtualbox/com/interface/3.1.x/session.rb +18 -0
- data/lib/virtualbox/com/interface/3.1.x/session_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/session_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/shared_folder.rb +17 -0
- data/lib/virtualbox/com/interface/3.1.x/snapshot.rb +20 -0
- data/lib/virtualbox/com/interface/3.1.x/storage_bus.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/storage_controller.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/storage_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/system_properties.rb +37 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_controller.rb +20 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device.rb +24 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device_filter.rb +23 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device_filter_action.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/usb_device_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_box_error_info.rb +17 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_system_description.rb +19 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_system_description_type.rb +14 -0
- data/lib/virtualbox/com/interface/3.1.x/virtual_system_description_value_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/virtualbox.rb +67 -0
- data/lib/virtualbox/com/interface/3.1.x/vrdp_auth_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.1.x/vrdp_server.rb +19 -0
- data/lib/virtualbox/com/interface/3.2.x/appliance.rb +22 -0
- data/lib/virtualbox/com/interface/3.2.x/audio_adapter.rb +15 -0
- data/lib/virtualbox/com/interface/3.2.x/audio_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/audio_driver_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/bios_boot_menu_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/bios_settings.rb +21 -0
- data/lib/virtualbox/com/interface/3.2.x/clipboard_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/console.rb +50 -0
- data/lib/virtualbox/com/interface/3.2.x/cpu_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/device_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/dhcp_server.rb +22 -0
- data/lib/virtualbox/com/interface/3.2.x/firmware_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/guest.rb +13 -0
- data/lib/virtualbox/com/interface/3.2.x/guest_os_type.rb +33 -0
- data/lib/virtualbox/com/interface/3.2.x/host.rb +43 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface.rb +30 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface_medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface_status.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/host_network_interface_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/host_usb_device.rb +13 -0
- data/lib/virtualbox/com/interface/3.2.x/host_usb_device_filter.rb +13 -0
- data/lib/virtualbox/com/interface/3.2.x/hw_virt_ex_property_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/keyboard_hid_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/machine.rb +118 -0
- data/lib/virtualbox/com/interface/3.2.x/machine_state.rb +14 -0
- data/lib/virtualbox/com/interface/3.2.x/medium.rb +51 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_attachment.rb +18 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_format.rb +18 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/medium_variant.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/nat_alias_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/nat_engine.rb +27 -0
- data/lib/virtualbox/com/interface/3.2.x/nat_protocol.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/network_adapter.rb +34 -0
- data/lib/virtualbox/com/interface/3.2.x/network_adapter_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/network_attachment_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/nsiexception.rb +23 -0
- data/lib/virtualbox/com/interface/3.2.x/nsisupports.rb +15 -0
- data/lib/virtualbox/com/interface/3.2.x/parallel_port.rb +17 -0
- data/lib/virtualbox/com/interface/3.2.x/pointing_hid_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/port_mode.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/progress.rb +63 -0
- data/lib/virtualbox/com/interface/3.2.x/serial_port.rb +19 -0
- data/lib/virtualbox/com/interface/3.2.x/session.rb +18 -0
- data/lib/virtualbox/com/interface/3.2.x/session_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/session_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/shared_folder.rb +17 -0
- data/lib/virtualbox/com/interface/3.2.x/snapshot.rb +20 -0
- data/lib/virtualbox/com/interface/3.2.x/storage_bus.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/storage_controller.rb +24 -0
- data/lib/virtualbox/com/interface/3.2.x/storage_controller_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/system_properties.rb +42 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_controller.rb +21 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device.rb +24 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device_filter.rb +23 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device_filter_action.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/usb_device_state.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_box_error_info.rb +17 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_system_description.rb +19 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_system_description_type.rb +14 -0
- data/lib/virtualbox/com/interface/3.2.x/virtual_system_description_value_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/virtualbox.rb +67 -0
- data/lib/virtualbox/com/interface/3.2.x/vrdp_auth_type.rb +11 -0
- data/lib/virtualbox/com/interface/3.2.x/vrdp_server.rb +21 -0
- data/lib/virtualbox/com/mscom_interface.rb +9 -4
- data/lib/virtualbox/com/nil_interface.rb +7 -0
- data/lib/virtualbox/com/util.rb +16 -2
- data/lib/virtualbox/com.rb +1 -1
- data/lib/virtualbox/cpu.rb +61 -0
- data/lib/virtualbox/dhcp_server.rb +89 -0
- data/lib/virtualbox/dvd.rb +2 -2
- data/lib/virtualbox/exceptions.rb +4 -0
- data/lib/virtualbox/ext/platform.rb +2 -2
- data/lib/virtualbox/extra_data.rb +5 -6
- data/lib/virtualbox/forwarded_port.rb +11 -7
- data/lib/virtualbox/global.rb +17 -6
- data/lib/virtualbox/hard_drive.rb +129 -66
- data/lib/virtualbox/host.rb +71 -0
- data/lib/virtualbox/host_network_interface.rb +137 -0
- data/lib/virtualbox/hw_virtualization.rb +12 -6
- data/lib/virtualbox/lib.rb +2 -2
- data/lib/virtualbox/media.rb +2 -2
- data/lib/virtualbox/medium.rb +10 -3
- data/lib/virtualbox/medium_attachment.rb +2 -2
- data/lib/virtualbox/network_adapter.rb +12 -4
- data/lib/virtualbox/proxies/collection.rb +26 -6
- data/lib/virtualbox/shared_folder.rb +22 -15
- data/lib/virtualbox/snapshot.rb +185 -0
- data/lib/virtualbox/storage_controller.rb +3 -3
- data/lib/virtualbox/system_properties.rb +1 -1
- data/lib/virtualbox/usb_controller.rb +8 -4
- data/lib/virtualbox/usb_device_filter.rb +74 -0
- data/lib/virtualbox/version.rb +12 -1
- data/lib/virtualbox/virtual_system_description.rb +4 -4
- data/lib/virtualbox/vm.rb +273 -64
- data/lib/virtualbox/vrdp_server.rb +59 -0
- data/test/test_helper.rb +7 -1
- data/test/virtualbox/abstract_model/attributable_test.rb +8 -0
- data/test/virtualbox/abstract_model/relatable_test.rb +5 -5
- data/test/virtualbox/abstract_model/validatable_test.rb +186 -3
- data/test/virtualbox/abstract_model_test.rb +3 -3
- data/test/virtualbox/appliance_test.rb +8 -1
- data/test/virtualbox/com/abstract_enum_test.rb +1 -0
- data/test/virtualbox/com/abstract_implementer_test.rb +4 -3
- data/test/virtualbox/com/abstract_interface_test.rb +3 -2
- data/test/virtualbox/com/ffi/interface_test.rb +4 -4
- data/test/virtualbox/com/ffi/util_test.rb +23 -1
- data/test/virtualbox/com/implementer/base_test.rb +4 -3
- data/test/virtualbox/com/implementer/ffi_test.rb +18 -10
- data/test/virtualbox/cpu_test.rb +103 -0
- data/test/virtualbox/dhcp_server_test.rb +165 -0
- data/test/virtualbox/extra_data_test.rb +4 -3
- data/test/virtualbox/forwarded_port_test.rb +17 -4
- data/test/virtualbox/hard_drive_test.rb +54 -5
- data/test/virtualbox/host_network_interface_test.rb +254 -0
- data/test/virtualbox/host_test.rb +94 -0
- data/test/virtualbox/network_adapter_test.rb +30 -1
- data/test/virtualbox/proxies/collection_test.rb +63 -21
- data/test/virtualbox/shared_folder_test.rb +16 -13
- data/test/virtualbox/snapshot_test.rb +231 -0
- data/test/virtualbox/storage_controller_test.rb +1 -1
- data/test/virtualbox/usb_controller_test.rb +7 -0
- data/test/virtualbox/usb_device_filter_test.rb +93 -0
- data/test/virtualbox/version_test.rb +13 -1
- data/test/virtualbox/vm_test.rb +245 -11
- data/test/virtualbox/vrdp_server_test.rb +83 -0
- data/virtualbox.gemspec +183 -97
- metadata +182 -96
- data/TODO +0 -9
- data/lib/virtualbox/com/interface/appliance.rb +0 -20
- data/lib/virtualbox/com/interface/audio_adapter.rb +0 -13
- data/lib/virtualbox/com/interface/audio_controller_type.rb +0 -9
- data/lib/virtualbox/com/interface/audio_driver_type.rb +0 -9
- data/lib/virtualbox/com/interface/bios_boot_menu_mode.rb +0 -9
- data/lib/virtualbox/com/interface/bios_settings.rb +0 -19
- data/lib/virtualbox/com/interface/clipboard_mode.rb +0 -9
- data/lib/virtualbox/com/interface/console.rb +0 -48
- data/lib/virtualbox/com/interface/cpu_property_type.rb +0 -9
- data/lib/virtualbox/com/interface/device_type.rb +0 -9
- data/lib/virtualbox/com/interface/dhcp_server.rb +0 -20
- data/lib/virtualbox/com/interface/firmware_type.rb +0 -9
- data/lib/virtualbox/com/interface/guest_os_type.rb +0 -21
- data/lib/virtualbox/com/interface/host.rb +0 -40
- data/lib/virtualbox/com/interface/host_network_interface.rb +0 -28
- data/lib/virtualbox/com/interface/host_network_interface_medium_type.rb +0 -9
- data/lib/virtualbox/com/interface/host_network_interface_status.rb +0 -9
- data/lib/virtualbox/com/interface/host_network_interface_type.rb +0 -9
- data/lib/virtualbox/com/interface/host_usb_device.rb +0 -11
- data/lib/virtualbox/com/interface/host_usb_device_filter.rb +0 -11
- data/lib/virtualbox/com/interface/hw_virt_ex_property_type.rb +0 -9
- data/lib/virtualbox/com/interface/machine.rb +0 -103
- data/lib/virtualbox/com/interface/machine_state.rb +0 -12
- data/lib/virtualbox/com/interface/medium.rb +0 -48
- data/lib/virtualbox/com/interface/medium_attachment.rb +0 -16
- data/lib/virtualbox/com/interface/medium_format.rb +0 -16
- data/lib/virtualbox/com/interface/medium_state.rb +0 -9
- data/lib/virtualbox/com/interface/medium_type.rb +0 -9
- data/lib/virtualbox/com/interface/medium_variant.rb +0 -9
- data/lib/virtualbox/com/interface/network_adapter.rb +0 -28
- data/lib/virtualbox/com/interface/network_adapter_type.rb +0 -9
- data/lib/virtualbox/com/interface/network_attachment_type.rb +0 -9
- data/lib/virtualbox/com/interface/nsiexception.rb +0 -21
- data/lib/virtualbox/com/interface/nsisupports.rb +0 -13
- data/lib/virtualbox/com/interface/parallel_port.rb +0 -15
- data/lib/virtualbox/com/interface/port_mode.rb +0 -9
- data/lib/virtualbox/com/interface/progress.rb +0 -58
- data/lib/virtualbox/com/interface/serial_port.rb +0 -17
- data/lib/virtualbox/com/interface/session.rb +0 -16
- data/lib/virtualbox/com/interface/session_state.rb +0 -9
- data/lib/virtualbox/com/interface/session_type.rb +0 -9
- data/lib/virtualbox/com/interface/shared_folder.rb +0 -15
- data/lib/virtualbox/com/interface/snapshot.rb +0 -18
- data/lib/virtualbox/com/interface/storage_bus.rb +0 -9
- data/lib/virtualbox/com/interface/storage_controller.rb +0 -21
- data/lib/virtualbox/com/interface/storage_controller_type.rb +0 -9
- data/lib/virtualbox/com/interface/system_properties.rb +0 -35
- data/lib/virtualbox/com/interface/usb_controller.rb +0 -18
- data/lib/virtualbox/com/interface/usb_device.rb +0 -22
- data/lib/virtualbox/com/interface/usb_device_filter.rb +0 -21
- data/lib/virtualbox/com/interface/usb_device_filter_action.rb +0 -9
- data/lib/virtualbox/com/interface/usb_device_state.rb +0 -9
- data/lib/virtualbox/com/interface/virtual_box_error_info.rb +0 -15
- data/lib/virtualbox/com/interface/virtual_system_description.rb +0 -17
- data/lib/virtualbox/com/interface/virtual_system_description_type.rb +0 -12
- data/lib/virtualbox/com/interface/virtual_system_description_value_type.rb +0 -9
- data/lib/virtualbox/com/interface/virtualbox.rb +0 -54
- data/lib/virtualbox/com/interface/vrdp_auth_type.rb +0 -9
- data/lib/virtualbox/com/interface/vrdp_server.rb +0 -17
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
module VirtualBox
|
|
2
2
|
module COM
|
|
3
|
-
class FFIInterface
|
|
3
|
+
class FFIInterface < BaseInterface
|
|
4
4
|
extend ::FFI::Library
|
|
5
|
+
include Logger
|
|
5
6
|
|
|
6
7
|
# Constant used to initialize the XPCOM C interface
|
|
7
8
|
XPCOMC_VERSION = 0x00020000
|
|
@@ -16,7 +17,7 @@ module VirtualBox
|
|
|
16
17
|
attr_reader :virtualbox
|
|
17
18
|
attr_reader :session
|
|
18
19
|
|
|
19
|
-
class <<self
|
|
20
|
+
class << self
|
|
20
21
|
# Sets up the FFI interface and also initializes the interface,
|
|
21
22
|
# returning an instance of {FFIInterface}.
|
|
22
23
|
def create(lib_path=nil)
|
|
@@ -40,6 +41,7 @@ module VirtualBox
|
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
def initialize
|
|
44
|
+
super
|
|
43
45
|
initialize_com
|
|
44
46
|
end
|
|
45
47
|
|
|
@@ -51,15 +53,44 @@ module VirtualBox
|
|
|
51
53
|
xpcom_pointer = self.class.VBoxGetXPCOMCFunctions(XPCOMC_VERSION)
|
|
52
54
|
@xpcom = FFI::VBOXXPCOMC.new(xpcom_pointer)
|
|
53
55
|
|
|
56
|
+
initialize_singletons
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Initializes the VirtualBox and Session interfaces. It goes through
|
|
60
|
+
# the various directories until it finds a working pair.
|
|
61
|
+
def initialize_singletons
|
|
62
|
+
interface_dir = File.expand_path(File.join(File.dirname(__FILE__), "interface"))
|
|
63
|
+
Dir[File.join(interface_dir, "*")].each do |f|
|
|
64
|
+
if File.directory?(f)
|
|
65
|
+
return if initialize_for_version(File.basename(f))
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Initializes the FFI interface for a specific version.
|
|
71
|
+
def initialize_for_version(version)
|
|
72
|
+
logger.debug("FFI init: Trying version #{version}")
|
|
73
|
+
|
|
74
|
+
# Setup the FFI classes
|
|
75
|
+
VirtualBox::COM::FFI.setup(version)
|
|
76
|
+
virtualbox_klass = COM::Util.versioned_interface(:VirtualBox)
|
|
77
|
+
session_klass = COM::Util.versioned_interface(:Session)
|
|
78
|
+
|
|
79
|
+
# Setup the OUT pointers
|
|
54
80
|
virtualbox_ptr = ::FFI::MemoryPointer.new(:pointer)
|
|
55
81
|
session_ptr = ::FFI::MemoryPointer.new(:pointer)
|
|
56
82
|
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
@
|
|
60
|
-
@
|
|
61
|
-
|
|
83
|
+
# Call the initialization functions
|
|
84
|
+
@xpcom[:pfnComInitialize].call(virtualbox_klass::IID_STR, virtualbox_ptr, session_klass::IID_STR, session_ptr)
|
|
85
|
+
@virtualbox = virtualbox_klass.new(Implementer::FFI, self, virtualbox_ptr.get_pointer(0))
|
|
86
|
+
@session = session_klass.new(Implementer::FFI, self, session_ptr.get_pointer(0))
|
|
87
|
+
|
|
88
|
+
logger.debug(" -- Valid version")
|
|
89
|
+
true
|
|
90
|
+
rescue Exception => e
|
|
91
|
+
logger.debug(" -- Invalid version")
|
|
92
|
+
false
|
|
62
93
|
end
|
|
63
94
|
end
|
|
64
95
|
end
|
|
65
|
-
end
|
|
96
|
+
end
|
|
@@ -16,7 +16,7 @@ module VirtualBox
|
|
|
16
16
|
#
|
|
17
17
|
# @return [Class]
|
|
18
18
|
def interface_klass(type)
|
|
19
|
-
COM::
|
|
19
|
+
::VirtualBox::COM::FFI::Util.interface_klass(type)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# Gives the C type and inferred type of a parameter type. Quite confusing
|
|
@@ -37,7 +37,7 @@ module VirtualBox
|
|
|
37
37
|
c_type = :pointer
|
|
38
38
|
else
|
|
39
39
|
# Try to get the class from the interfaces
|
|
40
|
-
interface =
|
|
40
|
+
interface = interface_klass(type)
|
|
41
41
|
|
|
42
42
|
c_type = :pointer
|
|
43
43
|
|
|
@@ -3,7 +3,6 @@ module VirtualBox
|
|
|
3
3
|
module Implementer
|
|
4
4
|
class FFI < Base
|
|
5
5
|
attr_reader :ffi_interface
|
|
6
|
-
attr_reader :lib
|
|
7
6
|
|
|
8
7
|
# Initializes the FFI implementer which takes an {VirtualBox::COM::AbstractInterface AbstractInterface}
|
|
9
8
|
# instant and FFI pointer and initializes everything required to
|
|
@@ -12,9 +11,8 @@ module VirtualBox
|
|
|
12
11
|
# @param [VirtualBox::COM::AbstractInteface] inteface
|
|
13
12
|
# @param [FFI::Pointer] pointer
|
|
14
13
|
def initialize(interface, lib_base, pointer)
|
|
15
|
-
super(interface)
|
|
14
|
+
super(interface, lib_base)
|
|
16
15
|
|
|
17
|
-
@lib = lib_base
|
|
18
16
|
@ffi_interface = ffi_class.new(pointer)
|
|
19
17
|
end
|
|
20
18
|
|
|
@@ -30,7 +28,7 @@ module VirtualBox
|
|
|
30
28
|
klass_name = interface.class.to_s.split("::").last
|
|
31
29
|
|
|
32
30
|
# Get the associated FFI class
|
|
33
|
-
COM::FFI.const_get(klass_name)
|
|
31
|
+
COM::FFI.const_get(::VirtualBox::COM::Util.version_const).const_get(klass_name)
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
# Reads a property from the interface with the given name.
|
|
@@ -67,8 +65,8 @@ module VirtualBox
|
|
|
67
65
|
formal_args = spec_to_args(spec, args)
|
|
68
66
|
|
|
69
67
|
# Call the function.
|
|
70
|
-
logger.debug("FFI call: #{name} #{args.inspect}")
|
|
71
|
-
call_and_check(
|
|
68
|
+
logger.debug("FFI call: #{name} #{args.inspect} #{formal_args.inspect}")
|
|
69
|
+
call_and_check(name, ffi_interface.vtbl_parent, *formal_args)
|
|
72
70
|
|
|
73
71
|
# Extract the values from the formal args array, again based on the
|
|
74
72
|
# spec (and the various :out parameters)
|
|
@@ -85,7 +83,7 @@ module VirtualBox
|
|
|
85
83
|
# Checks the result of a method call for an error, and if an error
|
|
86
84
|
# occurs, then raises an exception.
|
|
87
85
|
def call_and_check(function, *args)
|
|
88
|
-
result = function.call(*args)
|
|
86
|
+
result = ffi_interface.vtbl[function].call(*args)
|
|
89
87
|
|
|
90
88
|
# Ignore NS_ERROR_NOT_IMPLEMENTED, since it seems to be raised for
|
|
91
89
|
# things which aren't really exceptional
|
|
@@ -129,45 +127,58 @@ module VirtualBox
|
|
|
129
127
|
def spec_to_args(spec, args=[])
|
|
130
128
|
args = args.dup
|
|
131
129
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
results = spec.inject([]) do |results, item|
|
|
131
|
+
single_type_to_arg(args, item, results)
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Converts a single type and args list to the proper formal args list
|
|
136
|
+
def single_type_to_arg(args, item, results)
|
|
137
|
+
if item.is_a?(Array) && item[0] == :out
|
|
138
|
+
if item[1].is_a?(Array)
|
|
139
|
+
# For arrays we need two pointers: one for size, and one for the
|
|
140
|
+
# actual array
|
|
141
|
+
results << pointer_for_type(T_UINT32)
|
|
142
|
+
results << pointer_for_type(item[1][0])
|
|
143
|
+
else
|
|
144
|
+
results << pointer_for_type(item[1])
|
|
145
|
+
end
|
|
146
|
+
elsif item.is_a?(Array) && item.length == 1
|
|
147
|
+
# Convert the array to a size, then array parameter
|
|
148
|
+
data = args.shift
|
|
149
|
+
results << data.length
|
|
150
|
+
results << data.inject([]) do |converted_data, single|
|
|
151
|
+
single_type_to_arg([single], item[0], converted_data)
|
|
152
|
+
end
|
|
153
|
+
elsif item == WSTRING
|
|
154
|
+
# We have to convert the arg to a unicode string
|
|
155
|
+
results << string_to_utf16(args.shift)
|
|
156
|
+
elsif item == T_BOOL
|
|
157
|
+
results << (args.shift ? 1 : 0)
|
|
158
|
+
elsif item.to_s[0,1] == item.to_s[0,1].upcase
|
|
159
|
+
# Try to get the class from the interfaces
|
|
160
|
+
interface = interface_klass(item.to_sym)
|
|
161
|
+
|
|
162
|
+
if interface.superclass == COM::AbstractInterface
|
|
163
|
+
# For interfaces, get the instance, then dig deep to get the pointer
|
|
164
|
+
# to the VtblParent, which is what the API expects
|
|
165
|
+
instance = args.shift
|
|
166
|
+
|
|
167
|
+
results << if !instance.nil?
|
|
168
|
+
instance.implementer.ffi_interface.vtbl_parent
|
|
138
169
|
else
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
elsif item == WSTRING
|
|
142
|
-
# We have to convert the arg to a unicode string
|
|
143
|
-
string_to_utf16(args.shift)
|
|
144
|
-
elsif item == T_BOOL
|
|
145
|
-
args.shift ? 1 : 0
|
|
146
|
-
elsif item.to_s[0,1] == item.to_s[0,1].upcase
|
|
147
|
-
# Try to get the class from the interfaces
|
|
148
|
-
interface = interface_klass(item.to_sym)
|
|
149
|
-
|
|
150
|
-
if interface.superclass == COM::AbstractInterface
|
|
151
|
-
# For interfaces, get the instance, then dig deep to get the pointer
|
|
152
|
-
# to the VtblParent, which is what the API expects
|
|
153
|
-
instance = args.shift
|
|
154
|
-
|
|
155
|
-
if !instance.nil?
|
|
156
|
-
instance.implementer.ffi_interface.vtbl_parent
|
|
157
|
-
else
|
|
158
|
-
# If the argument was nil, just pass a nil pointer as the argument
|
|
159
|
-
nil
|
|
160
|
-
end
|
|
161
|
-
elsif interface.superclass == COM::AbstractEnum
|
|
162
|
-
# For enums, we need the value of the enum
|
|
163
|
-
interface.index(args.shift.to_sym)
|
|
170
|
+
# If the argument was nil, just pass a nil pointer as the argument
|
|
171
|
+
nil
|
|
164
172
|
end
|
|
165
|
-
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
args.shift
|
|
173
|
+
elsif interface.superclass == COM::AbstractEnum
|
|
174
|
+
# For enums, we need the value of the enum
|
|
175
|
+
results << interface.index(args.shift.to_sym)
|
|
169
176
|
end
|
|
170
|
-
|
|
177
|
+
else
|
|
178
|
+
# Simply replace spec item with next item in args
|
|
179
|
+
# list
|
|
180
|
+
results << args.shift
|
|
181
|
+
end
|
|
171
182
|
end
|
|
172
183
|
|
|
173
184
|
# Takes a spec and a formal parameter list and returns the output from
|
|
@@ -347,4 +358,4 @@ module VirtualBox
|
|
|
347
358
|
end
|
|
348
359
|
end
|
|
349
360
|
end
|
|
350
|
-
end
|
|
361
|
+
end
|
|
@@ -2,7 +2,6 @@ module VirtualBox
|
|
|
2
2
|
module COM
|
|
3
3
|
module Implementer
|
|
4
4
|
class MSCOM < Base
|
|
5
|
-
attr_reader :lib
|
|
6
5
|
attr_reader :object
|
|
7
6
|
|
|
8
7
|
# Initializes the MSCOM implementer.
|
|
@@ -10,9 +9,8 @@ module VirtualBox
|
|
|
10
9
|
# @param [AbstractInterface] inteface
|
|
11
10
|
# @param [FFI::Pointer] pointer
|
|
12
11
|
def initialize(interface, lib_base, object)
|
|
13
|
-
super(interface)
|
|
12
|
+
super(interface, lib_base)
|
|
14
13
|
|
|
15
|
-
@lib = lib_base
|
|
16
14
|
@object = object
|
|
17
15
|
end
|
|
18
16
|
|
|
@@ -174,4 +172,4 @@ module VirtualBox
|
|
|
174
172
|
end
|
|
175
173
|
end
|
|
176
174
|
end
|
|
177
|
-
end
|
|
175
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class Appliance < AbstractInterface
|
|
6
|
+
IID = "e3ba9ab9-ac2c-4266-8bd2-91c4bf721ceb"
|
|
7
|
+
|
|
8
|
+
property :path, WSTRING, :readonly => true
|
|
9
|
+
property :disks, [WSTRING], :readonly => true
|
|
10
|
+
property :virtual_system_descriptions, [:VirtualSystemDescription], :readonly => true
|
|
11
|
+
|
|
12
|
+
function :read, :Progress, [WSTRING]
|
|
13
|
+
function :interpret, nil, []
|
|
14
|
+
function :import_machines, :Progress, []
|
|
15
|
+
function :create_vfs_explorer, :VFSExplorer, [WSTRING]
|
|
16
|
+
function :write, :Progress, [WSTRING, WSTRING]
|
|
17
|
+
function :get_warnings, [WSTRING], []
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class AudioAdapter < AbstractInterface
|
|
6
|
+
IID = "921873db-5f3f-4b69-91f9-7be9e535a2cb"
|
|
7
|
+
|
|
8
|
+
property :enabled, T_BOOL
|
|
9
|
+
property :audio_controller, :AudioControllerType
|
|
10
|
+
property :audio_driver, :AudioDriverType
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class BIOSSettings < AbstractInterface
|
|
6
|
+
IID = "38b54279-dc35-4f5e-a431-835b867c6b5e"
|
|
7
|
+
|
|
8
|
+
property :logo_fade_in, T_BOOL
|
|
9
|
+
property :logo_fade_out, T_BOOL
|
|
10
|
+
property :logo_display_time, T_UINT32
|
|
11
|
+
property :logo_image_path, WSTRING
|
|
12
|
+
property :boot_menu_mode, :BIOSBootMenuMode
|
|
13
|
+
property :acpi_enabled, T_BOOL
|
|
14
|
+
property :io_apic_enabled, T_BOOL
|
|
15
|
+
property :time_offset, T_INT64
|
|
16
|
+
property :pxe_debug_enabled, T_BOOL
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class Console < AbstractInterface
|
|
6
|
+
IID = "6375231a-c17c-464b-92cb-ae9e128d71c3"
|
|
7
|
+
|
|
8
|
+
property :machine, :Machine, :readonly => true
|
|
9
|
+
property :state, :MachineState, :readonly => true
|
|
10
|
+
property :guest, :Guest, :readonly => true
|
|
11
|
+
property :keyboard, :Keyboard, :readonly => true
|
|
12
|
+
property :mouse, :Mouse, :readonly => true
|
|
13
|
+
property :display, :Display, :readonly => true
|
|
14
|
+
property :debugger, :MachineDebugger, :readonly => true
|
|
15
|
+
property :usb_devices, [:USBDevice], :readonly => true
|
|
16
|
+
property :remote_usb_devices, [:HostUSBDevice], :readonly => true
|
|
17
|
+
property :shared_folders, [:SharedFolder], :readonly => true
|
|
18
|
+
property :remote_display_info, :RemoteDisplayInfo, :readonly => true
|
|
19
|
+
|
|
20
|
+
function :power_up, :Progress, []
|
|
21
|
+
function :power_up_paused, :Progress, []
|
|
22
|
+
function :power_down, :Progress, []
|
|
23
|
+
function :reset, nil, []
|
|
24
|
+
function :pause, nil, []
|
|
25
|
+
function :resume, nil, []
|
|
26
|
+
function :power_button, nil, []
|
|
27
|
+
function :sleep_button, nil, []
|
|
28
|
+
function :get_power_button_handled, T_BOOL, []
|
|
29
|
+
function :get_guest_entered_acpi_mode, T_BOOL, []
|
|
30
|
+
function :save_state, :Progress, []
|
|
31
|
+
function :adopt_saved_state, nil, [WSTRING]
|
|
32
|
+
function :forget_saved_state, nil, [T_BOOL]
|
|
33
|
+
function :get_device_activity, :DeviceActivity, [:DeviceType]
|
|
34
|
+
function :attach_usb_device, nil, [WSTRING]
|
|
35
|
+
function :detach_usb_device, :USBDevice, [WSTRING]
|
|
36
|
+
function :find_usb_device_by_address, :USBDevice, [WSTRING]
|
|
37
|
+
function :find_usb_device_by_id, :USBDevice, [WSTRING]
|
|
38
|
+
function :create_shared_folder, nil, [WSTRING, WSTRING, T_BOOL]
|
|
39
|
+
function :remove_shared_folder, nil, [WSTRING]
|
|
40
|
+
function :take_snapshot, :Progress, [WSTRING, WSTRING]
|
|
41
|
+
function :delete_snapshot, :Progress, [WSTRING]
|
|
42
|
+
function :restore_snapshot, :Progress, [:Snapshot]
|
|
43
|
+
function :teleport, :Progress, [WSTRING, T_UINT32, WSTRING, T_UINT32]
|
|
44
|
+
function :register_callback, nil, [:ConsoleCallback]
|
|
45
|
+
function :unregister_callback, nil, [:ConsoleCallback]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class DHCPServer < AbstractInterface
|
|
6
|
+
IID = "6cfe387c-74fb-4ca7-bff6-973bec8af7a3"
|
|
7
|
+
|
|
8
|
+
property :enabled, T_BOOL
|
|
9
|
+
property :ip_address, WSTRING, :readonly => true
|
|
10
|
+
property :network_mask, WSTRING, :readonly => true
|
|
11
|
+
property :network_name, WSTRING, :readonly => true
|
|
12
|
+
property :lower_ip, WSTRING, :readonly => true
|
|
13
|
+
property :upper_ip, WSTRING, :readonly => true
|
|
14
|
+
|
|
15
|
+
function :set_configuration, nil, [WSTRING, WSTRING, WSTRING, WSTRING]
|
|
16
|
+
function :start, nil, [WSTRING, WSTRING, WSTRING]
|
|
17
|
+
function :stop, nil, []
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class GuestOSType < AbstractInterface
|
|
6
|
+
IID = "cfe9e64c-4430-435b-9e7c-e3d8e417bd58"
|
|
7
|
+
|
|
8
|
+
property :family_id, WSTRING, :readonly => true
|
|
9
|
+
property :family_description, WSTRING, :readonly => true
|
|
10
|
+
property :id, WSTRING, :readonly => true
|
|
11
|
+
property :description, WSTRING, :readonly => true
|
|
12
|
+
property :is_64_bit, T_BOOL, :readonly => true
|
|
13
|
+
property :recommended_io_apic, T_BOOL, :readonly => true
|
|
14
|
+
property :recommended_virt_ex, T_BOOL, :readonly => true
|
|
15
|
+
property :recommended_ram, T_UINT32, :readonly => true
|
|
16
|
+
property :recommended_vram, T_UINT32, :readonly => true
|
|
17
|
+
property :recommended_hdd, T_UINT32, :readonly => true
|
|
18
|
+
property :adapter_type, :NetworkAdapterType, :readonly => true
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class Host < AbstractInterface
|
|
6
|
+
IID_STR = "e380cbfc-ae65-4fa6-899e-45ded6b3132a"
|
|
7
|
+
|
|
8
|
+
property :dvd_drives, [:Medium], :readonly => true
|
|
9
|
+
property :floppy_drives, [:Medium], :readonly => true
|
|
10
|
+
property :usb_devices, [:HostUSBDevice], :readonly => true
|
|
11
|
+
property :usb_device_filters, [:HostUSBDeviceFilter], :readonly => true
|
|
12
|
+
property :network_interfaces, [:HostNetworkInterface], :readonly => true
|
|
13
|
+
property :processor_count, T_ULONG, :readonly => true
|
|
14
|
+
property :processor_online_count, T_ULONG, :readonly => true
|
|
15
|
+
property :memory_size, T_ULONG, :readonly => true
|
|
16
|
+
property :memory_available, T_ULONG, :readonly => true
|
|
17
|
+
property :operating_system, WSTRING, :readonly => true
|
|
18
|
+
property :os_version, WSTRING, :readonly => true
|
|
19
|
+
property :utc_time, T_INT64, :readonly => true
|
|
20
|
+
property :acceleration_3d_available, T_BOOL, :readonly => true
|
|
21
|
+
|
|
22
|
+
function :get_processor_speed, T_ULONG, [T_UINT32]
|
|
23
|
+
function :get_processor_feature, T_BOOL, [T_UINT32] # TODO ENUM
|
|
24
|
+
function :get_processor_description, WSTRING, [T_UINT32]
|
|
25
|
+
function :get_processor_cpu_id_leaf, nil, [T_UINT32, T_UINT32, T_UINT32, [:out, T_UINT32], [:out, T_UINT32], [:out, T_UINT32], [:out, T_UINT32]]
|
|
26
|
+
function :create_host_only_network_interface, :Progress, [[:out, :HostNetworkInterface]]
|
|
27
|
+
function :remove_host_only_network_interface, :Progress, [WSTRING]
|
|
28
|
+
function :create_usb_device_filter, :HostUSBDeviceFilter, [WSTRING]
|
|
29
|
+
function :insert_usb_device_filter, nil, [T_UINT32, :HostUSBDeviceFilter]
|
|
30
|
+
function :remove_usb_device_filter, nil, [T_UINT32]
|
|
31
|
+
function :find_host_dvd_drive, :Medium, [WSTRING]
|
|
32
|
+
function :find_host_floppy_drive, :Medium, [WSTRING]
|
|
33
|
+
function :find_host_network_interface_by_name, :HostNetworkInterface, [WSTRING]
|
|
34
|
+
function :find_host_network_interface_by_id, :HostNetworkInterface, [WSTRING]
|
|
35
|
+
function :find_host_network_interfaces_of_type, [:HostNetworkInterface], [:HostNetworkInterfaceType]
|
|
36
|
+
function :find_usb_device_by_id, :HostUSBDevice, [WSTRING]
|
|
37
|
+
function :find_usb_device_by_address, :HostUSBDevice, [WSTRING]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module VirtualBox
|
|
2
|
+
module COM
|
|
3
|
+
module Interface
|
|
4
|
+
module Version_3_1_X
|
|
5
|
+
class HostNetworkInterface < AbstractInterface
|
|
6
|
+
IID = "ce6fae58-7642-4102-b5db-c9005c2320a8"
|
|
7
|
+
|
|
8
|
+
property :name, WSTRING, :readonly => true
|
|
9
|
+
property :id, WSTRING, :readonly => true
|
|
10
|
+
property :network_name, WSTRING, :readonly => true
|
|
11
|
+
property :dhcp_enabled, T_BOOL, :readonly => true
|
|
12
|
+
property :ip_address, WSTRING, :readonly => true
|
|
13
|
+
property :network_mask, WSTRING, :readonly => true
|
|
14
|
+
property :ip_v6_supported, T_BOOL, :readonly => true
|
|
15
|
+
property :ip_v6_address, WSTRING, :readonly => true
|
|
16
|
+
property :ip_v6_network_mask_prefix_length, T_UINT32, :readonly => true
|
|
17
|
+
property :hardware_address, WSTRING, :readonly => true
|
|
18
|
+
property :medium_type, :HostNetworkInterfaceMediumType, :readonly => true
|
|
19
|
+
property :status, :HostNetworkInterfaceStatus, :readonly => true
|
|
20
|
+
property :interface_type, :HostNetworkInterfaceType, :readonly => true
|
|
21
|
+
|
|
22
|
+
function :enable_static_ip_config, nil, [WSTRING, WSTRING]
|
|
23
|
+
function :enable_static_ip_config_v6, nil, [WSTRING, T_UINT32]
|
|
24
|
+
function :enable_dynamic_ip_config, nil, []
|
|
25
|
+
function :dhcp_rediscover, nil, []
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|