File Coverage

blib/lib/Treex/Core/Run.pm
Criterion Covered Total %
statement 9 11 81.8
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 13 15 86.6


line stmt bran cond sub pod time code
1             package Treex::Core::Run;
2             $Treex::Core::Run::VERSION = '2.20150928';
3 1     1   72798 use 5.008;
  1         5  
4              
5 1     1   895 use Moose;
  1         415562  
  1         6  
6 1     1   7283 use Treex::Core::Common;
  1         3  
  1         4  
7 1     1   6309 use Treex::Core;
  0            
  0            
8             use MooseX::SemiAffordanceAccessor 0.09;
9             with 'MooseX::Getopt';
10              
11              
12             # TODO some of these modules might not be needed, check this
13             use Cwd;
14             use File::Path;
15             use File::Temp qw(tempdir);
16             use File::Which;
17             use List::MoreUtils qw(first_index);
18             use IO::Interactive;
19             use Time::HiRes;
20             use Readonly;
21             use POSIX;
22             use Exporter;
23             use Sys::Hostname;
24             use base 'Exporter';
25              
26             use File::Glob 'bsd_glob';
27              
28             our @EXPORT_OK = q(treex);
29              
30             has 'save' => (
31             traits => ['Getopt'],
32             cmd_aliases => 's',
33             is => 'rw',
34             isa => 'Bool',
35             default => 0,
36             documentation => 'save all documents',
37             );
38              
39             has 'quiet' => (
40             traits => ['Getopt'],
41             cmd_aliases => 'q',
42             is => 'rw',
43             isa => 'Bool',
44             default => 0,
45             trigger => sub { Treex::Core::Log::log_set_error_level('FATAL'); },
46             documentation => q{Warning, info and debug messages are suppressed. Only fatal errors are reported.},
47             );
48              
49             has 'cleanup' => (
50             traits => ['Getopt'],
51             is => 'rw', isa => 'Bool', default => 0,
52             documentation => q{Delete all temporary files.},
53             );
54              
55             has 'error_level' => (
56             traits => ['Getopt'],
57             cmd_aliases => 'e',
58             is => 'rw', isa => 'ErrorLevel', default => 'INFO',
59             trigger => sub { Treex::Core::Log::log_set_error_level( $_[1] ); },
60             documentation => q{Possible values: ALL, DEBUG, INFO, WARN, FATAL},
61             );
62              
63             has 'lang' => (
64             traits => ['Getopt'],
65             cmd_aliases => [ 'language', 'L' ],
66             is => 'rw', isa => 'Str',
67             documentation => q{shortcut for adding "Util::SetGlobal language=xy" at the beginning of the scenario},
68             );
69              
70             has 'selector' => (
71             traits => ['Getopt'],
72             cmd_aliases => 'S',
73             is => 'rw', isa => 'Str',
74             documentation => q{shortcut for adding "Util::SetGlobal selector=xy" at the beginning of the scenario},
75             );
76              
77             has 'tokenize' => (
78             traits => ['Getopt'],
79             cmd_aliases => 't',
80             is => 'rw', isa => 'Bool',
81             documentation => q{shortcut for adding "Read::Sentences W2A::Tokenize" at the beginning of the scenario (or W2A::XY::Tokenize if used with --lang=xy)},
82             );
83              
84              
85             # treex -h should not print "Unknown option: h" before the usage.
86             #has 'help' => (
87             # traits => ['Getopt'],
88             # cmd_aliases => 'h',
89             # is => 'ro', isa => 'Bool', default => 0,
90             # documentation => q{Print usage info},
91             #);
92              
93             has 'filenames' => (
94             traits => ['NoGetopt'],
95             is => 'rw',
96             isa => 'ArrayRef[Str]',
97             documentation => 'treex file names',
98             );
99              
100             has 'scenario' => (
101             traits => ['NoGetopt'],
102             is => 'rw',
103             isa => 'Treex::Core::Scenario',
104             predicate => '_has_scenario',
105             documentation => 'scenario object',
106             );
107              
108              
109             has 'watch' => (
110             traits => ['Getopt'],
111             is => 'ro',
112             isa => 'Str',
113             documentation => 're-run when the given file is changed TODO better doc',
114             );
115              
116             has 'dump_scenario' => (
117             traits => ['Getopt'],
118             cmd_aliases => 'd',
119             is => 'rw',
120             isa => 'Bool',
121             default => 0,
122             documentation => 'Just dump (print to STDOUT) the given scenario and exit.',
123             );
124              
125             has 'dump_required_files' => (
126             traits => ['Getopt'],
127             is => 'rw',
128             isa => 'Bool',
129             default => 0,
130             documentation => 'Just dump (print to STDOUT) files required by the given scenario and exit.',
131             );
132              
133             has 'cache' => (
134             traits => ['Getopt'],
135             is => 'rw',
136             isa => 'Str',
137             default => "",
138             documentation => 'Use cache. Required memory is specified in format memcached,loading. Numbers are in GB.',
139             );
140              
141             has version => (
142             traits => ['Getopt'],
143             is => 'ro',
144             isa => 'Bool',
145             default => 0,
146             cmd_aliases => 'v',
147             documentation => q(Print treex and perl version),
148             trigger => sub {
149             print get_version();
150             exit();
151             },
152             );
153              
154             #
155             # Parallel head execution options
156             # TODO move them to Treex::Core::Parallel::Head
157              
158             has 'forward_error_level' => (
159             traits => ['Getopt'],
160             cmd_aliases => 'E',
161             is => 'rw', isa => 'ErrorLevel', default => 'WARN',
162             documentation => q{messages with this level or higher will be forwarded from the distributed jobs to the main STDERR},
163             );
164              
165              
166             has 'parallel' => (
167             traits => ['Getopt'],
168             cmd_aliases => 'p',
169             is => 'rw',
170             isa => 'Bool',
171             default => 0,
172             documentation => 'Parallelize the task on SGE cluster (using qsub).',
173             );
174              
175             has 'jobs' => (
176             traits => ['Getopt'],
177             cmd_aliases => 'j',
178             is => 'ro',
179             isa => 'Int',
180             default => 10,
181             documentation => 'Number of jobs for parallelization, default 10. Requires -p.',
182             );
183              
184              
185             has 'local' => (
186             traits => ['Getopt'],
187             is => 'ro',
188             isa => 'Bool',
189             documentation => 'Run jobs locally (might help with multi-core machines). Requires -p.',
190             );
191              
192             has 'priority' => (
193             traits => ['Getopt'],
194             is => 'ro',
195             isa => 'Int',
196             default => -100,
197             documentation => 'Priority for qsub, an integer in the range -1023 to 0 (or 1024 for admins), default=-100. Requires -p.',
198             );
199              
200             has 'mem' => (
201             traits => ['Getopt'],
202             cmd_aliases => [ 'm', 'memory' ],
203             is => 'ro',
204             isa => 'Str',
205             default => '2G',
206             documentation => 'How much memory should be allocated for cluster jobs, default=2G. Requires -p. '
207             . 'Translates to "qsub -hard -l mem_free=$mem -l h_vmem=2*$mem -l act_mem_free=$mem". '
208             . 'Use --mem=0 and --qsub to set your own SGE settings (e.g. if act_mem_free is not available).',
209             );
210              
211             has 'name' => (
212             traits => ['Getopt'],
213             is => 'ro',
214             isa => 'Str',
215             default => '',
216             documentation => 'Prefix of submitted jobs. Requires -p. '
217             . 'Translates to "qsub -N $name-jobname".',
218             );
219              
220             has 'qsub' => (
221             traits => ['Getopt'],
222             is => 'ro',
223             isa => 'Str',
224             default => '',
225             documentation => 'Additional parameters passed to qsub. Requires -p. '
226             . 'See --priority and --mem. You can use e.g. --qsub="-q *@p*,*@s*" to use just machines p* and s*. '
227             . 'Or e.g. --qsub="-q *@!(twi*|pan*)" to skip twi* and pan* machines.',
228             );
229              
230             has 'workdir' => (
231             is => 'rw',
232             traits => ['Getopt'],
233             isa => 'Str',
234             default => './{NNN}-cluster-run-{XXXXX}',
235             documentation => 'working directory for temporary files in parallelized processing; ' .
236             'one can create automatic directories by using patterns: ' .
237             '{NNN} is replaced by an ordinal number with so many leading zeros to have length of the number of Ns, ' .
238             '{XXXX} is replaced by a random string, whose length is the same as the number of Xs (min. 4). ' .
239             'If not specified, directories such as 001-cluster-run, 002-cluster-run etc. are created',
240             );
241              
242             has 'sge_job_numbers' => (
243             is => 'rw',
244             traits => ['NoGetopt'],
245             documentation => 'list of numbers of jobs executed on sge',
246             default => sub { [] },
247             );
248              
249             has 'survive' => (
250             traits => ['Getopt'],
251             is => 'rw',
252             isa => 'Bool',
253             default => 0,
254             documentation => 'Continue collecting jobs\' outputs even if some of them crashed (risky, use with care!).',
255             );
256              
257              
258             #
259             # Parallel node/worker execution options
260             # TODO move them to Treex::Core::Parallel::Node
261              
262             has 'jobindex' => (
263             traits => ['Getopt'],
264             is => 'ro',
265             isa => 'Int',
266             documentation => 'Not to be used manually. If number of jobs is set to J and modulo set to M, only I-th files fulfilling I mod J == M are processed.',
267             );
268              
269             has 'outdir' => (
270             traits => ['Getopt'],
271             is => 'ro',
272             isa => 'Str',
273             documentation => 'Not to be used manually. Dictory for collecting standard and error outputs in parallelized processing.',
274             );
275              
276             has 'server' => (
277             traits => ['Getopt'],
278             is => 'ro',
279             isa => 'Str',
280             default => '',
281             documentation => 'Not to be used manually. Used to point parallel jobs to the head.',
282             );
283              
284             #
285             #
286             #
287              
288             sub _usage_format {
289             return "usage: %c %o scenario [-- treex_files]\nscenario is a sequence of blocks or *.scen files\noptions:";
290             }
291              
292             #gets info about version of treex and perl
293             sub get_version {
294             my $perl_v = $^V;
295             my $perl_x = $^X;
296             my $treex_v = $Treex::Core::Run::VERSION || 'DEV';
297             my $treex_x = which('treex');
298              
299             # File::Which::which sometimes fails to found treex.
300             if ( !defined $treex_x ) {
301             chomp( $treex_x = `which treex 2> /dev/null` );
302             $treex_x ||= '<treex not found in $PATH>';
303             }
304             my $version_string = <<"VERSIONS";
305             Treex version: $treex_v from $treex_x
306             Perl version: $perl_v from $perl_x
307             VERSIONS
308             return $version_string;
309             }
310              
311             sub BUILD {
312              
313             # more complicated tests on consistency of options will be place here
314             my ($self) = @_;
315              
316             return;
317             }
318              
319              
320             sub _execute {
321             my ($self) = @_;
322              
323             if ( $self->dump_scenario || $self->dump_required_files ) {
324              
325             # If someone wants to run treex -d My::Block my_scen.scen
326             my $scen_str = $self->_construct_scenario_string_with_quoted_whitespace();
327             $self->set_scenario( Treex::Core::Scenario->new( scenario_string => $scen_str, runner => $self ) );
328              
329             # TODO: Do it properly - perhaps, add a Scenario option to not load all the blocks.
330             # We cannot create the real scenario instance without loading all the blocks
331             # However, since r6307 some Scenario's functions were changed to methods, so we must create a dummy instance.
332              
333             #my @block_items = Treex::Core::Scenario::parse_scenario_string($scen_str);
334             #my @block_items = $dummy_scenario->parse_scenario_string($scen_str);
335              
336             if ( $self->dump_scenario ) {
337             print "# Full Scenario generated by 'treex --dump_scenario' on " . localtime() . "\n";
338             print $self->scenario->construct_scenario_string( multiline => 1 ), "\n";
339             }
340              
341             if ( $self->dump_required_files ) {
342             print "# Required files generated by 'treex --dump_required_files' on " . localtime() . "\n";
343             print join "\n", $self->scenario->get_required_files(), "\n";
344             }
345             exit;
346             }
347              
348             if ( $self->dump_required_files ) {
349              
350             my $scen_str = join ' ', @{ $self->extra_argv };
351             $self->set_scenario( Treex::Core::Scenario->new( scenario_string => $scen_str, runner => $self ) );
352              
353             print "# Required files generated by 'treex --dump_required_files' on " . localtime() . "\n";
354             print join "\n", $self->scenario->get_required_files(), "\n";
355             exit;
356             }
357             my $done = 0;
358             my $time;
359             my $watch = $self->watch;
360              
361             if ( defined $watch ) {
362             log_fatal "Watch file '$watch' does not exists" if !-f $watch;
363             $time = ( stat $watch )[9];
364             }
365              
366             while ( !$done ) {
367            
368             $self->_execute_scenario();
369              
370             $done = 1;
371             my $info_written = 0;
372             WATCH_CHANGE:
373             while ( defined $watch && -f $watch ) {
374             my $new_time = ( stat $watch )[9];
375             if ( $new_time > $time ) {
376             $time = $new_time;
377             $done = 0;
378             last WATCH_CHANGE;
379             }
380             if ( !$info_written ) {
381             log_info "Watching '$watch' file. Touch it to re-run, delete to quit.";
382             $info_written = 1;
383             }
384             sleep 1;
385             }
386             }
387             return;
388             }
389              
390             my %READER_FOR = (
391             'treex' => 'Treex',
392             'treex.gz' => 'Treex',
393             'txt' => 'Text',
394             'txt.gz' => 'Text',
395             'streex' => 'Treex',
396             'mrg' => 'PennMrg',
397             'mrg.gz' => 'PennMrg',
398             'tag' => 'CdtTag',
399              
400             # TODO:
401             # conll => 'Conll',
402             # plsgz => 'Plsgz',
403             # tmt
404             );
405              
406             sub _get_reader_name_for {
407             my $self = shift;
408             my @names = @_;
409             my $base_re = join( '|', keys %READER_FOR );
410             my $re = qr{\.($base_re)$};
411             my @extensions;
412             my $first;
413              
414             foreach my $name (@names) {
415             if ( $name =~ /$re/ ) {
416             my $current = $1;
417             $current =~ s/\.gz$//;
418             if ( !defined $first ) {
419             $first = $current;
420             }
421             if ( $current ne $first ) {
422             log_fatal 'All files (' . join( ',', @names ) . ') must have the same extension' . "\n" .
423             " current = $current\n" .
424             " first = $first\n" .
425             " curname = $name";
426             }
427             push @extensions, $current;
428             }
429             else {
430             log_fatal 'Files (' . join( ',', @names ) . ') must have extensions';
431             }
432             }
433             my $r = $READER_FOR{$first};
434             log_fatal "There is no DocumentReader implemented for extension '$first'" if !$r;
435             return "Read::$r";
436             }
437              
438             # This is where the main work is done. It is overridden in parallel execution.
439             sub _execute_scenario {
440             my ($self) = @_;
441            
442             log_info "Local (single-process) execution.";
443              
444             $self->_init_scenario();
445              
446             my $scenario = $self->scenario;
447              
448             my $runnin_started = time;
449             $scenario->run();
450              
451             log_info "Running the scenario took " . ( time - $runnin_started ) . " seconds";
452              
453             return;
454             }
455              
456             # Parameters can contain whitespaces that should be preserved
457             sub _construct_scenario_string_with_quoted_whitespace {
458             my ($self) = @_;
459             my @arguments;
460             foreach my $arg ( @{ $self->extra_argv } ) {
461             if ( $arg =~ /(\S+)=(.*\s.*)$/ ) {
462             my ( $name, $value ) = ( $1, $2 );
463             $value =~ s/'/\\'/g;
464             push @arguments, qq($name='$value');
465             }
466             else {
467             push @arguments, $arg;
468             }
469             }
470             return join ' ', @arguments;
471             }
472              
473             sub _init_scenario {
474             my ($self) = @_;
475              
476             my $scen_str = $self->_construct_scenario_string_with_quoted_whitespace();
477              
478             # some command line options are just shortcuts for blocks; the blocks are added to the scenario now
479             if ( $self->filenames ) {
480             my $reader = $self->_get_reader_name_for( @{ $self->filenames } );
481             log_info "Block $reader added to the beginning of the scenario.";
482             $scen_str = "$reader from=" . join( ',', @{ $self->filenames } ) . " $scen_str";
483             }
484              
485             if ( $self->save ) {
486             log_info "Block Write::Treex added to the end of the scenario.";
487             $scen_str .= ' Write::Treex';
488             }
489              
490             if ( $self->tokenize ) {
491             my $tokenizer = 'W2A::Tokenize';
492             my $lang = $self->lang;
493             if ($lang && $lang ne 'all'){
494             my $module = 'Treex::Block::W2A::' . uc($lang) . '::Tokenize';
495             if (eval "use $module;1"){
496             $tokenizer = 'W2A::' . uc($lang) . '::Tokenize';
497             }
498             }
499             $scen_str = "Read::Sentences $tokenizer $scen_str";
500             }
501              
502             if ( $self->lang ) {
503             $scen_str = 'Util::SetGlobal language=' . $self->lang . " $scen_str";
504             }
505              
506             if ( $self->selector ) {
507             $scen_str = 'Util::SetGlobal selector=' . $self->selector . " $scen_str";
508             }
509              
510             my $loading_started = time;
511             if ( $self->_has_scenario ) {
512             $self->scenario->restart();
513             }
514             else {
515             $self->set_scenario( Treex::Core::Scenario->new( from_string => $scen_str, runner => $self ) );
516             $self->scenario->load_blocks;
517             }
518              
519             my $loading_ended = time;
520             log_info "Loading the scenario took " . ( $loading_ended - $loading_started ) . " seconds";
521              
522             return;
523             }
524              
525              
526             # A factory subroutine, creating the right Treex object for the job.
527             # (local single-process: Treex::Core::Run, parallel processing head: Treex::Parallel::Head,
528             # parallel processing worker node: Treex::Parallel::Node)
529             sub treex {
530              
531             # ref to array of arguments, or a string containing all arguments as on the command line
532             my $arguments = shift;
533              
534             if ( ref($arguments) eq 'ARRAY' && scalar @$arguments > 0 ) {
535             my $idx = first_index { $_ eq '--' } @$arguments;
536             my %args = ( argv => $arguments );
537             if ( $idx != -1 ) {
538             $args{filenames} = [ splice @$arguments, $idx + 1 ];
539             pop @$arguments; # delete "--"
540             }
541             my $runner;
542            
543             if (any { $_ =~ /^--jobindex/ } @$arguments){
544             require Treex::Core::Parallel::Node;
545             $runner = Treex::Core::Parallel::Node->new_with_options( \%args );
546             }
547             elsif (any { $_ =~ /^(--parallel|-p|-pj\d+)$/ } @$arguments){
548             require Treex::Core::Parallel::Head;
549             $runner = Treex::Core::Parallel::Head->new_with_options( \%args );
550             }
551             else {
552             $runner = Treex::Core::Run->new_with_options( \%args );
553             }
554             $runner->_execute();
555              
556             }
557              
558             elsif ( defined $arguments && ref($arguments) ne 'ARRAY' ) {
559             treex( [ grep { defined $_ && $_ ne '' } split( /\s/, $arguments ) ] );
560             }
561              
562             else {
563             treex('--help');
564              
565             #log_fatal 'Unspecified arguments for running treex.';
566             }
567             return;
568             }
569              
570             1;
571              
572             __END__
573              
574             =head2 --watch option
575              
576             SYNOPSIS:
577             touch timestamp.file
578             treex --watch=timestamp.file my.scen & # or without & and open another terminal
579             # after all documents are processed, treex is still running, watching timestamp.file
580             # you can modify any modules/blocks and then
581             touch timestamp.file
582             # All modified modules will be reloaded (the number of reloaded modules is printed).
583             # The document reader is restarted, so it starts reading the first file again.
584             # To exit this "watching loop" either rm timestamp.file or press Ctrl^C.
585              
586             BENEFITS:
587             * much faster development cycles (e.g. most time of en-cs translation is spent on loading)
588             * Now I have some non-deterministic problems with loading NER::Stanford
589             - using --watch I get it loaded on all jobs once and then I don't have to reload it.
590              
591             TODO:
592             * modules are just reloaded, no constructors are called yet
593              
594              
595             =for Pod::Coverage BUILD get_version
596              
597             =encoding utf-8
598              
599             =head1 NAME
600              
601             Treex::Core::Run + treex - applying Treex blocks and/or scenarios on data
602              
603             =head1 VERSION
604              
605             version 2.20150928
606              
607             =head1 SYNOPSIS
608              
609             In bash:
610              
611             > treex myscenario.scen -- data/*.treex
612             > treex My::Block1 My::Block2 -- data/*.treex
613              
614             In Perl:
615              
616             use Treex::Core::Run q(treex);
617             treex([qw(myscenario.scen -- data/*.treex)]);
618             treex([qw(My::Block1 My::Block2 -- data/*.treex)]);
619              
620             =head1 DESCRIPTION
621              
622             C<Treex::Core::Run> allows to apply a block, a scenario, or their mixture on a
623             set of data files. It is designed to be used primarily from bash command line,
624             using a thin front-end script called C<treex>. However, the same list of
625             arguments can be passed by an array reference to the function C<treex()>
626             imported from C<Treex::Core::Run>.
627              
628             Note that this module supports distributed processing (Linux-only!), simply by
629             adding the switch C<-p>. The C<treex> method then creates a
630             C<Treex::Core::Parallel::Head> object, which extends C<Treex::Core::Run>
631             by providing parallel processing functionality.
632              
633             Then there are two ways to process the data in a parallel fashion. By
634             default, SGE cluster\'s C<qsub> is expected to be available. If you have no
635             cluster but want to make the computation parallelized at least on a multicore
636             machine, add the C<--local> switch.
637              
638             =head1 SUBROUTINES
639              
640             =over 4
641              
642             =item treex
643              
644             create new runner and runs scenario given in parameters
645              
646             =back
647              
648             =head1 USAGE
649              
650             usage: treex [-?dEehjLmpqSstv] [long options...] scenario [-- treex_files]
651             scenario is a sequence of blocks or *.scen files
652             options:
653             -h -? --usage --help Prints this usage information.
654             -s --save save all documents
655             -q --quiet Warning, info and debug messages are
656             suppressed. Only fatal errors are
657             reported.
658             --cleanup Delete all temporary files.
659             -e --error_level Possible values: ALL, DEBUG, INFO, WARN,
660             FATAL
661             -L --language --lang shortcut for adding "Util::SetGlobal
662             language=xy" at the beginning of the
663             scenario
664             -S --selector shortcut for adding "Util::SetGlobal
665             selector=xy" at the beginning of the
666             scenario
667             -t --tokenize shortcut for adding "Read::Sentences
668             W2A::Tokenize" at the beginning of the
669             scenario (or W2A::XY::Tokenize if used
670             with --lang=xy)
671             --watch re-run when the given file is changed
672             TODO better doc
673             -d --dump_scenario Just dump (print to STDOUT) the given
674             scenario and exit.
675             --dump_required_files Just dump (print to STDOUT) files
676             required by the given scenario and exit.
677             --cache Use cache. Required memory is specified
678             in format memcached,loading. Numbers are
679             in GB.
680             -v --version Print treex and perl version
681             -E --forward_error_level messages with this level or higher will
682             be forwarded from the distributed jobs
683             to the main STDERR
684             -p --parallel Parallelize the task on SGE cluster
685             (using qsub).
686             -j --jobs Number of jobs for parallelization,
687             default 10. Requires -p.
688             --local Run jobs locally (might help with
689             multi-core machines). Requires -p.
690             --priority Priority for qsub, an integer in the
691             range -1023 to 0 (or 1024 for admins),
692             default=-100. Requires -p.
693             --memory -m --mem How much memory should be allocated for
694             cluster jobs, default=2G. Requires -p.
695             Translates to "qsub -hard -l
696             mem_free=$mem -l h_vmem=2*$mem -l
697             act_mem_free=$mem". Use --mem=0 and
698             --qsub to set your own SGE settings
699             (e.g. if act_mem_free is not available).
700             --name Prefix of submitted jobs. Requires -p.
701             Translates to "qsub -N $name-jobname".
702             --qsub Additional parameters passed to qsub.
703             Requires -p. See --priority and --mem.
704             You can use e.g. --qsub="-q *@p*,*@s*"
705             to use just machines p* and s*. Or e.g.
706             --qsub="-q *@!(twi*|pan*)" to skip twi*
707             and pan* machines.
708             --workdir working directory for temporary files in
709             parallelized processing; one can create
710             automatic directories by using patterns:
711             {NNN} is replaced by an ordinal number
712             with so many leading zeros to have
713             length of the number of Ns, {XXXX} is
714             replaced by a random string, whose
715             length is the same as the number of Xs
716             (min. 4). If not specified, directories
717             such as 001-cluster-run, 002-cluster-run
718             etc. are created
719             --survive Continue collecting jobs' outputs even
720             if some of them crashed (risky, use with
721             care!).
722             --jobindex Not to be used manually. If number of
723             jobs is set to J and modulo set to M,
724             only I-th files fulfilling I mod J == M
725             are processed.
726             --outdir Not to be used manually. Dictory for
727             collecting standard and error outputs in
728             parallelized processing.
729             --server Not to be used manually. Used to point
730             parallel jobs to the head.
731              
732             =head1 AUTHORS
733              
734             ZdenÄ›k Žabokrtský <zabokrtsky@ufal.mff.cuni.cz>
735              
736             Martin Popel <popel@ufal.mff.cuni.cz>
737              
738             Martin MajliÅ¡
739              
740             OndÅ™ej DuÅ¡ek <odusek@ufal.mff.cuni.cz>
741              
742             =head1 COPYRIGHT AND LICENSE
743              
744             Copyright © 2011-2014 by Institute of Formal and Applied Linguistics, Charles University in Prague
745              
746             This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.