bcome 0.7.0 → 1.0.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.
Files changed (173) hide show
  1. checksums.yaml +4 -4
  2. data/bin/bcome +8 -39
  3. data/lib/bcome.rb +12 -3
  4. data/lib/objects/bcome/version.rb +3 -0
  5. data/lib/objects/bootup.rb +81 -0
  6. data/lib/objects/command/local.rb +40 -0
  7. data/lib/objects/config_factory.rb +36 -0
  8. data/lib/objects/driver/base.rb +30 -0
  9. data/lib/objects/driver/bucket.rb +20 -0
  10. data/lib/objects/driver/ec2.rb +44 -0
  11. data/lib/objects/driver/static.rb +4 -0
  12. data/lib/objects/exception/argument_error_invoking_method_from_command_line.rb +7 -0
  13. data/lib/objects/exception/base.rb +15 -0
  14. data/lib/objects/exception/can_only_subselect_on_inventory.rb +7 -0
  15. data/lib/objects/exception/cannot_find_internal_registry_klass.rb +7 -0
  16. data/lib/objects/exception/cannot_find_subselection_parent.rb +7 -0
  17. data/lib/objects/exception/cant_find_key_in_cloud_tags.rb +7 -0
  18. data/lib/objects/exception/cant_find_key_in_metadata.rb +7 -0
  19. data/lib/objects/exception/cant_find_proxy_host_by_identifier.rb +7 -0
  20. data/lib/objects/exception/cant_find_proxy_host_by_namespace.rb +7 -0
  21. data/lib/objects/exception/could_not_initiate_ssh_connection.rb +7 -0
  22. data/lib/objects/exception/could_not_initiate_ssh_connection_through_backend_proxy.rb +7 -0
  23. data/lib/objects/exception/deprecation_warning.rb +11 -0
  24. data/lib/objects/exception/duplicate_command_line_argument_key.rb +7 -0
  25. data/lib/objects/exception/ec2_driver_missing_provisioning_region.rb +7 -0
  26. data/lib/objects/exception/failed_to_run_local_command.rb +7 -0
  27. data/lib/objects/exception/interactive_session_halt.rb +4 -0
  28. data/lib/objects/exception/invalid_bcome_breadcrumb.rb +7 -0
  29. data/lib/objects/exception/invalid_breadcrumb.rb +7 -0
  30. data/lib/objects/exception/invalid_context_command.rb +7 -0
  31. data/lib/objects/exception/invalid_identifier.rb +7 -0
  32. data/lib/objects/exception/invalid_machines_cache_config.rb +7 -0
  33. data/lib/objects/exception/invalid_matcher_query.rb +7 -0
  34. data/lib/objects/exception/invalid_meta_data_config.rb +7 -0
  35. data/lib/objects/exception/invalid_network_config.rb +7 -0
  36. data/lib/objects/exception/invalid_network_driver_type.rb +7 -0
  37. data/lib/objects/exception/invalid_proxy_config.rb +7 -0
  38. data/lib/objects/exception/invalid_regexp_matcher_in_registry.rb +7 -0
  39. data/lib/objects/exception/invalid_registry_arguments_type.rb +7 -0
  40. data/lib/objects/exception/invalid_registry_data_config.rb +7 -0
  41. data/lib/objects/exception/invalid_restriction_key_in_registry.rb +7 -0
  42. data/lib/objects/exception/invalid_ssh_config.rb +7 -0
  43. data/lib/objects/exception/inventories_cannot_have_subviews.rb +7 -0
  44. data/lib/objects/exception/malformed_command_line_arguments.rb +7 -0
  45. data/lib/objects/exception/method_invocation_requires_parameter.rb +7 -0
  46. data/lib/objects/exception/method_name_conflict_in_registry.rb +7 -0
  47. data/lib/objects/exception/missing_argument_for_registry_command.rb +7 -0
  48. data/lib/objects/exception/missing_description_on_view.rb +7 -0
  49. data/lib/objects/exception/missing_execute_on_registry_object.rb +7 -0
  50. data/lib/objects/exception/missing_identifier_on_view.rb +7 -0
  51. data/lib/objects/exception/missing_ip_address_on_server.rb +7 -0
  52. data/lib/objects/exception/missing_network_config.rb +7 -0
  53. data/lib/objects/exception/missing_params_for_rsync.rb +7 -0
  54. data/lib/objects/exception/missing_params_for_scp.rb +7 -0
  55. data/lib/objects/exception/missing_subselection_key.rb +7 -0
  56. data/lib/objects/exception/missing_type_on_view.rb +7 -0
  57. data/lib/objects/exception/no_node_found_for_breadcrumb.rb +7 -0
  58. data/lib/objects/exception/no_node_named_by_identifier.rb +7 -0
  59. data/lib/objects/exception/node_identifiers_must_be_unique.rb +7 -0
  60. data/lib/objects/exception/orchestration_script_does_not_exist.rb +7 -0
  61. data/lib/objects/exception/proxy_host_node_does_not_have_public_ip_address.rb +7 -0
  62. data/lib/objects/exception/unknown_method_for_namespace.rb +7 -0
  63. data/lib/objects/interactive/session.rb +45 -0
  64. data/lib/objects/interactive/session_item/base.rb +36 -0
  65. data/lib/objects/interactive/session_item/capture_input.rb +20 -0
  66. data/lib/objects/interactive/session_item/transparent_ssh.rb +111 -0
  67. data/lib/objects/modules/context.rb +13 -0
  68. data/lib/objects/modules/registry_management.rb +14 -0
  69. data/lib/objects/modules/ui_output.rb +9 -0
  70. data/lib/objects/modules/workspace_commands.rb +198 -0
  71. data/lib/objects/modules/workspace_menu.rb +128 -0
  72. data/lib/objects/node/attributes.rb +47 -0
  73. data/lib/objects/node/base.rb +248 -0
  74. data/lib/objects/node/cache_handler.rb +24 -0
  75. data/lib/objects/node/collection.rb +51 -0
  76. data/lib/objects/node/factory.rb +108 -0
  77. data/lib/objects/node/inventory/base.rb +88 -0
  78. data/lib/objects/node/inventory/defined.rb +112 -0
  79. data/lib/objects/node/inventory/subselect.rb +54 -0
  80. data/lib/objects/node/meta/base.rb +36 -0
  81. data/lib/objects/node/meta/cloud.rb +4 -0
  82. data/lib/objects/node/meta/local.rb +4 -0
  83. data/lib/objects/node/meta_data_factory.rb +23 -0
  84. data/lib/objects/node/meta_data_loader.rb +32 -0
  85. data/lib/objects/node/resources/base.rb +98 -0
  86. data/lib/objects/node/resources/inventory.rb +25 -0
  87. data/lib/objects/node/resources/sub_inventory.rb +56 -0
  88. data/lib/objects/node/server/base.rb +218 -0
  89. data/lib/objects/node/server/dynamic.rb +39 -0
  90. data/lib/objects/node/server/static.rb +31 -0
  91. data/lib/objects/orchestration/base.rb +13 -0
  92. data/lib/objects/orchestrator.rb +24 -0
  93. data/lib/objects/parser/bread_crumb.rb +31 -0
  94. data/lib/objects/progress_bar.rb +30 -0
  95. data/lib/objects/registry/arguments/base.rb +36 -0
  96. data/lib/objects/registry/arguments/command_line.rb +35 -0
  97. data/lib/objects/registry/arguments/console.rb +15 -0
  98. data/lib/objects/registry/command/base.rb +66 -0
  99. data/lib/objects/registry/command/external.rb +55 -0
  100. data/lib/objects/registry/command/group.rb +76 -0
  101. data/lib/objects/registry/command/internal.rb +34 -0
  102. data/lib/objects/registry/command_list.rb +33 -0
  103. data/lib/objects/registry/loader.rb +70 -0
  104. data/lib/objects/ssh/bootstrap.rb +19 -0
  105. data/lib/objects/ssh/command.rb +46 -0
  106. data/lib/objects/ssh/command_exec.rb +65 -0
  107. data/lib/objects/ssh/connection_handler.rb +101 -0
  108. data/lib/objects/ssh/driver.rb +204 -0
  109. data/lib/objects/ssh/proxy_data.rb +56 -0
  110. data/lib/objects/ssh/script_exec.rb +43 -0
  111. data/lib/objects/system/local.rb +30 -0
  112. data/lib/objects/workspace.rb +75 -0
  113. data/patches/irb.rb +20 -7
  114. data/patches/string.rb +75 -0
  115. data/patches/string_stylesheet.rb +61 -0
  116. metadata +175 -93
  117. data/bin/bcome-bash-setup +0 -18
  118. data/bin/bcome-setup +0 -43
  119. data/bin/boot.rb +0 -148
  120. data/bin/boot_no_shell.rb +0 -3
  121. data/filters/ec2_filter.rb +0 -12
  122. data/lib/bcome/version.rb +0 -3
  123. data/lib/become_object.rb +0 -111
  124. data/lib/boot.rb +0 -13
  125. data/lib/command.rb +0 -56
  126. data/lib/context_functions.rb +0 -65
  127. data/lib/filters/base.rb +0 -10
  128. data/lib/filters/ec2_filter.rb +0 -4
  129. data/lib/functions.rb +0 -70
  130. data/lib/helpers/command_helper.rb +0 -13
  131. data/lib/helpers/environment_ssh.rb +0 -122
  132. data/lib/helpers/fog_helper.rb +0 -108
  133. data/lib/helpers/instance_command.rb +0 -71
  134. data/lib/helpers/instance_ssh.rb +0 -83
  135. data/lib/helpers/selections.rb +0 -117
  136. data/lib/interactive/interactive_session_halt.rb +0 -4
  137. data/lib/interactive/session.rb +0 -44
  138. data/lib/interactive/session_item/base.rb +0 -30
  139. data/lib/interactive/session_item/transparent_ssh.rb +0 -133
  140. data/lib/nodes/base.rb +0 -60
  141. data/lib/nodes/environment.rb +0 -30
  142. data/lib/nodes/estate.rb +0 -44
  143. data/lib/nodes/instance.rb +0 -94
  144. data/lib/nodes/platform.rb +0 -17
  145. data/lib/nodes/view.rb +0 -31
  146. data/lib/object.rb +0 -21
  147. data/lib/orchestrator/command_group/base.rb +0 -56
  148. data/lib/orchestrator/command_group/custom.rb +0 -13
  149. data/lib/orchestrator/command_group/direct.rb +0 -53
  150. data/lib/orchestrator/direct_command/group.rb +0 -21
  151. data/lib/orchestrator/direct_command/instance.rb +0 -19
  152. data/lib/orchestrator/factory.rb +0 -38
  153. data/lib/orchestrator/loader.rb +0 -47
  154. data/lib/orchestrator/node_target/all.rb +0 -14
  155. data/lib/orchestrator/node_target/all_excluding_roles.rb +0 -14
  156. data/lib/orchestrator/node_target/all_with_roles.rb +0 -14
  157. data/lib/orchestrator/node_target/base.rb +0 -43
  158. data/lib/orchestrator/node_target/single.rb +0 -12
  159. data/lib/orchestrator/recipe.rb +0 -60
  160. data/lib/orchestrator/registry.rb +0 -37
  161. data/lib/orchestrator/validate_and_set.rb +0 -10
  162. data/lib/patches/string.rb +0 -86
  163. data/lib/progress_bar.rb +0 -31
  164. data/lib/render_irb.rb +0 -53
  165. data/lib/scp.rb +0 -40
  166. data/lib/ssh.rb +0 -51
  167. data/lib/stack/base.rb +0 -148
  168. data/lib/stack/environment.rb +0 -222
  169. data/lib/stack/estate.rb +0 -50
  170. data/lib/stack/instance.rb +0 -130
  171. data/lib/stack/platform.rb +0 -74
  172. data/lib/stack/view.rb +0 -56
  173. data/lib/workspace_context.rb +0 -40
