wifi-wand 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +363 -0
- data/RELEASE_NOTES.md +81 -0
- data/exe/wifi-wand +24 -0
- data/lib/wifi-wand.rb +3 -0
- data/lib/wifi-wand/command_line_interface.rb +462 -0
- data/lib/wifi-wand/main.rb +66 -0
- data/lib/wifi-wand/models/base_model.rb +250 -0
- data/lib/wifi-wand/models/mac_os_model.rb +299 -0
- data/lib/wifi-wand/operating_systems.rb +51 -0
- data/lib/wifi-wand/os/base_os.rb +25 -0
- data/lib/wifi-wand/os/imaginary_os.rb +19 -0
- data/lib/wifi-wand/os/mac_os.rb +20 -0
- data/lib/wifi-wand/version.rb +5 -0
- data/sample-avail-network-data.xml +4042 -0
- data/sample-available-networks.json +27 -0
- data/sample-available-networks.yaml +26 -0
- data/spec/wifi-wand_spec.rb +114 -0
- data/wifi-wand.gemspec +28 -0
- metadata +108 -0
data/exe/wifi-wand
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# This script brings together several useful wifi-related functions.
|
|
4
|
+
#
|
|
5
|
+
# It is a bit of a kludge in that it calls Mac OS commands and uses
|
|
6
|
+
# the text output for its data. At some point I would like to replace
|
|
7
|
+
# that with system calls. Currently this script can break if Apple
|
|
8
|
+
# decides to modify the name, options, behavior, and/or format of its utilities.
|
|
9
|
+
#
|
|
10
|
+
# What would be *really* nice, would be for Apple to retrofit all
|
|
11
|
+
# system commands to optionally output JSON and/or YAML. Some offer XML, but that
|
|
12
|
+
# is not convenient to use.
|
|
13
|
+
#
|
|
14
|
+
# Mac OS commands currently used are: airport, ipconfig, networksetup, security.
|
|
15
|
+
#
|
|
16
|
+
# Author: keithrbennett (on Github, GMail, Twitter)
|
|
17
|
+
# I am available for Ruby development, troubleshooting, training, tutoring, etc.
|
|
18
|
+
#
|
|
19
|
+
# License: MIT License
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
require_relative '../lib/wifi-wand/main'
|
|
23
|
+
|
|
24
|
+
WifiWand::Main.new.call
|
data/lib/wifi-wand.rb
ADDED
|
@@ -0,0 +1,462 @@
|
|
|
1
|
+
require_relative 'version'
|
|
2
|
+
require_relative 'operating_systems'
|
|
3
|
+
|
|
4
|
+
module WifiWand
|
|
5
|
+
|
|
6
|
+
class CommandLineInterface
|
|
7
|
+
|
|
8
|
+
attr_reader :interactive_mode, :model, :open_resources, :options
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Command < Struct.new(:min_string, :max_string, :action); end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OpenResource < Struct.new(:code, :resource, :description)
|
|
15
|
+
|
|
16
|
+
# Ex: "'ipw' (What is My IP)"
|
|
17
|
+
def help_string
|
|
18
|
+
"'#{code}' (#{description})"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OpenResources < Array
|
|
24
|
+
|
|
25
|
+
def find_by_code(code)
|
|
26
|
+
detect { |resource| resource.code == code }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Ex: "('ipc' (IP Chicken), 'ipw' (What is My IP), 'spe' (Speed Test))"
|
|
30
|
+
def help_string
|
|
31
|
+
map(&:help_string).join(', ')
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class BadCommandError < RuntimeError
|
|
37
|
+
def initialize(error_message)
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
OPEN_RESOURCES = OpenResources.new([
|
|
43
|
+
OpenResource.new('ipc', 'https://ipchicken.com/', 'IP Chicken'),
|
|
44
|
+
OpenResource.new('ipw', 'https://www.whatismyip.com', 'What is My IP'),
|
|
45
|
+
OpenResource.new('spe', 'http://speedtest.net/', 'Speed Test'),
|
|
46
|
+
OpenResource.new('this', 'https://github.com/keithrbennett/wifiwand', 'wifi-wand Home Page'),
|
|
47
|
+
])
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# Help text to be used when requested by 'h' command, in case of unrecognized or nonexistent command, etc.
|
|
51
|
+
HELP_TEXT = "
|
|
52
|
+
Command Line Switches: [wifi-wand version #{WifiWand::VERSION}]
|
|
53
|
+
|
|
54
|
+
-o[i,j,p,y] - outputs data in inspect, JSON, puts, or YAML format when not in shell mode
|
|
55
|
+
-s - run in shell mode
|
|
56
|
+
-v - verbose mode (prints OS commands and their outputs)
|
|
57
|
+
|
|
58
|
+
Commands:
|
|
59
|
+
|
|
60
|
+
a[vail_nets] - array of names of the available networks
|
|
61
|
+
ci - connected to Internet (not just wifi on)?
|
|
62
|
+
co[nnect] network-name - turns wifi on, connects to network-name
|
|
63
|
+
cy[cle] - turns wifi off, then on, preserving network selection
|
|
64
|
+
d[isconnect] - disconnects from current network, does not turn off wifi
|
|
65
|
+
h[elp] - prints this help
|
|
66
|
+
i[nfo] - a hash of wifi-related information
|
|
67
|
+
l[s_avail_nets] - details about available networks
|
|
68
|
+
n[etwork_name] - name (SSID) of currently connected network
|
|
69
|
+
on - turns wifi on
|
|
70
|
+
of[f] - turns wifi off
|
|
71
|
+
pa[ssword] network-name - password for preferred network-name
|
|
72
|
+
pr[ef_nets] - preferred (not necessarily available) networks
|
|
73
|
+
q[uit] - exits this program (interactive shell mode only) (see also 'x')
|
|
74
|
+
r[m_pref_nets] network-name - removes network-name from the preferred networks list
|
|
75
|
+
(can provide multiple names separated by spaces)
|
|
76
|
+
ro[pen] - open resource (#{OPEN_RESOURCES.help_string})
|
|
77
|
+
t[ill] - returns when the desired Internet connection state is true. Options:
|
|
78
|
+
1) 'on'/:on, 'off'/:off, 'conn'/:conn, or 'disc'/:disc
|
|
79
|
+
2) wait interval, in seconds (optional, defaults to 0.5 seconds)
|
|
80
|
+
w[ifion] - is the wifi on?
|
|
81
|
+
x[it] - exits this program (interactive shell mode only) (see also 'q')
|
|
82
|
+
|
|
83
|
+
When in interactive shell mode:
|
|
84
|
+
* use quotes for string parameters such as method names.
|
|
85
|
+
* for pry commands, use prefix `%`.
|
|
86
|
+
|
|
87
|
+
"
|
|
88
|
+
|
|
89
|
+
def initialize(options)
|
|
90
|
+
@options = options
|
|
91
|
+
current_os = OperatingSystems.new.current_os
|
|
92
|
+
raise "Could not determine operating system" if current_os.nil?
|
|
93
|
+
@model = current_os.create_model(verbose_mode)
|
|
94
|
+
@interactive_mode = !!(options.interactive_mode)
|
|
95
|
+
run_shell if @interactive_mode
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# Until command line option parsing is added, the only way to specify
|
|
100
|
+
# verbose mode is in the environment variable MAC_WIFI_OPTS.
|
|
101
|
+
def verbose_mode
|
|
102
|
+
options.verbose
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def print_help
|
|
107
|
+
puts HELP_TEXT
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# @return true if awesome_print is available (after requiring it), else false after requiring 'pp'.
|
|
112
|
+
# We'd like to use awesome_print if it is available, but not require it.
|
|
113
|
+
# So, we try to require it, but if that fails, we fall back to using pp (pretty print),
|
|
114
|
+
# which is included in Ruby distributions without the need to install a gem.
|
|
115
|
+
def awesome_print_available?
|
|
116
|
+
if @awesome_print_available.nil? # first time here
|
|
117
|
+
begin
|
|
118
|
+
require 'awesome_print'
|
|
119
|
+
@awesome_print_available = true
|
|
120
|
+
rescue LoadError
|
|
121
|
+
require 'pp'
|
|
122
|
+
@awesome_print_available = false
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
@awesome_print_available
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def fancy_string(object)
|
|
131
|
+
awesome_print_available? ? object.ai : object.pretty_inspect
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def fancy_puts(object)
|
|
136
|
+
puts fancy_string(object)
|
|
137
|
+
end
|
|
138
|
+
alias_method :fp, :fancy_puts
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Asserts that a command has been passed on the command line.
|
|
142
|
+
def validate_command_line
|
|
143
|
+
if ARGV.empty?
|
|
144
|
+
puts "Syntax is: #{__FILE__} [options] command [command_options]"
|
|
145
|
+
print_help
|
|
146
|
+
exit(-1)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# Pry will output the content of the method from which it was called.
|
|
152
|
+
# This small method exists solely to reduce the amount of pry's output
|
|
153
|
+
# that is not needed here.
|
|
154
|
+
def run_pry
|
|
155
|
+
binding.pry
|
|
156
|
+
|
|
157
|
+
# the seemingly useless line below is needed to avoid pry's exiting
|
|
158
|
+
# (see https://github.com/deivid-rodriguez/pry-byebug/issues/45)
|
|
159
|
+
_a = nil
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# Runs a pry session in the context of this object.
|
|
164
|
+
# Commands and options specified on the command line can also be specified in the shell.
|
|
165
|
+
def run_shell
|
|
166
|
+
begin
|
|
167
|
+
require 'pry'
|
|
168
|
+
rescue LoadError
|
|
169
|
+
puts "The 'pry' gem and/or one of its prerequisites, required for running the shell, was not found." +
|
|
170
|
+
" Please `gem install pry` or, if necessary, `sudo gem install pry`."
|
|
171
|
+
exit(-1)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
print_help
|
|
175
|
+
|
|
176
|
+
# Enable the line below if you have any problems with pry configuration being loaded
|
|
177
|
+
# that is messing up this runtime use of pry:
|
|
178
|
+
# Pry.config.should_load_rc = false
|
|
179
|
+
|
|
180
|
+
# Strangely, this is the only thing I have found that successfully suppresses the
|
|
181
|
+
# code context output, which is not useful here. Anyway, this will differentiate
|
|
182
|
+
# a pry command from a DSL command, which _is_ useful here.
|
|
183
|
+
Pry.config.command_prefix = '%'
|
|
184
|
+
|
|
185
|
+
run_pry
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# For use by the shell; when typing a command and options, it is passed to process_command_line
|
|
190
|
+
def method_missing(method_name, *options)
|
|
191
|
+
method_name = method_name.to_s
|
|
192
|
+
method_exists = !! find_command_action(method_name)
|
|
193
|
+
if method_exists
|
|
194
|
+
process_command_line(method_name, options)
|
|
195
|
+
else
|
|
196
|
+
puts(%Q{"#{method_name}" is not a valid command or option. If you intend for this to be a string literal, use quotes or %q/Q{}.})
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Processes the command (ARGV[0]) and any relevant options (ARGV[1..-1]).
|
|
202
|
+
#
|
|
203
|
+
# CAUTION! In interactive mode, any strings entered (e.g. a network name) MUST
|
|
204
|
+
# be in a form that the Ruby interpreter will recognize as a string,
|
|
205
|
+
# i.e. single or double quotes, %q, %Q, etc.
|
|
206
|
+
# Otherwise it will assume it's a method name and pass it to method_missing!
|
|
207
|
+
def process_command_line(command, options)
|
|
208
|
+
action = find_command_action(command)
|
|
209
|
+
if action
|
|
210
|
+
action.(*options)
|
|
211
|
+
else
|
|
212
|
+
print_help
|
|
213
|
+
raise BadCommandError.new(
|
|
214
|
+
%Q{Unrecognized command. Command was "#{command}" and options were #{options.inspect}.})
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def quit
|
|
220
|
+
if interactive_mode
|
|
221
|
+
exit(0)
|
|
222
|
+
else
|
|
223
|
+
puts "This command can only be run in shell mode."
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def cmd_a
|
|
229
|
+
info = model.available_network_names
|
|
230
|
+
if interactive_mode
|
|
231
|
+
info
|
|
232
|
+
else
|
|
233
|
+
if post_processor
|
|
234
|
+
puts post_processor.(info)
|
|
235
|
+
else
|
|
236
|
+
puts model.wifi_on? \
|
|
237
|
+
? "Available networks are:\n\n#{fancy_string(info)}" \
|
|
238
|
+
: "Wifi is off, cannot see available networks."
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def cmd_ci
|
|
245
|
+
connected = model.connected_to_internet?
|
|
246
|
+
if interactive_mode
|
|
247
|
+
connected
|
|
248
|
+
else
|
|
249
|
+
puts (post_processor ? post_processor.(connected) : "Connected to Internet: #{connected}")
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def cmd_co(network, password = nil)
|
|
255
|
+
model.connect(network, password)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def cmd_cy
|
|
260
|
+
model.cycle_network
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def cmd_d
|
|
265
|
+
model.disconnect
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def cmd_h
|
|
270
|
+
print_help
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def cmd_i
|
|
275
|
+
info = model.wifi_info
|
|
276
|
+
if interactive_mode
|
|
277
|
+
info
|
|
278
|
+
else
|
|
279
|
+
if post_processor
|
|
280
|
+
puts post_processor.(info)
|
|
281
|
+
else
|
|
282
|
+
puts fancy_string(info)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def cmd_lsa
|
|
289
|
+
info = model.available_network_info
|
|
290
|
+
if interactive_mode
|
|
291
|
+
info
|
|
292
|
+
else
|
|
293
|
+
if post_processor
|
|
294
|
+
puts post_processor.(info)
|
|
295
|
+
else
|
|
296
|
+
message = model.wifi_on? ? fancy_string(info) : "Wifi is off, cannot see available networks."
|
|
297
|
+
puts(message)
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def cmd_n
|
|
304
|
+
name = model.current_network
|
|
305
|
+
if interactive_mode
|
|
306
|
+
name
|
|
307
|
+
else
|
|
308
|
+
display_name = name ? name : '[none]'
|
|
309
|
+
puts (post_processor ? post_processor.(name) : %Q{Network (SSID) name: "#{display_name}"})
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def cmd_of
|
|
315
|
+
model.wifi_off
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
def cmd_on
|
|
320
|
+
model.wifi_on
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
# Use Mac OS 'open' command line utility
|
|
325
|
+
def cmd_ro(*resource_codes)
|
|
326
|
+
resource_codes.each do |code|
|
|
327
|
+
resource = OPEN_RESOURCES.find_by_code(code)
|
|
328
|
+
if resource
|
|
329
|
+
model.open_resource(resource.resource)
|
|
330
|
+
end
|
|
331
|
+
end
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
def cmd_pa(network)
|
|
335
|
+
password = model.preferred_network_password(network)
|
|
336
|
+
|
|
337
|
+
if interactive_mode
|
|
338
|
+
password
|
|
339
|
+
else
|
|
340
|
+
if post_processor
|
|
341
|
+
puts post_processor.(password)
|
|
342
|
+
else
|
|
343
|
+
output = %Q{Preferred network "#{model.connected_network_name}" }
|
|
344
|
+
output << (password ? %Q{stored password is "#{password}".} : "has no stored password.")
|
|
345
|
+
puts output
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def cmd_pr
|
|
352
|
+
networks = model.preferred_networks
|
|
353
|
+
if interactive_mode
|
|
354
|
+
networks
|
|
355
|
+
else
|
|
356
|
+
puts (post_processor ? post_processor.(networks) : fancy_string(networks))
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
def cmd_pu
|
|
362
|
+
`open https://www.whatismyip.com/`
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def cmd_q
|
|
367
|
+
quit
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def cmd_r(*options)
|
|
372
|
+
removed_networks = model.remove_preferred_networks(*options)
|
|
373
|
+
if interactive_mode
|
|
374
|
+
removed_networks
|
|
375
|
+
else
|
|
376
|
+
puts (post_processor ? post_processor.(removed_networks) : "Removed networks: #{removed_networks.inspect}")
|
|
377
|
+
end
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
def cmd_t(*options)
|
|
382
|
+
target_status = options[0].to_sym
|
|
383
|
+
wait_interval_in_secs = (options[1] ? Float(options[1]) : nil)
|
|
384
|
+
model.till(target_status, wait_interval_in_secs)
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
def cmd_w
|
|
389
|
+
on = model.wifi_on?
|
|
390
|
+
if interactive_mode
|
|
391
|
+
on
|
|
392
|
+
else
|
|
393
|
+
puts (post_processor ? post_processor.(on) : "Wifi on: #{on}")
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def cmd_x
|
|
399
|
+
quit
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def commands
|
|
404
|
+
@commands_ ||= [
|
|
405
|
+
Command.new('a', 'avail_nets', -> (*_options) { cmd_a }),
|
|
406
|
+
Command.new('ci', 'ci', -> (*_options) { cmd_ci }),
|
|
407
|
+
Command.new('co', 'connect', -> (*options) { cmd_co(*options) }),
|
|
408
|
+
Command.new('cy', 'cycle', -> (*_options) { cmd_cy }),
|
|
409
|
+
Command.new('d', 'disconnect', -> (*_options) { cmd_d }),
|
|
410
|
+
Command.new('h', 'help', -> (*_options) { cmd_h }),
|
|
411
|
+
Command.new('i', 'info', -> (*_options) { cmd_i }),
|
|
412
|
+
Command.new('l', 'ls_avail_nets', -> (*_options) { cmd_lsa }),
|
|
413
|
+
Command.new('n', 'network_name', -> (*_options) { cmd_n }),
|
|
414
|
+
Command.new('of', 'off', -> (*_options) { cmd_of }),
|
|
415
|
+
Command.new('on', 'on', -> (*_options) { cmd_on }),
|
|
416
|
+
Command.new('ro', 'ropen', -> (*options) { cmd_ro(*options) }),
|
|
417
|
+
Command.new('pa', 'password', -> (*options) { cmd_pa(*options) }),
|
|
418
|
+
Command.new('pr', 'pref_nets', -> (*_options) { cmd_pr }),
|
|
419
|
+
Command.new('q', 'quit', -> (*_options) { cmd_q }),
|
|
420
|
+
Command.new('r', 'rm_pref_nets', -> (*options) { cmd_r(*options) }),
|
|
421
|
+
Command.new('t', 'till', -> (*options) { cmd_t(*options) }),
|
|
422
|
+
Command.new('w', 'wifion', -> (*_options) { cmd_w }),
|
|
423
|
+
Command.new('x', 'xit', -> (*_options) { cmd_x })
|
|
424
|
+
]
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
def find_command_action(command_string)
|
|
429
|
+
result = commands.detect do |cmd|
|
|
430
|
+
cmd.max_string.start_with?(command_string) \
|
|
431
|
+
&& \
|
|
432
|
+
command_string.length >= cmd.min_string.length # e.g. 'c' by itself should not work
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
result ? result.action : nil
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
# If a post-processor has been configured (e.g. YAML or JSON), use it.
|
|
440
|
+
def post_process(object)
|
|
441
|
+
post_processor ? post_processor.(object) : object
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
def post_processor
|
|
447
|
+
options.post_processor
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
def call
|
|
452
|
+
validate_command_line
|
|
453
|
+
begin
|
|
454
|
+
process_command_line(ARGV[0], ARGV[1..-1])
|
|
455
|
+
rescue BadCommandError => error
|
|
456
|
+
separator_line = "! #{'-' * 75} !\n"
|
|
457
|
+
puts '' << separator_line << error.to_s << "\n" << separator_line
|
|
458
|
+
exit(-1)
|
|
459
|
+
end
|
|
460
|
+
end
|
|
461
|
+
end
|
|
462
|
+
end
|