line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Selenium::CanStartBinary; |
2
|
|
|
|
|
|
|
$Selenium::CanStartBinary::VERSION = '1.49'; |
3
|
1
|
|
|
1
|
|
643
|
use strict; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
31
|
|
4
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
28
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
# ABSTRACT: Teach a WebDriver how to start its own binary aka no JRE! |
7
|
1
|
|
|
1
|
|
14
|
use File::Spec; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
8
|
|
|
|
|
|
|
use Selenium::CanStartBinary::ProbePort |
9
|
1
|
|
|
1
|
|
451
|
qw/find_open_port_above find_open_port probe_port/; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
65
|
|
10
|
1
|
|
|
1
|
|
10
|
use Selenium::Firefox::Binary qw/setup_firefox_binary_env/; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
55
|
|
11
|
1
|
|
|
1
|
|
6
|
use Selenium::Waiter qw/wait_until/; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
33
|
|
12
|
1
|
|
|
1
|
|
6
|
use Moo::Role; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
13
|
|
|
|
|
|
|
|
14
|
1
|
|
|
1
|
|
427
|
use constant IS_WIN => $^O eq 'MSWin32'; |
|
1
|
|
|
|
|
40
|
|
|
1
|
|
|
|
|
1621
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
requires 'binary'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
requires 'binary_port'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
requires '_binary_args'; |
24
|
|
|
|
|
|
|
|
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has '_real_binary' => ( |
27
|
|
|
|
|
|
|
is => 'lazy', |
28
|
|
|
|
|
|
|
builder => sub { |
29
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
30
|
|
|
|
|
|
|
|
31
|
0
|
0
|
|
|
|
0
|
if ( $self->_is_old_ff ) { |
32
|
0
|
|
|
|
|
0
|
return $self->firefox_binary; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
else { |
35
|
0
|
|
|
|
|
0
|
return $self->binary; |
36
|
|
|
|
|
|
|
} |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
); |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
has '_is_old_ff' => ( |
41
|
|
|
|
|
|
|
is => 'lazy', |
42
|
|
|
|
|
|
|
builder => sub { |
43
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
44
|
|
|
|
|
|
|
|
45
|
0
|
|
0
|
|
|
0
|
return $self->isa('Selenium::Firefox') && !$self->marionette_enabled; |
46
|
|
|
|
|
|
|
} |
47
|
|
|
|
|
|
|
); |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
has '+port' => ( |
50
|
|
|
|
|
|
|
is => 'lazy', |
51
|
|
|
|
|
|
|
builder => sub { |
52
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
53
|
|
|
|
|
|
|
|
54
|
0
|
0
|
|
|
|
0
|
if ( $self->_real_binary ) { |
55
|
0
|
0
|
|
|
|
0
|
if ( $self->fixed_ports ) { |
56
|
0
|
|
|
|
|
0
|
return find_open_port( $self->binary_port ); |
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
else { |
59
|
0
|
|
|
|
|
0
|
return find_open_port_above( $self->binary_port ); |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
} |
62
|
|
|
|
|
|
|
else { |
63
|
0
|
|
|
|
|
0
|
return 4444; |
64
|
|
|
|
|
|
|
} |
65
|
|
|
|
|
|
|
} |
66
|
|
|
|
|
|
|
); |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
has 'fixed_ports' => ( |
70
|
|
|
|
|
|
|
is => 'lazy', |
71
|
|
|
|
|
|
|
default => sub { 0 } |
72
|
|
|
|
|
|
|
); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
has custom_args => ( |
76
|
|
|
|
|
|
|
is => 'lazy', |
77
|
|
|
|
|
|
|
predicate => 1, |
78
|
|
|
|
|
|
|
default => sub { '' } |
79
|
|
|
|
|
|
|
); |
80
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
has 'marionette_port' => ( |
82
|
|
|
|
|
|
|
is => 'lazy', |
83
|
|
|
|
|
|
|
builder => sub { |
84
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
85
|
|
|
|
|
|
|
|
86
|
0
|
0
|
|
|
|
0
|
if ( $self->_is_old_ff ) { |
87
|
0
|
|
|
|
|
0
|
return 0; |
88
|
|
|
|
|
|
|
} |
89
|
|
|
|
|
|
|
else { |
90
|
0
|
0
|
|
|
|
0
|
if ( $self->fixed_ports ) { |
91
|
0
|
|
|
|
|
0
|
return find_open_port( $self->marionette_binary_port ); |
92
|
|
|
|
|
|
|
} |
93
|
|
|
|
|
|
|
else { |
94
|
0
|
|
|
|
|
0
|
return find_open_port_above( $self->marionette_binary_port ); |
95
|
|
|
|
|
|
|
} |
96
|
|
|
|
|
|
|
} |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
); |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
has startup_timeout => ( |
102
|
|
|
|
|
|
|
is => 'lazy', |
103
|
|
|
|
|
|
|
default => sub { 10 } |
104
|
|
|
|
|
|
|
); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
has 'binary_mode' => ( |
108
|
|
|
|
|
|
|
is => 'lazy', |
109
|
|
|
|
|
|
|
init_arg => undef, |
110
|
|
|
|
|
|
|
builder => 1, |
111
|
|
|
|
|
|
|
predicate => 1 |
112
|
|
|
|
|
|
|
); |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
has 'try_binary' => ( |
115
|
|
|
|
|
|
|
is => 'lazy', |
116
|
|
|
|
|
|
|
default => sub { 0 }, |
117
|
|
|
|
|
|
|
trigger => sub { |
118
|
|
|
|
|
|
|
my ($self) = @_; |
119
|
|
|
|
|
|
|
$self->binary_mode if $self->try_binary; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
); |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
has 'window_title' => ( |
125
|
|
|
|
|
|
|
is => 'lazy', |
126
|
|
|
|
|
|
|
init_arg => undef, |
127
|
|
|
|
|
|
|
builder => sub { |
128
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
129
|
0
|
|
|
|
|
0
|
my ( undef, undef, $file ) = |
130
|
|
|
|
|
|
|
File::Spec->splitpath( $self->_real_binary ); |
131
|
0
|
|
|
|
|
0
|
my $port = $self->port; |
132
|
|
|
|
|
|
|
|
133
|
0
|
|
|
|
|
0
|
return $file . ':' . $port; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
); |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
has '_command' => ( |
139
|
|
|
|
|
|
|
is => 'lazy', |
140
|
|
|
|
|
|
|
init_arg => undef, |
141
|
|
|
|
|
|
|
builder => sub { |
142
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
143
|
0
|
|
|
|
|
0
|
return $self->_construct_command; |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
); |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
has 'logfile' => ( |
149
|
|
|
|
|
|
|
is => 'lazy', |
150
|
|
|
|
|
|
|
default => sub { |
151
|
|
|
|
|
|
|
return '/nul' if IS_WIN; |
152
|
|
|
|
|
|
|
return '/dev/null'; |
153
|
|
|
|
|
|
|
} |
154
|
|
|
|
|
|
|
); |
155
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
sub BUILDARGS { |
157
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
# There's a bit of finagling to do to since we can't ensure the |
159
|
|
|
|
|
|
|
# attribute instantiation order. To decide whether we're going into |
160
|
|
|
|
|
|
|
# binary mode, we need the remote_server_addr and port. But, they're |
161
|
|
|
|
|
|
|
# both lazy and only instantiated immediately before S:R:D's |
162
|
|
|
|
|
|
|
# remote_conn attribute. Once remote_conn is set, we can't change it, |
163
|
|
|
|
|
|
|
# so we need the following order: |
164
|
|
|
|
|
|
|
# |
165
|
|
|
|
|
|
|
# parent: remote_server_addr, port |
166
|
|
|
|
|
|
|
# role: binary_mode (aka _build_binary_mode) |
167
|
|
|
|
|
|
|
# parent: remote_conn |
168
|
|
|
|
|
|
|
# |
169
|
|
|
|
|
|
|
# Since we can't force an order, we introduced try_binary which gets |
170
|
|
|
|
|
|
|
# decided during BUILDARGS to tip us off as to whether we should try |
171
|
|
|
|
|
|
|
# binary mode or not. |
172
|
4
|
|
|
4
|
0
|
38509
|
my ( undef, %args ) = @_; |
173
|
|
|
|
|
|
|
|
174
|
4
|
50
|
33
|
|
|
27
|
if ( !exists $args{remote_server_addr} && !exists $args{port} ) { |
175
|
0
|
|
|
|
|
0
|
$args{try_binary} = 1; |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
# Windows may throw a fit about invalid pointers if we try to |
178
|
|
|
|
|
|
|
# connect to localhost instead of 127.1 |
179
|
0
|
|
|
|
|
0
|
$args{remote_server_addr} = '127.0.0.1'; |
180
|
|
|
|
|
|
|
} |
181
|
|
|
|
|
|
|
else { |
182
|
4
|
|
|
|
|
14
|
$args{try_binary} = 0; |
183
|
4
|
|
|
|
|
10
|
$args{binary_mode} = 0; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
|
186
|
4
|
|
|
|
|
87
|
return {%args}; |
187
|
|
|
|
|
|
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
sub _build_binary_mode { |
190
|
0
|
|
|
0
|
|
0
|
my ($self) = @_; |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
# We don't know what to do without a binary driver to start up |
193
|
0
|
0
|
|
|
|
0
|
return unless $self->_real_binary; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
# Either the user asked for 4444, or we couldn't find an open port |
196
|
0
|
|
|
|
|
0
|
my $port = $self->port + 0; |
197
|
0
|
0
|
|
|
|
0
|
return if $port == 4444; |
198
|
0
|
0
|
0
|
|
|
0
|
if ( $self->fixed_ports && $port == 0 ) { |
199
|
0
|
|
|
|
|
0
|
die 'port ' |
200
|
|
|
|
|
|
|
. $self->binary_port |
201
|
|
|
|
|
|
|
. ' is not free and have requested fixed ports'; |
202
|
|
|
|
|
|
|
} |
203
|
|
|
|
|
|
|
|
204
|
0
|
|
|
|
|
0
|
$self->_handle_firefox_setup($port); |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
0
|
system( $self->_command ); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
my $success = |
209
|
0
|
|
|
0
|
|
0
|
wait_until { probe_port($port) } timeout => $self->startup_timeout; |
|
0
|
|
|
|
|
0
|
|
210
|
0
|
0
|
|
|
|
0
|
if ($success) { |
211
|
0
|
|
|
|
|
0
|
return 1; |
212
|
|
|
|
|
|
|
} |
213
|
|
|
|
|
|
|
else { |
214
|
0
|
|
|
|
|
0
|
die 'Unable to connect to the ' |
215
|
|
|
|
|
|
|
. $self->_real_binary |
216
|
|
|
|
|
|
|
. ' binary on port ' |
217
|
|
|
|
|
|
|
. $port; |
218
|
|
|
|
|
|
|
} |
219
|
|
|
|
|
|
|
} |
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub _handle_firefox_setup { |
222
|
0
|
|
|
0
|
|
0
|
my ( $self, $port ) = @_; |
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
# This is a no-op for other browsers |
225
|
0
|
0
|
|
|
|
0
|
return unless $self->isa('Selenium::Firefox'); |
226
|
|
|
|
|
|
|
|
227
|
0
|
0
|
|
|
|
0
|
my $user_profile = |
228
|
|
|
|
|
|
|
$self->has_firefox_profile |
229
|
|
|
|
|
|
|
? $self->firefox_profile |
230
|
|
|
|
|
|
|
: 0; |
231
|
|
|
|
|
|
|
|
232
|
0
|
|
|
|
|
0
|
my $profile = |
233
|
|
|
|
|
|
|
setup_firefox_binary_env( $port, $self->marionette_port, $user_profile ); |
234
|
|
|
|
|
|
|
|
235
|
0
|
0
|
|
|
|
0
|
if ( $self->_is_old_ff ) { |
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# For non-geckodriver/non-marionette, we want to get rid of |
238
|
|
|
|
|
|
|
# the profile so that we don't accidentally zip it and encode |
239
|
|
|
|
|
|
|
# it down the line while Firefox is trying to read from it. |
240
|
0
|
0
|
|
|
|
0
|
$self->clear_firefox_profile if $self->has_firefox_profile; |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
else { |
243
|
|
|
|
|
|
|
# For geckodriver/marionette, we keep the enhanced profile around because |
244
|
|
|
|
|
|
|
# we need to send it to geckodriver as a zipped b64-encoded |
245
|
|
|
|
|
|
|
# directory. |
246
|
0
|
|
|
|
|
0
|
$self->firefox_profile($profile); |
247
|
|
|
|
|
|
|
} |
248
|
|
|
|
|
|
|
} |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
sub shutdown_binary { |
251
|
4
|
|
|
4
|
0
|
11
|
my ($self) = @_; |
252
|
|
|
|
|
|
|
|
253
|
4
|
50
|
|
|
|
89
|
return unless $self->auto_close(); |
254
|
4
|
50
|
|
|
|
62
|
if ( defined $self->session_id ) { |
255
|
0
|
|
|
|
|
0
|
$self->quit(); |
256
|
|
|
|
|
|
|
} |
257
|
4
|
50
|
33
|
|
|
82
|
if ( $self->has_binary_mode && $self->binary_mode ) { |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# Tell the binary itself to shutdown |
260
|
0
|
|
|
|
|
0
|
my $port = $self->port; |
261
|
0
|
|
|
|
|
0
|
my $ua = $self->ua; |
262
|
0
|
|
|
|
|
0
|
$ua->get( 'http://127.0.0.1:' . $port . '/wd/hub/shutdown' ); |
263
|
|
|
|
|
|
|
|
264
|
|
|
|
|
|
|
# Close the orphaned command windows on windows |
265
|
0
|
|
|
|
|
0
|
$self->shutdown_windows_binary; |
266
|
0
|
|
|
|
|
0
|
$self->shutdown_unix_binary; |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
} |
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub shutdown_unix_binary { |
272
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
273
|
0
|
|
|
|
|
0
|
if (!IS_WIN) { |
274
|
0
|
|
|
|
|
0
|
my $cmd = "lsof -t -i :".$self->port(); |
275
|
0
|
0
|
|
|
|
0
|
my ( $pid ) = grep { $_ && $_ ne $$ } split( /\s+/, scalar `$cmd` ); |
|
0
|
|
|
|
|
0
|
|
276
|
0
|
0
|
|
|
|
0
|
if ($pid) { |
277
|
0
|
|
|
|
|
0
|
print "Killing Driver PID $pid listening on port " |
278
|
|
|
|
|
|
|
. $self->port . "...\n"; |
279
|
0
|
|
|
|
|
0
|
eval { kill 'KILL', $pid }; |
|
0
|
|
|
|
|
0
|
|
280
|
0
|
0
|
|
|
|
0
|
warn |
281
|
|
|
|
|
|
|
"Could not kill driver process! you may have to clean up manually." |
282
|
|
|
|
|
|
|
if $@; |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
} |
285
|
|
|
|
|
|
|
} |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
sub shutdown_windows_binary { |
288
|
0
|
|
|
0
|
0
|
0
|
my ($self) = @_; |
289
|
|
|
|
|
|
|
|
290
|
0
|
|
|
|
|
0
|
if (IS_WIN) { |
291
|
|
|
|
|
|
|
if ( $self->_is_old_ff ) { |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# FIXME: Blech, handle a race condition that kills the |
294
|
|
|
|
|
|
|
# driver before it's finished cleaning up its sessions. In |
295
|
|
|
|
|
|
|
# particular, when the perl process ends, it wants to |
296
|
|
|
|
|
|
|
# clean up the temp directory it created for the Firefox |
297
|
|
|
|
|
|
|
# profile. But, if the Firefox process is still running, |
298
|
|
|
|
|
|
|
# it will have a lock on the temp profile directory, and |
299
|
|
|
|
|
|
|
# perl will get upset. This "solution" is _very_ bad. |
300
|
|
|
|
|
|
|
sleep(2); |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Firefox doesn't have a Driver/Session architecture - the |
303
|
|
|
|
|
|
|
# only thing running is Firefox itself, so there's no |
304
|
|
|
|
|
|
|
# other task to kill. |
305
|
|
|
|
|
|
|
return; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
system( 'taskkill /FI "WINDOWTITLE eq ' |
308
|
|
|
|
|
|
|
. $self->window_title |
309
|
|
|
|
|
|
|
. '" > nul 2>&1' ); |
310
|
|
|
|
|
|
|
} |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
sub DEMOLISH { |
314
|
4
|
|
|
4
|
0
|
6192
|
my ( $self, $in_gd ) = @_; |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
# if we're in global destruction, all bets are off. |
317
|
4
|
50
|
|
|
|
15
|
return if $in_gd; |
318
|
4
|
|
|
|
|
35
|
$self->shutdown_binary; |
319
|
|
|
|
|
|
|
} |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
sub _construct_command { |
322
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
323
|
0
|
|
|
|
|
|
my $executable = $self->_real_binary; |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
# Executable path names may have spaces |
326
|
0
|
|
|
|
|
|
$executable = '"' . $executable . '"'; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
# The different binaries take different arguments for proper setup |
329
|
0
|
|
|
|
|
|
$executable .= $self->_binary_args; |
330
|
0
|
0
|
|
|
|
|
if ( $self->has_custom_args ) { |
331
|
0
|
|
|
|
|
|
$executable .= ' ' . $self->custom_args; |
332
|
|
|
|
|
|
|
} |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
# Handle Windows vs Unix discrepancies for invoking shell commands |
335
|
0
|
|
|
|
|
|
my ( $prefix, $suffix ) = ( $self->_cmd_prefix, $self->_cmd_suffix ); |
336
|
0
|
|
|
|
|
|
return join( ' ', ( $prefix, $executable, $suffix ) ); |
337
|
|
|
|
|
|
|
} |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
sub _cmd_prefix { |
340
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
341
|
|
|
|
|
|
|
|
342
|
0
|
|
|
|
|
|
my $prefix = ''; |
343
|
0
|
|
|
|
|
|
if (IS_WIN) { |
344
|
|
|
|
|
|
|
$prefix = 'start "' . $self->window_title . '"'; |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
if ( $self->_is_old_ff ) { |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
# For older versions of Firefox that run without |
349
|
|
|
|
|
|
|
# marionette, the command we're running actually starts up |
350
|
|
|
|
|
|
|
# the browser itself, so we don't want to minimize it. |
351
|
|
|
|
|
|
|
return $prefix; |
352
|
|
|
|
|
|
|
} |
353
|
|
|
|
|
|
|
else { |
354
|
|
|
|
|
|
|
# If we're firefox with marionette, or any other browser, |
355
|
|
|
|
|
|
|
# the command we're running is the driver, and we don't |
356
|
|
|
|
|
|
|
# need want the command window in the foreground. |
357
|
|
|
|
|
|
|
return $prefix . ' /MIN '; |
358
|
|
|
|
|
|
|
} |
359
|
|
|
|
|
|
|
} |
360
|
0
|
|
|
|
|
|
return $prefix; |
361
|
|
|
|
|
|
|
} |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
sub _cmd_suffix { |
364
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
365
|
0
|
|
|
|
|
|
return " > " . $self->logfile . " 2>&1 " if IS_WIN; |
366
|
0
|
|
|
|
|
|
return " > " . $self->logfile . " 2>&1 &"; |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
|
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
1; |
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
__END__ |