@@ -1,117 +0,0 @@
1
- module Bcome::Selections
2
-
3
- def manage_object(method, resource_identifier = nil)
4
- unless resource_identifier && resource_identifier.is_a?(String)
5
- print "You must select a resource identified by its name. #{available_resources_options_string}".headsup
6
- else
7
- object = find_resource_by_identifier(resource_identifier)
8
- unless object
9
- print "Cannot find object with identifier #{resource_identifier} within the resources for this collection. #{available_resources_options_string}".failure unless object
10
- else
11
- send(method, object)
12
- end
13
- end
14
- end
15
-
16
- ## Runs commands over *every* object in the selection
17
- def run(raw_commands, bootstrap = false)
18
- return unless @objects
19
- @objects.pmap {|object|
20
- object.run(raw_commands, bootstrap)
21
- }
22
- return
23
- end
24
-
25
- def no_selections?
26
- !@objects || @objects.empty?
27
- end
28
-
29
- def put(local_path, remote_path, bootstrap = false)
30
- if no_selections?
31
- no_selections_error
32
- return
33
- end
34
-
35
- @objects.each do |object|
36
- object.put(local_path, remote_path, bootstrap)
37
- end
38
- return
39
- end
40
-
41
- def get(remote_path)
42
- if no_selections?
43
- no_selections_error
44
- return
45
- end
46
- @objects.each do |object|
47
- object.get(remote_path)
48
- end
49
- return
50
- end
51
-
52
- def add(resource_identifier = nil)
53
- resource_identifier = [resource_identifier] unless resource_identifier.is_a?(Array)
54
- resource_identifier.each {|ri| manage_object(:add_object, ri) }
55
- puts "\n" + "#{resource_identifier.join(",")} added.".menu_item_cyan + "\n\nType 'selections' or 's' to review your selections.'".menu_item_white
56
- end
57
-
58
- def remove(resource_identifier = nil)
59
- resource_identifier = [resource_identifier] unless resource_identifier.is_a?(Array)
60
- resource_identifier.each { |ri| manage_object(:remove_object, ri) }
61
- puts "\n Nodes removed.".menu_item_cyan
62
- end
63
-
64
- def add!
65
- @objects = resources
66
- puts "All nodes added".informational
67
- end
68
-
69
- def clear!
70
- @objects = []
71
- selections
72
- end
73
-
74
- def find_resource_by_identifier(resource_identifier)
75
- resources.select{|r| r.identifier == resource_identifier }.first
76
- end
77
-
78
- def in_resources?(object)
79
- resources.include?(object)
80
- end
81
-
82
- def add_object(object)
83
- return if object_in_selections?(object)
84
- @objects = @objects ? (@objects << object) : [object]
85
- return
86
- end
87
-
88
- def remove_object(object)
89
- return if no_selections?
90
- unless object_in_selections?(object)
91
- puts "\n#{object.identifier} is not within selections".headsup
92
- else
93
- @objects = @objects - [object]
94
- end
95
- return
96
- end
97
-
98
- def object_in_selections?(object)
99
- return false unless @objects
100
- return @objects.include?(object)
101
- end
102
-
103
- def selections
104
- if no_selections?
105
- puts "\n" + "No added nodes.".headsup + "\n"
106
- else
107
- puts "\n\s\s" + "Selected nodes:".menu_title_green + "\n\n"
108
- puts @objects.collect {|o| o.do_describe }.join + "\n"
109
- end
110
- end
111
- alias :s :selections
112
-
113
- def no_selections_error
114
- puts "No nodes selected".informational
115
- end
116
-
117
- end
@@ -1,4 +0,0 @@
1
- module Bcome::Interactive
2
- class SessionHalt < RuntimeError
3
- end
4
- end
@@ -1,44 +0,0 @@
1
- module Bcome::Interactive
2
- class Session
3
-
4
- class << self
5
- def run(irb_session)
6
- irb_pre_session_return_format = irb_session.conf.return_format
7
- session_end_message = "\ninteractive session ended".success
8
- begin
9
- session = ::Bcome::Interactive::Session.new(irb_session)
10
- irb_session.conf.return_format = ""
11
- system("clear")
12
- session.prompt
13
- rescue ::Bcome::Interactive::SessionHalt => e
14
- irb_session.conf.return_format = irb_pre_session_return_format
15
- puts session_end_message
16
- end
17
- end
18
- end
19
-
20
- attr_reader :responses, :irb_session
21
-
22
- def initialize(irb_session)
23
- @irb_session = irb_session
24
- @responses = {}
25
- end
26
-
27
- def prompt
28
- item = ::Bcome::Interactive::SessionItem::TransparentSsh.new(self)
29
- print item.start_message
30
- process_item(item)
31
- end
32
-
33
- def process_item(item)
34
- begin
35
- item.do
36
- rescue Exception => e
37
- puts "Exception: #{e.message}"
38
- puts e.backtrace.join("\n")
39
- raise ::Bcome::Interactive::SessionHalt.new
40
- end
41
- end
42
-
43
- end
44
- end
@@ -1,30 +0,0 @@
1
- module Bcome::Interactive::SessionItem
2
- class Base
3
-
4
- def initialize(session)
5
- @session = session
6
- @irb_session = @session.irb_session
7
- end
8
-
9
- def bcome_identifier
10
- @irb_session.become_identifier
11
- end
12
-
13
- def irb_session
14
- @session.irb_session
15
- end
16
-
17
- def options
18
- @session.options
19
- end
20
-
21
- def set_response_on_session
22
- @session.responses[@key] = @response
23
- end
24
-
25
- def do(*params)
26
- raise "Should be overidden"
27
- end
28
-
29
- end
30
- end
@@ -1,133 +0,0 @@
1
- module Bcome::Interactive::SessionItem
2
- class TransparentSsh < ::Bcome::Interactive::SessionItem::Base
3
-
4
- END_SESSION_KEY = "\\q"
5
- HELP_KEY = "\\?"
6
- LIST_KEY = "\\l"
7
-
8
- DANGER_CMD = "rm\s+-r|rm\s+-f|rm\s+-fr|rm\s+-rf|rm"
9
-
10
- def do
11
- show_menu
12
- puts ""
13
- open_ssh_connections!
14
- puts ""
15
- list_machines
16
- action
17
- end
18
-
19
- def action
20
- input = get_input
21
- return if exit?(input)
22
- if show_menu?(input)
23
- show_menu
24
- elsif list_machines?(input)
25
- list_machines
26
- elsif command_may_be_unwise?(input)
27
- handle_the_unwise(input)
28
- else
29
- execute_on_machines(input)
30
- end
31
- action
32
- end
33
-
34
- def show_menu
35
- system("clear") ; print start_message
36
- end
37
-
38
- def handle_the_unwise(input)
39
- if prompt_for_confirmation("Command may be dangerous to run on all machines. Are you sure you want to proceed? [Y|N] > ".danger)
40
- execute_on_machines(input)
41
- end
42
- end
43
-
44
- def command_may_be_unwise?(input)
45
- input =~ /#{DANGER_CMD}/
46
- end
47
-
48
- def prompt_for_confirmation(message)
49
- answer = get_input(message)
50
- unless ["Y", "N"].include?(answer)
51
- prompt_for_confirmation(message)
52
- end
53
- return answer == "Y" ? true : false
54
- end
55
-
56
- def start_message
57
- warning = "\nCommands entered here will be executed on EVERY machine in your selection.".danger
58
- second_warning = "\n\nUse with CAUTION.".danger
59
- info = "\n\n\\l list machines\n\\q to quit\n\\? this message".informational
60
- return "#{warning}#{second_warning}#{info}\n"
61
- end
62
-
63
- def terminal_prompt
64
- "#{bcome_identifier}>\s" + "interactive\s>\s".command # high voltage
65
- end
66
-
67
- def valid_response(response)
68
- a = response.gsub("\s", "").downcase
69
- valid_responses.include?(response)
70
- end
71
-
72
- def exit?(input)
73
- input == END_SESSION_KEY
74
- end
75
-
76
- def show_menu?(input)
77
- input == HELP_KEY
78
- end
79
-
80
- def list_machines?(input)
81
- input == LIST_KEY
82
- end
83
-
84
- def open_ssh_connections!
85
- ProgressBar.instance.reset!
86
- machines.pmap {|machine|
87
- ProgressBar.instance.indicate_and_increment!("init ssh: ","~~~", "connections")
88
- machine.ssh_connect!
89
- }
90
- ProgressBar.instance.reset!
91
- end
92
-
93
- def list_machines
94
- puts "\n"
95
- machines.each do |machine|
96
- env = machine.environment
97
- platform = env.platform
98
- puts "#{platform.identifier.cyan}:#{env.identifier.orange}:#{machine.identifier.yellow}"
99
- end
100
- end
101
-
102
- def get_input(message = terminal_prompt)
103
- return ::Readline.readline("\n#{message}", true).squeeze(" " ).to_s
104
- end
105
-
106
- def execute_on_machines(user_input)
107
- machines.pmap {|machine|
108
- machine.run(user_input)
109
- }
110
- end
111
-
112
- def machines
113
- @machines ||= has_selected_machines? ? selected_machines.collect(&:node) : flat_list_of_machines
114
- end
115
-
116
- def flat_list_of_machines
117
- resources.collect{|resource| resource.node.machines }.flatten
118
- end
119
-
120
- def resources
121
- @irb_session.resources
122
- end
123
-
124
- def has_selected_machines?
125
- selected_machines.is_a?(Array) && selected_machines.any?
126
- end
127
-
128
- def selected_machines
129
- @selections ||= @irb_session.instance_variable_get(:@objects)
130
- end
131
-
132
- end
133
- end
data/lib/nodes/base.rb DELETED
@@ -1,60 +0,0 @@
1
- module ::Bcome::Node
2
- class Base
3
-
4
- include ::Bcome::CommandHelper
5
-
6
- attr_reader :meta_data, :stack_peer
7
-
8
- def machines
9
- raise "Should be overriden"
10
- end
11
-
12
- def ls
13
- self.stack_peer.ls
14
- end
15
-
16
- def initialize(meta_data)
17
- construct(meta_data)
18
- end
19
-
20
- def set_stack_peer(stack_instance)
21
- @stack_peer = stack_instance
22
- end
23
-
24
- def interactive
25
- stack_peer.interactive
26
- end
27
-
28
- ## Runs a command over *every* machine in this node
29
- def run(raw_command, bootstrap = false)
30
- return unless machines
31
- machines.pmap {|machine|
32
- machine.run([raw_command], bootstrap)
33
- }
34
- return
35
- end
36
-
37
- def method_missing(method_sym, *arguments, &block)
38
- if instance_variable_defined?("@#{method_sym}")
39
- return instance_variable_get("@#{method_sym}")
40
- else
41
- super
42
- end
43
- end
44
-
45
- def set_parent_reference(parent, parent_reference_key, collection_key)
46
- instance_variable_get("@#{collection_key}").map{|collection_item|
47
- collection_item.instance_variable_set("@#{parent_reference_key}", parent)
48
- }
49
- end
50
-
51
- private
52
-
53
- def construct(meta_data = {})
54
- meta_data.each do |key, value|
55
- self.instance_variable_set("@#{key}", value)
56
- end
57
- end
58
-
59
- end
60
- end
@@ -1,30 +0,0 @@
1
- module ::Bcome::Node
2
- class Environment < ::Bcome::Node::Base
3
-
4
- include ::Bcome::EnvironmentSSH
5
-
6
- def machines
7
- if instances.empty?
8
- stack_peer.do_load_resources
9
- end
10
- instances
11
- end
12
-
13
- def identifier
14
- @environment
15
- end
16
-
17
- def bootstrap_settings
18
- @bootstrap_settings
19
- end
20
-
21
- def namespace
22
- "#{platform.namespace}/#{identifier}"
23
- end
24
-
25
- def set_instances(loaded_resources)
26
- @instances = loaded_resources.collect(&:node)
27
- end
28
-
29
- end
30
- end
data/lib/nodes/estate.rb DELETED
@@ -1,44 +0,0 @@
1
- module ::Bcome::Node
2
- class Estate < ::Bcome::Node::Base
3
-
4
- include ::Bcome::Selections
5
-
6
- def machines
7
- platforms.collect(&:machines).flatten
8
- end
9
-
10
- def namespace
11
- ""
12
- end
13
-
14
- def run(raw_command, bootstrap = false)
15
- return unless platforms
16
- platforms.pmap {|platform|
17
- platform.run(raw_command, bootstrap)
18
- }
19
- return
20
- end
21
-
22
- def environments
23
- @environments ||= platforms.collect(&:environments).flatten
24
- end
25
-
26
- def list_all
27
- estate_machine_list = "\n"
28
- platforms.each do |platform|
29
- estate_machine_list += "* #{platform.identifier}\n"
30
- platform.environments.each do |environment|
31
- estate_machine_list += "\t- #{environment.identifier}\n"
32
- environment.instances.each do |instance|
33
- estate_machine_list += "\t\t / #{instance.identifier} (#{instance.public_ip_address})\n"
34
- end
35
- end
36
- end
37
-
38
- puts estate_machine_list
39
-
40
- return ""
41
- end
42
-
43
- end
44
- end