paexec-1.1.1/0000755000175000017500000000000013431606354012676 5ustar cheusovcheusovpaexec-1.1.1/paexec/0000755000175000017500000000000013431606354014143 5ustar cheusovcheusovpaexec-1.1.1/paexec/paexec_reorder.pod0000644000175000017500000000462313431606350017637 0ustar cheusovcheusov=head1 NAME paexec_reorder - reorder sliced output of "paexec -l" =head1 SYNOPSIS B [I] [I] =head1 DESCRIPTION B with -l option produces a sliced output where results of different tasks are intermixed. The intent of B is to produce ordered output where results for all tasks follow each other without intermixing. It is strongly recomended to send output of "B I<-le>" or "B I<-gle>" to the input of B. Otherwise more memory or disk space for temporary files will be required. =head1 OPTIONS =over 6 =item B<-h> Display help information. =item B<-M> I If I is I, result is reordered in memory, this is the default. If it is I, temporary files are used for reordering. If I, B command is used. =item B<-l> Prepand output lines with the task number. =item B<-g> By default output of "B I<-le>" is expected on input. With I<-g> option, output of "B I<-gle>" is expected. In this case B will react on "fatal" B keyword. =item B<-x> If applied, output of "B -le [-g] I<-x>" is expected on input. This option has higher priority than PAEXEC_EOT environment variable. Actually B<-x> and B<-y> are synonyms. =item B<-y> If applied, output of "B -le [-g] I<-y>" is expected on input. This option has higher priority than PAEXEC_EOT environment variable. =item B<-S> Remove leading space character. =item B<-m> s=I =item B<-m> f=I =item B<-m> F=I =item B<-m> t=I Set alternative string for 'success', 'failure', 'fatal' and '' (end of task). =back =head1 EXAMPLES =over 6 paexec -t '/usr/bin/ssh -x' -n 'host1 host2 host3' \ -l -c ~/bin/complex_task | paexec_reorder paexec -gEI -lr -n 'host1 host2 host3' \ -c command -t /usr/bin/rsh < tasks.txt | paexec_reorder -lgS -Mf For other examples, see examples/ directory =back =head1 ENVIRONMENT =over 6 =item I I is used for creating temporary directory. See the appropriate man page. =item I The same as in B. =back =head1 BUGS/FEEDBACK Please send any comments, questions, bug reports etc. to me by e-mail or (even better) register them at sourceforge project home. Feature requests are also welcomed. =head1 HOME L =head1 SEE ALSO L L paexec-1.1.1/paexec/paexec.pod0000644000175000017500000003321313431606350016112 0ustar cheusovcheusov=head1 NAME paexec - parallel executor, distribute tasks over network or CPUs =head1 SYNOPSIS B I<[options]> B -C I<[options]> I I<[args...]> =head1 DESCRIPTION Suppose you have a long list of tasks that need to be done, for example, you want to convert thousands of .wav audio files to .ogg format. Also suppose that multiple CPUs are available, e.g. multi-CPU system or a cluster consisting of individual computers connected to the network or internet. B can efficiently do this work, that is, B efficiently distributes different tasks to different processors (or computers), receives the results of processing from them and sends these results to stdout. There are several notions that should be defined: I, I, I, I. I are read by B from stdin and are represented as one line of text, i.e. one input line - one task. I identifier - remote computer or CPU identifier, for example CPU ordinal number or computer's DNS name like node12.cluster.company.com. I - user's program that reads one-line task from stdin and sends multiline result to stdout ending with an end of task (EOT) marker. EOT marker means "Task is done. I am ready for the next one". After sending EOT to stdout, stdout MUST be flushed. Remember that EOT marker MUST NOT appears in general result. Otherwise, B may hang due to deadlock. The default EOT is an empty line. Command may use environment variable PAEXEC_EOT for the end-of-task marker. I - special program that helps to run I on I. It takes the I identifier as its first argument and I with its arguments as the rest. Good examples for transport are I and I. Both I and I may be specified with their arguments, e.g, '/usr/bin/ssh -x' is allowed as a I program. How B works. I are run on each I with a help of I program. Then, I are read from stdin one-by-one and sent to free I (exactly one task per node at a time). At the same time result lines are read from I stdout and are output to B stdout. When EOT marker is obtained from the I, it is marked as free and becomes ready for the next task. These steps repeat until the end of stdin is reached and all I finish their job. More formally (to better understand how paexec works): run_command_on_each_node mark_all_nodes_as_free while not(end_of_stdin) or not(all_nodes_are_free) while there_is_free_node/i and not(end_of_stdin) task = read_task_from_stdin send_task_to_node(task, i) mark_node_as_busy(i) end while result_line_from_node_is_available/i result = read_result_line_from_node(i) send_line_to_stdout(result) if is_EOT(result) mark_node_as_free(i) end end end close_command_on_each_node Note that Is are run once per node, it is not restarted for every task. Also note that output contains result lines (obtained from different I) in the mixed order. That is, the first line of the output may contain a result line obtain from the first I, the second line of output - from the second I, but the third output line may contain result line from the first I again. It is also not guaranteed that the first line of output will be from the first I or from the first I. All result lines are output as soon as they are read by B, i.e as soon as they are ready. B works this way for the efficiency reasons. You can play with I<-l>, I<-r> and I<-p> options to see what happens. For reordering output line you can use B utility. =head1 OPTIONS =over 6 =item B<-h> Display help information. =item B<-V> Display version information. =item B<-c> I Command with its arguments. =item B<-C> Command and its arguments are specified by free arguments. =item B<-t> I Transport program. =item B<-n> I<+number> A number of commands to run in parallel. =item B<-n> I List of nodes separated by space character. The first character must be alphanumeric, `_' or `/'. All other characters are reserved for future extensions. =item B<-n> I<:filename> Filename containing list of nodes, one per line. =item B<-x> Run command specificed by I<-c> for each task. Its stdout is sent to B. If both C<-x> and C<-g> are specified, task is considered failed if command's exit status is non-zero. =item B<-X> Implies I<-x> and ignore command's stdout. =item B<-r> Include node identifier or node number (0-based) to the output, i.e. id/number of node that produces this particular output line. This identifier or number appears before line number if I<-l> is also applied. Space character is used as a separator. =item B<-l> Include a 0-based task number (input line number) to the output, i.e. line number from which this particular output line was produced. It appears before pid if I<-p> is also applied. Space character is used as a separator. =item B<-p> Include pid of paexec's subprocess that communicates with I to the output. Pid prepends the actual result line. Space character is used as a separator. =item B<-e> When end-of-task marker is obtained from node, EOT marker is output to stdout. This option may be useful together with I<-l> and/or I<-r>. =item B<-E> Imply B<-e> and flushes stdout. =item B<-d> Turn on a debugging mode (for debugging purposes only) =item B<-i> Copy input lines (i.e. tasks) to stdout. =item B<-I> Imply B<-i> and flushes stdout. =item B<-s>|B<-g> Orgraph of tasks (partially ordered set) is read from stdin. Instead of autonomous tasks, graph of the tasks is read from stdin. In this mode every task can either FAIL or SUCCEED. As always an empty line output by I means I. The line before it shows an EXIT STATUS of the task. The word "failure" means failure, "success" - success and "fatal" means that the current task is reassigned to another node (and restarted, of course) (see option -z). See examples/1_div_x/cmd for the sample. An input line (paexec's stdin) should contain either single task without spaces inside or two tasks separated by single space character, e.g. task1task2. task1task2 line means that task1 must be done before task2 and it is mandatory, that is if task1 I all dependent tasks (including task2) are also failed recursively. Tasks having dependencies are started only after all dependencies are succeeded. When a task succeeds paexec outputs "success" word just before end_of_task marker (see -e or -E), otherwise "failure" word is output followed by a list of tasks failed because of it. Samples: tasks (examples/make_package/tasks file) textproc/dictem devel/autoconf wip/libmaa devel/gmake wip/libmaa wip/libmaa wip/dict-server wip/libmaa wip/dict-client devel/m4 wip/dict-server devel/byacc wip/dict-server devel/byacc wip/dict-client devel/flex wip/dict-server devel/flex wip/dict-client devel/glib2 devel/libjudy command (examples/make_package/cmd__flex) #!/usr/bin/awk -f { print $0 if ($0 == "devel/flex") print "failure" else print "success" print "" # end of task marker fflush() } output of "paexec -s -l -c cmd__flex -n +10 \ < tasks" 3 devel/autoconf 3 success 4 devel/gmake 4 success 7 devel/m4 7 success 8 devel/byacc 8 success 9 devel/flex 9 failure 9 devel/flex wip/dict-server wip/dict-client 10 devel/glib2 10 success 11 devel/libjudy 11 success 1 textproc/dictem 1 success 2 wip/libmaa 2 success =item B<-z> If applied, read/write(2) operations from/to nodes becomes not critical. In case paexec has lost connection to the node, it will reassign failed task to another node and, if -s applied, will output "fatal" string to stdout ("success" + "failure" + "fatal"). This makes paexec resistant to the I/O errors, as a result you can create paexec clusters even over network consisting of unreliable hosts (Internet?). Failed hosts are marked as such and will not be used during the current run of paexec. =item B<-Z> I When I<-z> applied, if a I fails, appropriate node is marked as broken and is excluded from the following task distribution. But if B<-Z> applied, every I seconds an attempt to rerun a comand on a failed node is made. I<-Z> implies I<-z>. This option makes possible to organize clusters over unreliable networks/hardware. =item B<-w> If I<-Z> option were applied, B exits with error if B nodes failed. With B<-w> it will not exit and will wait for restoring nodes. =item B<-m> s=I Set an alternative string for 'success' message. =item B<-m> f=I Set an alternative string for 'failure' message. =item B<-m> F=I Set an alternative string for 'fatal' message. An empty string for 'fatal' means it will not be output to stdout in case of fatal error. =item B<-m> t=I Set an alternative string for EOT message. =item B<-m> d=I Set an alternative string for tasks delimiter (for I<-g> mode). Delimiter should be at most one character. No delimiter means an entire input line is treated as a task. =item B<-m> w=I Set an alternative string for "weight:" message. =item B<-W> I When multiple machines or CPUs are used for tasks processing, it makes sense to start "heavier" tasks as soon as possible in order to minimize total calculatiion time. If B<-W> is specified, special weight is assigned to each tasks which is used for reordering tasks. If I is 0, weights themselves are used for reordering tasks. The bigger weight is, the more priority of the task is. If I is 1, the total weight of task is a sum of its own weight (specified on input) and weights of all tasks depending on it directly or indirectly. If I is 2, the total weight of task is a maximum value of task's own weight and weights of all tasks depending on it directly or indirectly. Weights are specified with a help of "weight:" keyword (unless I<-m w=> was specified). If weight is not specified, it defaults to 1. The following is the example for input graph of tasks with weights. weight: gtk2 30 weight: glib2 20 gtk2 firefox weight: firefox 200 glib2 gtk2 weight: qt4 200 weight: kcachegrind 2 qt4 kcachegrind qt4 djview4 tiff djview4 png djview4 weight: twm 1 weight: gqview 4 =item B<-y> If applied, the magic string is used as an end-of-task marker instead of empty line. It is unlikely that this line appears on I's output. This option has higher priority than PAEXEC_EOT environment variable. =item B<-0> Change paexec to expect NUL character as a line separator instead of newline. This is expected to be used in concert with the -print0 function in find(1). =item B<-J> I Execute I for each I, replacing one or more occurrences of I with the entire I. Only 2-character I is allowed. Tale a note that such replacement works only if shell variable expansion is allowed in appropriate part of command (if B<-c> is applied) or if free argument is exactly a I (if B<-C> is applied). This option implies -x. =back =head1 EXAMPLES =over 6 =item 1 paexec -t '/usr/bin/ssh -x' -n 'host1 host2 host3' \ -le -g -c calculate-me < tasks.txt | paexec_reorder -Mf -Sl =item 2 ls -1 *.wav | paexec -x -n +4 -c 'oggenc -Q' =item 3 ls -1 *.wav | paexec -xCil -n+4 flac -f --silent =item 4 { uname -s; uname -r; uname -m; } | paexec -x -lp -n+2 -c banner | paexec_reorder -l =item 5 find . -name '*.dat' -print0 | paexec -0 -n+10 -C -J// scp // remoteserver:/remote/path =item 6 ls -1 *.txt | paexec -n+10 -J%% -c 'awk "BEGIN {print toupper(\"%%\")}"' =back For more examples see paexec.pdf and examples/ subdirectory in the distribution. =head1 NOTES select(2) system call and non-blocking read(2) are used to read result lines from I. At the moment blocking write(2) is used to send I to the I. This may slow down an entire processing if I are too big. So, it is recommended to use shorter I, for example, filename or URI (several tens of bytes in size) instead of multi-megabyte content. Though this may be fixed in the future. Original paexec tarball contains a number of sample of use in presentation/paexec.pdf file. After installation you can find this file under share/doc/paexec/paexec.pdf or nearby. =head1 ENVIRONMENT =over 6 =item I Overrides the compile time I size for internal buffers used to store tasks and the result lines. Versions of B prior to 0.9.0 used this value as a I buffer size. Now internal buffers are resized automatically. If unsure, do not set PAEXEC_BUFSIZE variable. See the default value in Makefile. =item I A list of variables passed to I. =item I This variable sets the end-of-task marker which is an empty line by default. Also, through this variable an end-of-task marker is passed to all Is. =item I Unless option B<-n> was applied, this variables specifies the nodes. =item I Unless option B<-t> was applied, this variables specifies the transport. =back =head1 BUGS/FEEDBACK Please send any comments, questions, bug reports etc. to me by e-mail or (even better) register them at sourceforge project home. Feature requests are also welcomed. =head1 HOME L =head1 SEE ALSO L L L L L paexec-1.1.1/paexec/nodes.h0000644000175000017500000000235213431606350015422 0ustar cheusovcheusov/* * Copyright (c) 2007-2011 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ extern char **nodes; extern int nodes_count; void nodes_create (const char *nodes_str); void nodes_destroy (void); paexec-1.1.1/paexec/tasks.h0000644000175000017500000000410113431606350015431 0ustar cheusovcheusov/* * Copyright (c) 2007-2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _TASKS_H_ #define _TASKS_H_ /* The following variables are read-only, do set them directly! */ /* a number of tasks */ extern int tasks_count; /* true "paexec -s" */ extern int graph_mode; /* last read task and its id */ extern char *current_task; extern int current_taskid; /* a number of tasks to be done */ extern int remained_tasks_count; /* a number of tasks with FATAL failure (e.g. connection lost) */ extern int failed_taskids_count; void tasks__init (void); int tasks__add_task (char *s, int weight); void tasks__add_task_arc (int task_from, int task_to); void tasks__check_for_cycles (void); void tasks__delete_task (int task, int print_task, int with_prefix); void tasks__delete_task_rec (int task); void tasks__destroy (void); const char *tasks__get_new_task (void); void tasks__mark_task_as_failed (int taskid); void tasks__make_sum_weights (void); void tasks__make_max_weights (void); void tasks__print_sum_weights (void); #endif // _TASKS_H_ paexec-1.1.1/paexec/paexec_reorder0000755000175000017500000001315113431606350017055 0ustar cheusovcheusov#!/usr/bin/env runawk # Copyright (c) 2009-2013 Aleksey Cheusov # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #env "LC_ALL=C" #use "alt_assert.awk" #use "init_getopt.awk" #use "tmpfile.awk" #use "xsystem.awk" ############################################################ #.begin-str help # paexec_reorder - takes output of 'paexec -le' or 'paexec -gle' on # input and outputs ordered results, that is without "slicing". # usage: paexec_reorder [OPTIONS] # OPTIONS: # -h display this help # -g expects output of "paexec -gle", # by default -- "paexec -le". # -S remove leading space # -l prepand output line with the task number # given on input # -x synonym for -y # -y output of "paexec -le [g] -y" is expected on input # =M method of resorting result line, where method is # m in-memory sort (the default) # s use sort(1) command # f use multiple temporary files # =m s= set alternative string for 'success', 'failure', # f= 'fatal' and '' (end of task). # F= # t= # # In -g -Mm and -g -Mf modes, portions of the result followed # by "fatal" marker are automatically cut off. #.end-str ############################################################ BEGIN { method = "m" msg_success = "success" msg_failure = "failure" msg_fatal = "fatal" msg_eot = ENVIRON ["PAEXEC_EOT"] while (getopt(short_opts)){ if (optopt == "h"){ print_help() exitnow(0) }else if (optopt == "g"){ graph_mode = 1 }else if (optopt == "S"){ remove_spc = 1 }else if (optopt == "l"){ output_task = 1 }else if (optopt == "M"){ method = optarg }else if (optopt == "m"){ if (optarg ~ /^s=/){ msg_success = substr(optarg, 3) }else if (optarg ~ /^f=/){ msg_failure = substr(optarg, 3) }else if (optarg ~ /^F=/){ msg_fatal = substr(optarg, 3) }else if (optarg ~ /^t=/){ msg_eot = substr(optarg, 3) }else{ abort("bad argument for -m") } }else if (optopt == "y" || optopt == "x"){ msg_eot = "HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5" }else{ abort() } } bad_input_msg = "bad input, did you run paexec -sle?" # -Ms if (output_task) sort_cmd = "sort -k2n -k1n -t ' ' | cut -f 2- -d ' '" else sort_cmd = "sort -k2n -k1n -t ' ' | cut -f 3- -d ' '" } # -Mm function print_results (task, cnt,i){ if (graph_mode && !(task in pline)) return if (!graph_mode || pline [task] == msg_success || ppline [task] == msg_failure){ cnt = count [task] for (i=1; i <= cnt; ++i){ if (output_task) printf "%s ", task print line [task, i] delete line [task, i] } count [task] = 0 }else if (pline [task] == msg_fatal){ count [task] = 0 }else{ abort(bad_input_msg) } } # common code { assert(NF > 0 && $0 ~ /^[0-9]+ /, bad_input_msg) if (task > task_max) task_max = task } # -Ms method == "s" { if (! (match($0, /^[0-9]+ /) && substr($0, RSTART+RLENGTH) == msg_eot)){ if (remove_spc){ num = $1 sub(/^[0-9]+ ?/, "", $0) print NR, num, $0 | sort_cmd }else{ print NR, $0 | sort_cmd } } next } # -Mf function print_results_file (task, cmd,fn){ if (task in count){ fn = runawk_tmpdir "/" task xclose(fn) cmd = sprintf("cat '%s' && rm '%s'", fn, fn) xsystem(cmd) delete count [task] } } method == "f" { if (match($0, /^[0-9]+ /) && substr($0, RSTART+RLENGTH) == msg_eot){ if (!graph_mode || pline [$1] != msg_fatal){ print_results_file(task) }else{ fn = runawk_tmpdir "/" task xclose(fn) xsystem("rm '" fn "'") delete count [task] } }else{ if (graph_mode){ ppline [$1] = pline [$1] pline [$1] = $2 } task = $1 count [task] = 1 if (remove_spc) sub(/^[0-9]+ ?/, "") else sub(/^[0-9]+ /, "") fn = runawk_tmpdir "/" task if (output_task) print task, $0 > fn else print $0 > fn } next } # -Mm match($0, /^[0-9]+ /) && substr($0, RSTART+RLENGTH) == msg_eot { print_results($1) next } { if (graph_mode){ ppline [$1] = pline [$1] pline [$1] = $2 } task = $1 sub(/^[0-9]+ /, "", $0) cnt = ++count [task] if (remove_spc) sub(/^ /, "", $0) line [task, cnt] = $0 } END { # output of "paexec -l" (without -e) is also allowed, obviously # this requires more memory for reordering results, so applying # option -e is strongly recomended. if (method == "m"){ # -Mm for (i=1; i <= task_max; ++i){ print_results(i) } }else if (method == "f"){ # -Mf for (i=1; i <= task_max; ++i){ print_results_file(i) } } } paexec-1.1.1/paexec/shquote.c0000644000175000017500000000343013431606350015773 0ustar cheusovcheusov/* * Copyright (c) 2012 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include /* * Idea comes from NetBSD but implementations are not equal. * * http://netbsd.gw.com/cgi-bin/man-cgi?shquote+3+NetBSD-current * */ size_t shquote(const char *arg, char *buf, size_t bufsize); size_t shquote(const char *arg, char *buf, size_t bufsize) { int i; size_t len = 2; for (i=0; arg [i]; ++i){ ++len; if (arg [i] == '\'') len += 3; } if (!buf) return len; if (bufsize < len+1) return (size_t) -1; *buf++ = '\''; for (i=0; arg [i]; ++i){ if (arg [i] == '\''){ *buf++ = '\''; *buf++ = '\\'; *buf++ = '\''; *buf++ = '\''; }else{ *buf++ = arg [i]; } } *buf++ = '\''; *buf++ = '\0'; return len; } paexec-1.1.1/paexec/wrappers.h0000644000175000017500000000400213431606350016147 0ustar cheusovcheusov/* * Copyright (c) 2007-2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _WRAPPERS_H_ #define _WRAPPERS_H_ #if HAVE_HEADER_SYS_SELECT_H #include #endif #include /* On ancient HP-UX select(2) is declared here */ #include #include #include void nonblock (int fd); void xsigprocmask (int how, const sigset_t *set, sigset_t *oset); void xsigaddset (sigset_t *set, int signo); ssize_t xgetdelim(char **lineptr, size_t *n, int delimiter, FILE *stream); char *xstrdup (const char *s); void *xmalloc (size_t size); void *xcalloc(size_t number, size_t size); void *xrealloc(void *ptr, size_t size); void xfree (void *p); void xshquote(const char *arg, char *buf, size_t bufsize); void err_fatal (const char *m); void err_fatal_errno (const char *m); void err_internal (const char *routine, const char *m); void kill_childs (void); /* paexec.c */ void wait_for_childs (void); /* paexec.c */ #endif /* _WRAPPERS_H_ */ paexec-1.1.1/paexec/decls.h0000644000175000017500000000260013431606350015400 0ustar cheusovcheusov/* * Copyright (c) 2014 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef _DECLS_H_ #define _DECLS_H_ #include #include #include #include #ifndef HAVE_FUNC3_SHQUOTE size_t shquote (const char *arg, char *buf, size_t bufsize); #endif extern char eol_char; #endif // _DECLS_H_ paexec-1.1.1/paexec/paexec_reorder.10000644000175000017500000001555513431606354017227 0ustar cheusovcheusov.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "paexec_reorder 1" .TH paexec_reorder 1 "2019-02-15" "" "" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" paexec_reorder \- reorder sliced output of "paexec \-l" .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBpaexec_reorder\fR [\fI\s-1OPTIONS\s0\fR] [\fIfiles...\fR] .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBpaexec\fR with \-l option produces a sliced output where results of different tasks are intermixed. The intent of \fBpaexec_reorder\fR is to produce ordered output where results for all tasks follow each other without intermixing. It is strongly recomended to send output of "\fBpaexec\fR \fI\-le\fR\*(L" or \*(R"\fBpaexec\fR \fI\-gle\fR" to the input of \fBpaexec_reorder\fR. Otherwise more memory or disk space for temporary files will be required. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-h\fR" 6 .IX Item "-h" Display help information. .IP "\fB\-M\fR \fImethod\fR" 6 .IX Item "-M method" If \fImethod\fR is \fIm\fR, result is reordered in memory, this is the default. If it is \fIf\fR, temporary files are used for reordering. If \fIs\fR, \fB\f(BIsort\fB\|(1)\fR command is used. .IP "\fB\-l\fR" 6 .IX Item "-l" Prepand output lines with the task number. .IP "\fB\-g\fR" 6 .IX Item "-g" By default output of "\fBpaexec\fR \fI\-le\fR" is expected on input. With \fI\-g\fR option, output of "\fBpaexec\fR \fI\-gle\fR" is expected. In this case \fBpaexec_reorder\fR will react on \*(L"fatal\*(R" \fBpaexec's\fR keyword. .IP "\fB\-x\fR" 6 .IX Item "-x" If applied, output of "\fBpaexec\fR \-le [\-g] \fI\-x\fR" is expected on input. This option has higher priority than \s-1PAEXEC_EOT\s0 environment variable. Actually \fB\-x\fR and \fB\-y\fR are synonyms. .IP "\fB\-y\fR" 6 .IX Item "-y" If applied, output of "\fBpaexec\fR \-le [\-g] \fI\-y\fR" is expected on input. This option has higher priority than \s-1PAEXEC_EOT\s0 environment variable. .IP "\fB\-S\fR" 6 .IX Item "-S" Remove leading space character. .IP "\fB\-m\fR s=\fIsuccess\fR" 6 .IX Item "-m s=success" .PD 0 .IP "\fB\-m\fR f=\fIfailure\fR" 6 .IX Item "-m f=failure" .IP "\fB\-m\fR F=\fIfatal\fR" 6 .IX Item "-m F=fatal" .IP "\fB\-m\fR t=\fIeot\fR" 6 .IX Item "-m t=eot" .PD Set alternative string for 'success', 'failure', 'fatal' and '' (end of task). .SH "EXAMPLES" .IX Header "EXAMPLES" .Vb 2 \& paexec \-t \*(Aq/usr/bin/ssh \-x\*(Aq \-n \*(Aqhost1 host2 host3\*(Aq \e \& \-l \-c ~/bin/complex_task | paexec_reorder \& \& paexec \-gEI \-lr \-n \*(Aqhost1 host2 host3\*(Aq \e \& \-c command \-t /usr/bin/rsh < tasks.txt | paexec_reorder \-lgS \-Mf \& \& For other examples, see examples/ directory .Ve .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" .IP "\fI\s-1TMPDIR\s0\fR" 6 .IX Item "TMPDIR" \&\fI\fItempnam\fI\|(3)\fR is used for creating temporary directory. See the appropriate man page. .IP "\fI\s-1PAEXEC_EOT\s0\fR" 6 .IX Item "PAEXEC_EOT" The same as in \fBpaexec\fR. .SH "BUGS/FEEDBACK" .IX Header "BUGS/FEEDBACK" Please send any comments, questions, bug reports etc. to me by e\-mail or (even better) register them at sourceforge project home. Feature requests are also welcomed. .SH "HOME" .IX Header "HOME" .SH "SEE ALSO \fIpaexec\fP\|(1) \fItempnam\fP\|(3)" .IX Header "SEE ALSO paexec tempnam" paexec-1.1.1/paexec/tasks.c0000644000175000017500000002523313431606350015435 0ustar cheusovcheusov/* * Copyright (c) 2007-2014 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H /* if you need, add extra includes to config.h */ #include "config.h" #endif #include #include #include #include #include "decls.h" #include "tasks.h" #include "wrappers.h" extern char msg_delim; /* from paexec.c */ static int *deleted_tasks = NULL; struct task_entry { SLIST_ENTRY (task_entry) entries; /* List. */ int task_id; }; static SLIST_HEAD (task_head, task_entry) *arcs_outg = NULL, *arcs_inco = NULL; static int arcs_count = 0; static int *tasks_graph_deg = NULL; int tasks_count = 1; /* 0 - special meaning, not task ID */ int remained_tasks_count = 0; typedef struct task_struct { RB_ENTRY(task_struct) linkage; char *task; int task_id; } task_t; static int tasks_cmp (task_t *a, task_t *b) { return strcmp (a->task, b->task); } static RB_HEAD (tasks_entries, task_struct) tasks = RB_INITIALIZER(&tasks); RB_PROTOTYPE (tasks_entries, task_struct, linkage, tasks_cmp) RB_GENERATE (tasks_entries, task_struct, linkage, tasks_cmp) int graph_mode = 0; /* numeric task id to textual representation*/ static char ** id2task = NULL; /* numeric task id to weight */ static int *id2weight = NULL; static int *id2sum_weight = NULL; char *current_task = NULL; size_t current_task_sz = 0; int current_taskid = 0; static int *failed_taskids = NULL; int failed_taskids_count = 0; void tasks__init (void) { } void tasks__destroy (void) { task_t *data, *next; data = (task_t *) RB_MIN (tasks_entries, &tasks); while (data){ next = (task_t *) RB_NEXT (tasks_entries, &tasks, data); RB_REMOVE (tasks_entries, &tasks, data); free (data->task); free (data); data = next; } if (deleted_tasks) xfree (deleted_tasks); if (id2weight) xfree (id2weight); if (id2sum_weight) xfree (id2sum_weight); } void tasks__delete_task (int task, int print_task, int with_prefix) { struct task_entry *p; int to; assert (task < tasks_count); assert (task >= 0); if (!graph_mode){ if (id2task [task]){ xfree (id2task [task]); id2task [task] = NULL; } } if (graph_mode){ SLIST_FOREACH (p, &arcs_outg [task], entries){ to = p->task_id; if (tasks_graph_deg [to] > 0) --tasks_graph_deg [to]; } if (tasks_graph_deg [task] >= -1){ tasks_graph_deg [task] = -2; --remained_tasks_count; } } if (print_task){ if (!deleted_tasks [task]){ if (with_prefix) printf ("%c", msg_delim); printf ("%s", id2task [task]); deleted_tasks [task] = 1; } } } static void delete_task_rec2 (int task, int with_prefix) { struct task_entry *p; int to; assert (task >= 0); tasks__delete_task (task, 1, with_prefix); SLIST_FOREACH (p, &arcs_outg [task], entries){ to = p->task_id; delete_task_rec2 (to, 1); } } void tasks__delete_task_rec (int task) { memset (deleted_tasks, 0, tasks_count * sizeof (*deleted_tasks)); delete_task_rec2 (task, 0); } static int get_new_task_num_from_graph (void) { int i; int best_weight = 0; int best_task = -1; for (i=1; i < tasks_count; ++i){ assert (tasks_graph_deg [i] >= -2); if (tasks_graph_deg [i] == 0){ if (id2sum_weight [i] > best_weight){ best_weight = id2sum_weight [i]; best_task = i; } } } return best_task; } static const char * get_new_task_from_graph (void) { /* topological sort of task graph */ int num = get_new_task_num_from_graph (); if (num == -1) return NULL; current_taskid = num; tasks_graph_deg [num] = -1; return id2task [num]; } static const char * get_new_task_from_stdin (void) { static char *task = NULL; static size_t task_sz = 0; ssize_t sz = 0; sz = xgetdelim(&task, &task_sz, eol_char, stdin); if (sz == -1) return NULL; if (sz > 0 && task [sz-1] == '\n') task [sz-1] = 0; current_taskid = tasks_count++; id2task = (char **) xrealloc ( id2task, tasks_count * sizeof (*id2task)); id2task [current_taskid] = xstrdup(task); return task; } const char *tasks__get_new_task (void) { const char *task = NULL; size_t task_len = 0; if (failed_taskids_count > 0){ current_taskid = failed_taskids [--failed_taskids_count]; assert (current_taskid < tasks_count); task = id2task [current_taskid]; assert (task); }else if (graph_mode){ task = get_new_task_from_graph (); }else{ task = get_new_task_from_stdin (); } if (!task) return NULL; task_len = strlen (task); if (task_len >= current_task_sz){ current_task_sz = task_len+1; current_task = (char *) xrealloc (current_task, current_task_sz); } memcpy (current_task, task, task_len+1); return current_task; } int tasks__add_task (char *s, int weight) { task_t *n = malloc (sizeof (*n)); task_t *data; int task_id; n->task = s; data = RB_INSERT (tasks_entries, &tasks, n); if (data){ task_id = data->task_id; if (id2weight [task_id] < weight){ id2weight [task_id] = weight; id2sum_weight [task_id] = weight; } free (s); free (n); return task_id; }else{ n->task_id = tasks_count; ++tasks_count; ++remained_tasks_count; arcs_outg = (struct task_head *) xrealloc ( arcs_outg, tasks_count * sizeof (*arcs_outg)); SLIST_INIT(&arcs_outg [tasks_count-1]); arcs_inco = (struct task_head *) xrealloc ( arcs_inco, tasks_count * sizeof (*arcs_inco)); SLIST_INIT(&arcs_inco [tasks_count-1]); id2task = (char **) xrealloc ( id2task, tasks_count * sizeof (*id2task)); id2task [tasks_count-1] = s; id2weight = (int *) xrealloc ( id2weight, tasks_count * sizeof (*id2weight)); id2weight [tasks_count-1] = weight; id2sum_weight = (int *) xrealloc ( id2sum_weight, tasks_count * sizeof (*id2sum_weight)); id2sum_weight [tasks_count-1] = weight; deleted_tasks = (int *) xrealloc ( deleted_tasks, tasks_count * sizeof (*deleted_tasks)); deleted_tasks [tasks_count-1] = -1; tasks_graph_deg = (int *) xrealloc ( tasks_graph_deg, tasks_count * sizeof (*tasks_graph_deg)); tasks_graph_deg [tasks_count-1] = 0; return tasks_count-1; } } void tasks__add_task_arc (int task_from, int task_to) { struct task_entry *p1,*p2; ++arcs_count; p1 = xmalloc (sizeof (*p1)); memset (p1, 0, sizeof (*p1)); p1->task_id = task_to; SLIST_INSERT_HEAD (&arcs_outg [task_from], p1, entries); p2 = xmalloc (sizeof (*p2)); memset (p2, 0, sizeof (*p2)); p2->task_id = task_from; SLIST_INSERT_HEAD (&arcs_inco [task_to], p2, entries); ++tasks_graph_deg [task_to]; } void tasks__mark_task_as_failed (int id) { failed_taskids = (int *) xrealloc ( failed_taskids, (failed_taskids_count+1) * sizeof (*failed_taskids)); failed_taskids [failed_taskids_count++] = id; } static int *check_cycles__stack; static int *check_cycles__mark; static void check_cycles__outgoing (int stack_sz) { struct task_entry *p; int j; int s, t; int loop; int to; int from = check_cycles__stack [stack_sz-1]; assert (stack_sz > 0); assert (check_cycles__mark [from] == 0); check_cycles__mark [from] = 2; /* currently in the path */ SLIST_FOREACH (p, &arcs_outg [from], entries){ to = p->task_id; assert (stack_sz < tasks_count); check_cycles__stack [stack_sz] = to; switch (check_cycles__mark [to]){ case 2: loop = 0; fprintf (stderr, "Cyclic dependancy detected:\n"); for (j=1; j <= stack_sz; ++j){ s = check_cycles__stack [j-1]; t = check_cycles__stack [j]; if (!loop && s != to) continue; loop = 1; fprintf (stderr, " %s -> %s\n", id2task [s], id2task [t]); } exit (1); case 0: check_cycles__outgoing (stack_sz + 1); break; case 1: break; default: abort (); /* this should not happen */ } } check_cycles__mark [from] = 1; /* already seen */ } void tasks__check_for_cycles (void) { int i; check_cycles__stack = xmalloc ( tasks_count * sizeof (check_cycles__stack [0])); check_cycles__mark = xmalloc ( tasks_count * sizeof (check_cycles__mark [0])); memset (check_cycles__mark, 0, tasks_count * sizeof (check_cycles__mark [0])); /* */ for (i=1; i < tasks_count; ++i){ switch (check_cycles__mark [i]){ case 0: check_cycles__stack [0] = i; check_cycles__outgoing (1); break; case 1: break; case 2: abort (); /* this should not happen */ } } xfree (check_cycles__mark); xfree (check_cycles__stack); } static char *seen = NULL; static void tasks__make_sum_weights_rec (int *accu_w, int task) { struct task_entry *p; int to; seen [task] = 1; SLIST_FOREACH (p, &arcs_outg [task], entries){ to = p->task_id; if (seen [to]) continue; tasks__make_sum_weights_rec (accu_w, to); *accu_w += id2weight [to]; seen [to] = 1; } } void tasks__make_sum_weights (void) { int i; if (!graph_mode) return; seen = (char *) xmalloc (tasks_count); for (i=1; i < tasks_count; ++i){ memset (seen, 0, tasks_count); tasks__make_sum_weights_rec (&id2sum_weight [i], i); } xfree (seen); } static void tasks__make_max_weights_rec (int *accu_w, int task) { struct task_entry *p; int to; int curr_w; seen [task] = 1; SLIST_FOREACH (p, &arcs_outg [task], entries){ to = p->task_id; if (seen [to]) continue; tasks__make_max_weights_rec (accu_w, to); curr_w = id2weight [to]; if (*accu_w < curr_w) *accu_w = curr_w; seen [to] = 1; } } void tasks__make_max_weights (void) { int i; if (!graph_mode) return; seen = (char *) xmalloc (tasks_count); for (i=1; i < tasks_count; ++i){ memset (seen, 0, tasks_count); tasks__make_max_weights_rec (&id2sum_weight [i], i); } xfree (seen); } void tasks__print_sum_weights (void) { int i; if (!graph_mode) return; for (i=1; i < tasks_count; ++i){ fprintf (stderr, "weight [%s]=%d\n", id2task [i], id2weight [i]); fprintf (stderr, "sum_weight [%s]=%d\n", id2task [i], id2sum_weight [i]); } } paexec-1.1.1/paexec/paexec.10000644000175000017500000004716513431606354015507 0ustar cheusovcheusov.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "paexec 1" .TH paexec 1 "2019-02-15" "" "" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" paexec \- parallel executor, distribute tasks over network or CPUs .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBpaexec\fR \fI[options]\fR .PP \&\fBpaexec\fR \-C \fI[options]\fR \fIcommand\fR \fI[args...]\fR .SH "DESCRIPTION" .IX Header "DESCRIPTION" Suppose you have a long list of tasks that need to be done, for example, you want to convert thousands of .wav audio files to .ogg format. Also suppose that multiple CPUs are available, e.g. multi-CPU system or a cluster consisting of individual computers connected to the network or internet. \fBpaexec\fR can efficiently do this work, that is, \fBpaexec\fR efficiently distributes different tasks to different processors (or computers), receives the results of processing from them and sends these results to stdout. .PP There are several notions that should be defined: \fItask\fR, \fIcommand\fR, \&\fItransport\fR, \fInode\fR. .PP \&\fITasks\fR are read by \fBpaexec\fR from stdin and are represented as one line of text, i.e. one input line \- one task. .PP \&\fInode\fR identifier \- remote computer or \s-1CPU\s0 identifier, for example \s-1CPU\s0 ordinal number or computer's \s-1DNS\s0 name like node12.cluster.company.com. .PP \&\fICommand\fR \- user's program that reads one-line task from stdin and sends multiline result to stdout ending with an end of task (\s-1EOT\s0) marker. \&\s-1EOT\s0 marker means \&\*(L"Task is done. I am ready for the next one\*(R". After sending \s-1EOT\s0 to stdout, stdout \s-1MUST\s0 be flushed. Remember that \s-1EOT\s0 marker \&\s-1MUST NOT\s0 appears in general result. Otherwise, \fBpaexec\fR may hang due to deadlock. The default \s-1EOT\s0 is an empty line. Command may use environment variable \s-1PAEXEC_EOT\s0 for the end-of-task marker. .PP \&\fITransport\fR \- special program that helps to run \fIcommand\fR on \&\fInode\fR. It takes the \fInode\fR identifier as its first argument and \fIcommand\fR with its arguments as the rest. Good examples for transport are \fIssh\fR and \fIrsh\fR. Both \fItransport\fR and \fIcommand\fR may be specified with their arguments, e.g, '/usr/bin/ssh \-x' is allowed as a \fItransport\fR program. .PP How \fBpaexec\fR works. \&\fICommands\fR are run on each \fInode\fR with a help of \&\fItransport\fR program. Then, \fItasks\fR are read from stdin one-by-one and sent to free \fInode\fR (exactly one task per node at a time). At the same time result lines are read from \fIcommand's\fR stdout and are output to \fBpaexec's\fR stdout. When \s-1EOT\s0 marker is obtained from the \fInode\fR, it is marked as free and becomes ready for the next task. These steps repeat until the end of stdin is reached and all \&\fInodes\fR finish their job. .PP More formally (to better understand how paexec works): .PP .Vb 10 \& run_command_on_each_node \& mark_all_nodes_as_free \& while not(end_of_stdin) or not(all_nodes_are_free) \& while there_is_free_node/i and not(end_of_stdin) \& task = read_task_from_stdin \& send_task_to_node(task, i) \& mark_node_as_busy(i) \& end \& while result_line_from_node_is_available/i \& result = read_result_line_from_node(i) \& send_line_to_stdout(result) \& if is_EOT(result) \& mark_node_as_free(i) \& end \& end \& end \& close_command_on_each_node .Ve .PP Note that \fIcommand\fRs are run once per node, it is not restarted for every task. .PP Also note that output contains result lines (obtained from different \&\fInodes\fR) in the mixed order. That is, the first line of the output may contain a result line obtain from the first \fInode\fR, the second line of output \- from the second \fInode\fR, but the third output line may contain result line from the first \fInode\fR again. It is also not guaranteed that the first line of output will be from the first \fInode\fR or from the first \fItask\fR. All result lines are output as soon as they are read by \fBpaexec\fR, i.e as soon as they are ready. \fBpaexec\fR works this way for the efficiency reasons. You can play with \fI\-l\fR, \fI\-r\fR and \fI\-p\fR options to see what happens. For reordering output line you can use \fBpaexec_reorder\fR utility. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-h\fR" 6 .IX Item "-h" Display help information. .IP "\fB\-V\fR" 6 .IX Item "-V" Display version information. .IP "\fB\-c\fR \fIcommand\fR" 6 .IX Item "-c command" Command with its arguments. .IP "\fB\-C\fR" 6 .IX Item "-C" Command and its arguments are specified by free arguments. .IP "\fB\-t\fR \fItransport\fR" 6 .IX Item "-t transport" Transport program. .IP "\fB\-n\fR \fI+number\fR" 6 .IX Item "-n +number" A number of commands to run in parallel. .IP "\fB\-n\fR \fInodes\fR" 6 .IX Item "-n nodes" List of nodes separated by space character. The first character must be alphanumeric, `_' or `/'. All other characters are reserved for future extensions. .IP "\fB\-n\fR \fI:filename\fR" 6 .IX Item "-n :filename" Filename containing list of nodes, one per line. .IP "\fB\-x\fR" 6 .IX Item "-x" Run command specificed by \fI\-c\fR for each task. Its stdout is sent to \fBpaexec\fR. If both \f(CW\*(C`\-x\*(C'\fR and \f(CW\*(C`\-g\*(C'\fR are specified, task is considered failed if command's exit status is non-zero. .IP "\fB\-X\fR" 6 .IX Item "-X" Implies \fI\-x\fR and ignore command's stdout. .IP "\fB\-r\fR" 6 .IX Item "-r" Include node identifier or node number (0\-based) to the output, i.e. id/number of node that produces this particular output line. This identifier or number appears before line number if \&\fI\-l\fR is also applied. Space character is used as a separator. .IP "\fB\-l\fR" 6 .IX Item "-l" Include a 0\-based task number (input line number) to the output, i.e. line number from which this particular output line was produced. It appears before pid if \fI\-p\fR is also applied. Space character is used as a separator. .IP "\fB\-p\fR" 6 .IX Item "-p" Include pid of paexec's subprocess that communicates with \&\fInode+command\fR to the output. Pid prepends the actual result line. Space character is used as a separator. .IP "\fB\-e\fR" 6 .IX Item "-e" When end-of-task marker is obtained from node, \s-1EOT\s0 marker is output to stdout. This option may be useful together with \fI\-l\fR and/or \fI\-r\fR. .IP "\fB\-E\fR" 6 .IX Item "-E" Imply \fB\-e\fR and flushes stdout. .IP "\fB\-d\fR" 6 .IX Item "-d" Turn on a debugging mode (for debugging purposes only) .IP "\fB\-i\fR" 6 .IX Item "-i" Copy input lines (i.e. tasks) to stdout. .IP "\fB\-I\fR" 6 .IX Item "-I" Imply \fB\-i\fR and flushes stdout. .IP "\fB\-s\fR|\fB\-g\fR" 6 .IX Item "-s|-g" Orgraph of tasks (partially ordered set) is read from stdin. .Sp Instead of autonomous tasks, graph of the tasks is read from stdin. In this mode every task can either \s-1FAIL\s0 or \s-1SUCCEED.\s0 As always an empty line output by \fIcommand\fR means \fIend of task\fR. The line before it shows an \s-1EXIT STATUS\s0 of the task. The word \*(L"failure\*(R" means failure, \*(L"success\*(R" \- success and \&\*(L"fatal\*(R" means that the current task is reassigned to another node (and restarted, of course) (see option \-z). See examples/1_div_x/cmd for the sample. An input line (paexec's stdin) should contain either single task without spaces inside or two tasks separated by single space character, e.g. task1<\s-1SPC\s0>task2. task1<\s-1SPC\s0>task2 line means that task1 must be done before task2 and it is mandatory, that is if task1 \fIfail\fR all dependent tasks (including task2) are also failed recursively. Tasks having dependencies are started only after all dependencies are succeeded. When a task succeeds paexec outputs \*(L"success\*(R" word just before end_of_task marker (see \-e or \-E), otherwise \*(L"failure\*(R" word is output followed by a list of tasks failed because of it. .Sp .Vb 1 \& Samples: \& \& tasks (examples/make_package/tasks file) \& \& textproc/dictem \& devel/autoconf wip/libmaa \& devel/gmake wip/libmaa \& wip/libmaa wip/dict\-server \& wip/libmaa wip/dict\-client \& devel/m4 wip/dict\-server \& devel/byacc wip/dict\-server \& devel/byacc wip/dict\-client \& devel/flex wip/dict\-server \& devel/flex wip/dict\-client \& devel/glib2 \& devel/libjudy \& \& command (examples/make_package/cmd_\|_flex) \& \& #!/usr/bin/awk \-f \& { \& print $0 \& if ($0 == "devel/flex") \& print "failure" \& else \& print "success" \& \& print "" # end of task marker \& fflush() \& } \& \& output of "paexec \-s \-l \-c cmd_\|_flex \-n +10 \e \& < tasks" \& \& 3 devel/autoconf \& 3 success \& 4 devel/gmake \& 4 success \& 7 devel/m4 \& 7 success \& 8 devel/byacc \& 8 success \& 9 devel/flex \& 9 failure \& 9 devel/flex wip/dict\-server wip/dict\-client \& 10 devel/glib2 \& 10 success \& 11 devel/libjudy \& 11 success \& 1 textproc/dictem \& 1 success \& 2 wip/libmaa \& 2 success .Ve .IP "\fB\-z\fR" 6 .IX Item "-z" If applied, read/\fIwrite\fR\|(2) operations from/to nodes becomes not critical. In case paexec has lost connection to the node, it will reassign failed task to another node and, if \-s applied, will output \&\*(L"fatal\*(R" string to stdout (\*(L"success\*(R" + \*(L"failure\*(R" + \*(L"fatal\*(R"). This makes paexec resistant to the I/O errors, as a result you can create paexec clusters even over network consisting of unreliable hosts (Internet?). Failed hosts are marked as such and will not be used during the current run of paexec. .IP "\fB\-Z\fR \fItimeout\fR" 6 .IX Item "-Z timeout" When \fI\-z\fR applied, if a \fIcommand\fR fails, appropriate node is marked as broken and is excluded from the following task distribution. But if \&\fB\-Z\fR applied, every \fItimeout\fR seconds an attempt to rerun a comand on a failed node is made. \fI\-Z\fR implies \fI\-z\fR. This option makes possible to organize clusters over unreliable networks/hardware. .IP "\fB\-w\fR" 6 .IX Item "-w" If \fI\-Z\fR option were applied, \fBpaexec\fR exits with error if \fB\s-1ALL\s0\fR nodes failed. With \fB\-w\fR it will not exit and will wait for restoring nodes. .IP "\fB\-m\fR s=\fIsuccess\fR" 6 .IX Item "-m s=success" Set an alternative string for 'success' message. .IP "\fB\-m\fR f=\fIfailure\fR" 6 .IX Item "-m f=failure" Set an alternative string for 'failure' message. .IP "\fB\-m\fR F=\fIfatal\fR" 6 .IX Item "-m F=fatal" Set an alternative string for 'fatal' message. An empty string for 'fatal' means it will not be output to stdout in case of fatal error. .IP "\fB\-m\fR t=\fIeot\fR" 6 .IX Item "-m t=eot" Set an alternative string for \s-1EOT\s0 message. .IP "\fB\-m\fR d=\fIdelimiter\fR" 6 .IX Item "-m d=delimiter" Set an alternative string for tasks delimiter (for \fI\-g\fR mode). Delimiter should be at most one character. No delimiter means an entire input line is treated as a task. .IP "\fB\-m\fR w=\fIweight\fR" 6 .IX Item "-m w=weight" Set an alternative string for \*(L"weight:\*(R" message. .IP "\fB\-W\fR \fInum\fR" 6 .IX Item "-W num" When multiple machines or CPUs are used for tasks processing, it makes sense to start \*(L"heavier\*(R" tasks as soon as possible in order to minimize total calculatiion time. If \fB\-W\fR is specified, special weight is assigned to each tasks which is used for reordering tasks. If \fInum\fR is 0, weights themselves are used for reordering tasks. The bigger weight is, the more priority of the task is. If \fInum\fR is 1, the total weight of task is a sum of its own weight (specified on input) and weights of all tasks depending on it directly or indirectly. If \fInum\fR is 2, the total weight of task is a maximum value of task's own weight and weights of all tasks depending on it directly or indirectly. Weights are specified with a help of \*(L"weight:\*(R" keyword (unless \fI\-m w=\fR was specified). If weight is not specified, it defaults to 1. The following is the example for input graph of tasks with weights. .Sp .Vb 10 \& weight: gtk2 30 \& weight: glib2 20 \& gtk2 firefox \& weight: firefox 200 \& glib2 gtk2 \& weight: qt4 200 \& weight: kcachegrind 2 \& qt4 kcachegrind \& qt4 djview4 \& tiff djview4 \& png djview4 \& weight: twm 1 \& weight: gqview 4 .Ve .IP "\fB\-y\fR" 6 .IX Item "-y" If applied, the magic string is used as an end-of-task marker instead of empty line. It is unlikely that this line appears on \fIcommand\fR's output. This option has higher priority than \s-1PAEXEC_EOT\s0 environment variable. .IP "\fB\-0\fR" 6 .IX Item "-0" Change paexec to expect \s-1NUL\s0 character as a line separator instead of newline. This is expected to be used in concert with the \-print0 function in \fIfind\fR\|(1). .IP "\fB\-J\fR \fIreplstr\fR" 6 .IX Item "-J replstr" Execute \fIcommand\fR for each \fItask\fR, replacing one or more occurrences of \fIreplstr\fR with the entire \fItask\fR. Only 2\-character \fIreplstr\fR is allowed. Tale a note that such replacement works only if shell variable expansion is allowed in appropriate part of command (if \fB\-c\fR is applied) or if free argument is exactly a \fIreplstr\fR (if \fB\-C\fR is applied). This option implies \-x. .SH "EXAMPLES" .IX Header "EXAMPLES" .IP "1." 6 .Vb 3 \& paexec \-t \*(Aq/usr/bin/ssh \-x\*(Aq \-n \*(Aqhost1 host2 host3\*(Aq \e \& \-le \-g \-c calculate\-me < tasks.txt | \& paexec_reorder \-Mf \-Sl .Ve .IP "2." 6 .Vb 1 \& ls \-1 *.wav | paexec \-x \-n +4 \-c \*(Aqoggenc \-Q\*(Aq .Ve .IP "3." 6 .Vb 1 \& ls \-1 *.wav | paexec \-xCil \-n+4 flac \-f \-\-silent .Ve .IP "4." 6 .Vb 3 \& { uname \-s; uname \-r; uname \-m; } | \& paexec \-x \-lp \-n+2 \-c banner | \& paexec_reorder \-l .Ve .IP "5." 6 .Vb 2 \& find . \-name \*(Aq*.dat\*(Aq \-print0 | \& paexec \-0 \-n+10 \-C \-J// scp // remoteserver:/remote/path .Ve .IP "6." 6 .Vb 1 \& ls \-1 *.txt | paexec \-n+10 \-J%% \-c \*(Aqawk "BEGIN {print toupper(\e"%%\e")}"\*(Aq .Ve .PP For more examples see paexec.pdf and examples/ subdirectory in the distribution. .SH "NOTES" .IX Header "NOTES" \&\fIselect\fR\|(2) system call and non-blocking \fIread\fR\|(2) are used to read result lines from \fInodes\fR. .PP At the moment blocking \fIwrite\fR\|(2) is used to send \fItask\fR to the \&\fInode\fR. This may slow down an entire processing if \fItasks\fR are too big. So, it is recommended to use shorter \fItasks\fR, for example, filename or \s-1URI\s0 (several tens of bytes in size) instead of multi-megabyte content. Though this may be fixed in the future. .PP Original paexec tarball contains a number of sample of use in presentation/paexec.pdf file. After installation you can find this file under share/doc/paexec/paexec.pdf or nearby. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" .IP "\fI\s-1PAEXEC_BUFSIZE\s0\fR" 6 .IX Item "PAEXEC_BUFSIZE" Overrides the compile time \fIinitial\fR size for internal buffers used to store tasks and the result lines. Versions of \fBpaexec\fR prior to 0.9.0 used this value as a \fImaximum\fR buffer size. Now internal buffers are resized automatically. If unsure, do not set \s-1PAEXEC_BUFSIZE\s0 variable. See the default value in Makefile. .IP "\fI\s-1PAEXEC_ENV\s0\fR" 6 .IX Item "PAEXEC_ENV" A list of variables passed to \fIcommand\fR. .IP "\fI\s-1PAEXEC_EOT\s0\fR" 6 .IX Item "PAEXEC_EOT" This variable sets the end-of-task marker which is an empty line by default. Also, through this variable an end-of-task marker is passed to all \fIcommand\fRs. .IP "\fI\s-1PAEXEC_NODES\s0\fR" 6 .IX Item "PAEXEC_NODES" Unless option \fB\-n\fR was applied, this variables specifies the nodes. .IP "\fI\s-1PAEXEC_TRANSPORT\s0\fR" 6 .IX Item "PAEXEC_TRANSPORT" Unless option \fB\-t\fR was applied, this variables specifies the transport. .SH "BUGS/FEEDBACK" .IX Header "BUGS/FEEDBACK" Please send any comments, questions, bug reports etc. to me by e\-mail or (even better) register them at sourceforge project home. Feature requests are also welcomed. .SH "HOME" .IX Header "HOME" .SH "SEE ALSO \fIssh\fP\|(1) \fIrsh\fP\|(1) \fIselect\fP\|(2) \fIread\fP\|(2) \fIwrite\fP\|(2)" .IX Header "SEE ALSO ssh rsh select read write" paexec-1.1.1/paexec/signals.c0000644000175000017500000000443013431606350015744 0ustar cheusovcheusov/* * Copyright (c) 2007-2011 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include "signals.h" #include "common.h" #include "wrappers.h" void block_signals (void) { sigset_t set; sigemptyset (&set); xsigaddset (&set, SIGALRM); xsigaddset (&set, SIGCHLD); xsigprocmask (SIG_BLOCK, &set, NULL); } void unblock_signals (void) { sigset_t set; sigemptyset (&set); xsigaddset (&set, SIGALRM); xsigaddset (&set, SIGCHLD); xsigprocmask (SIG_UNBLOCK, &set, NULL); } void set_sig_handler (int sig, void (*handler) (int)) { struct sigaction sa; sa.sa_handler = handler; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (sig, &sa, NULL); } void ignore_sigpipe (void) { set_sig_handler (SIGPIPE, SIG_IGN); } void wait_for_sigalrm (void) { sigset_t set; sigemptyset (&set); sigsuspend (&set); } void handler_sigchld (int dummy attr_unused) { int status; pid_t pid; while (pid = waitpid(-1, &status, WNOHANG), pid > 0){ } } void set_sigalrm_handler (void) { set_sig_handler (SIGALRM, handler_sigalrm); } void set_sigchld_handler (void) { set_sig_handler (SIGCHLD, handler_sigchld); } int sigalrm_tics = 0; void handler_sigalrm (int dummy attr_unused) { ++sigalrm_tics; alarm (1); } paexec-1.1.1/paexec/pr.h0000644000175000017500000000303213431606350014727 0ustar cheusovcheusov/* * Copyright (c) 1996, 2002 Rickard E. Faith (faith@dict.org) * Copyright (c) 2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #define PR_USE_STDIN 0x00000001 #define PR_USE_STDOUT 0x00000002 #define PR_USE_STDERR 0x00000004 #define PR_CREATE_STDIN 0x00000010 #define PR_CREATE_STDOUT 0x00000020 #define PR_CREATE_STDERR 0x00000040 #define PR_STDERR_TO_STDOUT 0x00000100 int pr_open (const char *command, int flags, int *infd, int *outfd, int *errfd); paexec-1.1.1/paexec/wrappers.c0000644000175000017500000000655113431606350016155 0ustar cheusovcheusov/* * Copyright (c) 2007-2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include "decls.h" #include "wrappers.h" #include "common.h" void nonblock (int fd) { int ret = fcntl (fd, F_GETFL, 0); if (ret == -1){ perror ("fcntl failed(2)"); exit (1); } ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK); if (ret == -1){ perror ("fcntl failed(2)"); exit (1); } } void xsigaddset (sigset_t *set, int signo) { if (sigaddset (set, signo)){ perror ("sigaddset(2) failed"); exit (1); } } void xsigprocmask (int how, const sigset_t *set, sigset_t *oset) { if (sigprocmask (how, set, oset)){ perror ("sigprocmask(2) failed"); exit (1); } } ssize_t xgetdelim(char **lineptr, size_t *n, int delimiter, FILE *stream) { ssize_t ret = getdelim(lineptr, n, delimiter, stream); if (ret == (ssize_t) -1 && ferror (stdin)){ perror ("getdelim(3) failed"); exit (1); } return ret; } char *xstrdup (const char *s) { char *ret = strdup (s); if (!ret){ perror ("strdup(3) failed"); exit (1); } return ret; } void *xmalloc (size_t size) { void *ret = malloc (size); if (!ret){ perror ("malloc(3) failed"); exit (1); } return ret; } void *xcalloc(size_t number, size_t size) { void *ret = calloc (number, size); if (!ret){ perror ("calloc(3) failed"); exit (1); } return ret; } void *xrealloc(void *ptr, size_t size) { void *ret = realloc (ptr, size); if (!ret){ perror ("realloc(3) failed"); exit (1); } return ret; } void xfree (void *p) { if (p) free (p); } void xshquote(const char *arg, char *buf, size_t bufsize) { size_t ret = shquote (arg, buf, bufsize); if ((size_t)-1 == ret){ err_fatal ("paexec: shquote(3) failed"); exit (1); } } void err_fatal (const char *m) { kill_childs (); wait_for_childs (); fflush (stdout); fprintf (stderr, "%s\n", m); exit (1); } void err_fatal_errno (const char *m) { kill_childs (); wait_for_childs (); fflush (stdout); fprintf (stderr, "%s: %s\n", m, strerror (errno)); exit (1); } void err_internal (const char *routine, const char *m) { kill_childs (); wait_for_childs (); fflush (stdout); if (routine) fprintf (stderr, "%s (%s)\n", m, routine); else fprintf (stderr, "%s\n", m); exit (1); } paexec-1.1.1/paexec/signals.h0000644000175000017500000000270013431606350015747 0ustar cheusovcheusov/* * Copyright (c) 2007-2011 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ extern int sigalrm_tics; void block_signals (void); void unblock_signals (void); void set_sig_handler (int sig, void (*handler) (int)); void ignore_sigpipe (void); void wait_for_sigalrm (void); void handler_sigchld (int dummy); void set_sigalrm_handler (void); void set_sigchld_handler (void); void handler_sigalrm (int dummy); paexec-1.1.1/paexec/nodes.c0000644000175000017500000000664013431606350015421 0ustar cheusovcheusov/* * Copyright (c) 2007-2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "nodes.h" #include "wrappers.h" #include #include #include #include #include char **nodes = NULL; int nodes_count = 0; static void nodes_create__count (const char *nodes_str) { int i; nodes_count = (int) strtol (nodes_str, NULL, 10); if (nodes_count == (int) LONG_MAX) err_fatal_errno ("paexec: invalid option -n:"); nodes = xmalloc (nodes_count * sizeof (nodes [0])); for (i=0; i < nodes_count; ++i){ char num [50]; snprintf (num, sizeof (num), "%d", i); nodes [i] = xstrdup (num); } } static void nodes_create__list (char *nodes_str) { char *last = NULL; char *p = nodes_str; char c; /* "node1 nodes2 ..." format */ for (;;){ c = *p; switch (c){ case ' ': case '\t': case '\r': case '\n': case 0: if (last){ *p = 0; ++nodes_count; nodes = xrealloc ( nodes, nodes_count * sizeof (*nodes)); nodes [nodes_count - 1] = xstrdup (last); last = NULL; } break; default: if (!last){ last = p; } break; } if (!c) break; ++p; } } static void nodes_create__file (const char *nodes_str) { char node [4096]; FILE *fd = fopen (nodes_str, "r"); size_t len = 0; if (!fd) err_fatal_errno ("paexec: Cannot obtain a list of nodes"); while (fgets (node, sizeof (node), fd)){ len = strlen (node); if (len > 0 && node [len-1] == '\n') node [len-1] = 0; ++nodes_count; nodes = xrealloc ( nodes, nodes_count * sizeof (*nodes)); nodes [nodes_count - 1] = xstrdup (node); } fclose (fd); } void nodes_create (const char *nodes_str) { unsigned char c0 = nodes_str [0]; char *nodes_copy; if (c0 == '+'){ /* "+NUM" format */ nodes_create__count (nodes_str + 1); }else if (c0 == ':'){ /* "+NUM" format */ nodes_create__file (nodes_str + 1); }else if (isalnum (c0) || c0 == '/' || c0 == '_'){ /* list of nodes */ nodes_copy = xstrdup (nodes_str); nodes_create__list (nodes_copy); xfree (nodes_copy); }else{ err_fatal ("paexec: invalid argument for option -n"); } /* final check */ if (nodes_count == 0) err_fatal ("paexec: invalid argument for option -n"); } void nodes_destroy (void) { int i; if (nodes){ for (i=0; i < nodes_count; ++i){ if (nodes [i]) xfree (nodes [i]); } xfree (nodes); } } paexec-1.1.1/paexec/paexec.c0000644000175000017500000007011513431606350015554 0ustar cheusovcheusov/* * Copyright (c) 2007-2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifdef HAVE_CONFIG_H /* if you need, add extra includes to config.h */ #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include /***********************************************************/ #include "decls.h" #include "wrappers.h" #include "common.h" #include "tasks.h" #include "nodes.h" #include "signals.h" #include "pr.h" #ifndef BUFSIZE #define BUFSIZE 2048 #endif #ifndef PAEXEC_VERSION #define PAEXEC_VERSION "x.y.z" #endif static void usage (void) { fprintf (stderr, "\ paexec -- parallel executor\n\ that distributes tasks over CPUs or machines in a network.\n\ usage: paexec [OPTIONS]\n\ paexec -C [OPTIONS] cmd [args...]\n\ OPTIONS:\n\ -h give this help\n\ -V show version\n\ \n\ -n <+num> number of subprocesses to run\n\ -n list of nodes separated by space character\n\ -n <:filename> filename containing a list of nodes, one node per line\n\ -c set a command\n\ -C use free arguments as a command and its arguments\n\ -t set a transport program\n\ \n\ -x run command once per task\n\ -X implies -x and ignore calculator's stdout.\n\ -y magic line is used as an end-of-task marker\n\ -0 change paexec to expect NUL character as\n\ a line separator instead of newline\n\ \n\ -r include a node (or a number) to the output\n\ -l include 0-based task number to the output\n\ -p include a pid of subprocess to the output\n\ \n\ -e print an empty line when end-of-task is reached\n\ -E implies -e and flushes stdout\n\ \n\ -i copy input lines (i.e. tasks) to stdout\n\ -I implies -i and flushes stdout\n\ \n\ -s|-g graph of tasks is given on stdin, by default a list of\n\ independent tasks is read from stdin\n\ \n\ -d debug mode, for debugging only\n\ \n\ -z failed nodes are marked as dead\n\ -Z timeout to restart faild command, imply -z\n\ -w wait for restoring nodes (needs -Z)\n\ \n\ -W heavier tasks are processed first, a weight\n\ of task is a sum of its own weight and weights\n\ of all tasks that depend on it,\n\ directly or indirectly\n\ \n\ -m s= set an alternative for 'success' message\n\ f= set an alternative for 'failure' message\n\ F= set an alternative for 'fatal' message\n\ t= set an alternative for EOT marker\n\ d= set the delimiter for -g mode.\n\ The default is space character.\n\ w= set an alternative for 'weight:' marker\n\ \n\ -J replstr\n\ execute command for each task, replacing\n\ one or more occurrences of replstr with the entire task.\n\ \n\ -n and -c are mandatory options\n\ \n\ "); } static const char magic_eot [] = "HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5"; /* arguments */ static char *arg_nodes = NULL; static char *arg_cmd = NULL; static char *arg_transport = NULL; /**/ static int *fd_in = NULL; static int *fd_out = NULL; static char **buf_out = NULL; static size_t *bufsize_out = NULL; static size_t *size_out = NULL; static int *busy = NULL; static int busy_count = 0; static pid_t *pids = NULL; static int *node2taskid = NULL; typedef enum { rt_undef = -1, rt_success = 0, rt_failure = 1, } ret_code_t; static ret_code_t *ret_codes = NULL; static int max_fd = 0; static char *buf_stdin = NULL; static int alive_nodes_count = 0; static int show_pid = 0; static int show_taskid = 0; static int show_node = 0; static int print_eot = 0; static int flush_eot = 0; static int print_i2o = 0; static int flush_i2o = 0; static int initial_bufsize = BUFSIZE; static int debug = 0; static char **node2task = NULL; static size_t *node2task_buf_sz = NULL; static int end_of_stdin = 0; static const char *msg_success = "success"; static const char *msg_failure = "failure"; static const char *msg_fatal = "fatal"; static const char *msg_weight = "weight:"; static const char *msg_eot = NULL; char msg_delim = ' '; /* also used in tasks.c */ static int resistant = 0; static int resistance_timeout = 0; static int resistance_last_restart = 0; static int wait_mode = 0; static int exec_mode = 0; static int use_weights = 0; char eol_char = '\n'; static char replstr[2] = ""; struct envvar_entry { SLIST_ENTRY(envvar_entry) entries; /* List. */ char* name; char* value; }; static SLIST_HEAD(envvar_head, envvar_entry) envvars = SLIST_HEAD_INITIALIZER(envvars); static void add_envvar (const char *name, const char *value) { struct envvar_entry *val = calloc(1, sizeof (struct envvar_entry)); val->name = strdup (name); val->value = (value ? strdup (value) : NULL); SLIST_INSERT_HEAD(&envvars, val, entries); } static void assign_str (char **ptr, const char *str) { size_t len = strlen (str); *ptr = xrealloc (*ptr, len+1); memcpy (*ptr, str, len+1); } static void close_all_ins (void) { int i; for (i=0; i < nodes_count; ++i){ if (!busy [i] && fd_in [i] != -1){ close (fd_in [i]); fd_in [i] = -1; } } } static void bad_input_line (const char *line) { char buf [4000]; snprintf (buf, sizeof (buf), "Bad input line: %s\n", line); err_fatal (buf); } static void init__read_graph_tasks (void) { char *buf = NULL; size_t buf_sz = 0; ssize_t len = 0; int id1, id2; char *tok1, *tok2, *tok3, *tok; int tok_cnt; char *p; char buf_copy [2000]; /* */ if (debug){ fprintf (stderr, "start: init__read_graph_tasks\n"); } /* */ if (!graph_mode){ /* completely independent tasks */ return; } /* reading all tasks with their dependancies */ while (len = xgetdelim(&buf, &buf_sz, eol_char, stdin), len != -1){ if (len > 0 && buf [len-1] == '\n'){ buf [len-1] = 0; --len; } strncpy (buf_copy, buf, sizeof (buf_copy)); tok1 = tok2 = tok3 = tok = NULL; tok_cnt = 0; for (p=buf; 1; ++p){ char ch = *p; if (ch == msg_delim){ *p = 0; } if (!tok) tok = p; if (*p == 0){ if (!tok1){ tok1 = tok; tok_cnt = 1; }else if (!tok2){ tok2 = tok; tok_cnt = 2; }else if (!tok3){ tok3 = tok; tok_cnt = 3; }else{ bad_input_line (buf_copy); } tok = NULL; } if (!ch) break; } if (tok_cnt == 3 && !strcmp (tok1, msg_weight)){ /* weight: */ id2 = tasks__add_task (xstrdup (tok2), atoi (tok3)); continue; } if (tok_cnt == 2){ /* */ id1 = tasks__add_task (xstrdup (tok1), 1); id2 = tasks__add_task (xstrdup (tok2), 1); tasks__add_task_arc (id1, id2); continue; } if (tok_cnt == 1){ /* */ id1 = tasks__add_task (xstrdup (tok1), 1); continue; } bad_input_line (buf_copy); } if (buf) free (buf); /* */ if (debug){ fprintf (stderr, "end: init__read_graph_tasks\n"); } } static char const runner_function1[] = "run() { %s \"$1\"; }"; static char const runner_function2[] = "run() { %s; }"; static char* generate_run_command(void) { static char run_command [4096]; char *repl_ptr = NULL; if (replstr[0]){ repl_ptr = arg_cmd; while (repl_ptr = strstr(repl_ptr, replstr), repl_ptr != NULL){ repl_ptr[0] = '$'; repl_ptr[1] = '1'; repl_ptr += 2; } snprintf(run_command, sizeof(run_command), runner_function2, arg_cmd); }else{ snprintf(run_command, sizeof(run_command), runner_function1, arg_cmd); } if (strlen(run_command) + 1 == sizeof(run_command)){ err_fatal ("paexec: Internal error6! (buffer size)"); } // fprintf(stderr, "run_command: %s\n", run_command); return run_command; } static void init__postproc_arg_cmd (void) { char shq_cmd [4096]; char cmd [4096]; char tmp [4096]; char env_str [4096]=""; char tmp2 [4096]=""; struct envvar_entry *p; if (exec_mode){ char cond_cmd [4096] = ""; if (exec_mode == 'x'){ strlcpy(tmp, " printf '%s\\n' \"$res\";", sizeof (tmp)); } if (graph_mode){ snprintf ( cond_cmd, sizeof (cond_cmd), "if test $ex = 0; then echo '%s'; else echo '%s'; fi;", msg_success, msg_failure); } if (snprintf (cmd, sizeof (cmd), "%s\n while read f; do" " res=`run \"$f\"`;" " ex=$?;" " %s" /* printing result */ " %s" /* condition. success/failure */ " echo '%s';" /* EOT */ "done", generate_run_command(), tmp, cond_cmd, magic_eot) >= sizeof (cmd)){ err_fatal ("paexec: Internal error7! (buffer size)"); } xfree (arg_cmd); arg_cmd = xstrdup (cmd); } xshquote (arg_cmd, shq_cmd, sizeof (shq_cmd)); /* env(1) arg for environment variables */ add_envvar("PAEXEC_EOT", msg_eot); SLIST_FOREACH (p, &envvars, entries){ xshquote ((p->value ? p->value : ""), tmp, sizeof (tmp)); if (snprintf (tmp2, sizeof (tmp2), "%s=%s ", p->name, tmp) >= sizeof (tmp2)){ err_fatal ("paexec: Internal error! (buffer size)"); } strlcat (env_str, tmp2, sizeof (env_str)); } /**/ if (snprintf (cmd, sizeof (cmd), "env %s /bin/sh -c %s", env_str, shq_cmd) >= sizeof (cmd)){ err_fatal ("paexec: Internal error! (buffer size)"); } xfree (arg_cmd); arg_cmd = xstrdup (cmd); /**/ if (arg_transport){ /* one more shquote(3) for ssh-like transport */ xshquote (arg_cmd, shq_cmd, sizeof (shq_cmd)); xfree (arg_cmd); arg_cmd = xstrdup (shq_cmd); } if (strlen (cmd) + 20 >= sizeof (shq_cmd)){ err_fatal ("paexec: internal error, buffer size limit"); } } static void init__child_processes (void) { char full_cmd [2000]; int i; /* */ if (debug){ fprintf (stderr, "start: init__child_processes\n"); } /* */ for (i=0; i < nodes_count; ++i){ if (pids [i] != (pid_t) -1) continue; if (!buf_out [i]){ /* +1 for \0 and -d option */ buf_out [i] = xmalloc (initial_bufsize+1); } if (!bufsize_out [i]) bufsize_out [i] = initial_bufsize; size_out [i] = 0; busy [i] = 0; ret_codes [i] = rt_undef; if (arg_transport) snprintf (full_cmd, sizeof (full_cmd), "%s %s %s", arg_transport, nodes [i], arg_cmd); else snprintf (full_cmd, sizeof (full_cmd), "%s", arg_cmd); if (debug){ fprintf (stderr, "running cmd: %s\n", full_cmd); } pids [i] = pr_open ( full_cmd, PR_CREATE_STDIN | PR_CREATE_STDOUT, &fd_in [i], &fd_out [i], NULL); ++alive_nodes_count; nonblock (fd_out [i]); if (fd_in [i] > max_fd){ max_fd = fd_in [i]; } if (fd_out [i] > max_fd){ max_fd = fd_out [i]; } } /* */ if (debug){ fprintf (stderr, "end: init__child_processes\n"); } } static void mark_node_as_dead (int node) { if (debug){ fprintf (stderr, "mark_node_as_dead (%d)\n", node); } if (busy [node]){ busy [node] = 0; --busy_count; tasks__mark_task_as_failed (node2taskid [node]); --alive_nodes_count; } if (fd_in [node] >= 0) close (fd_in [node]); if (fd_out [node] >= 0) close (fd_out [node]); fd_in [node] = -1; fd_out [node] = -1; unblock_signals (); waitpid (pids [node], NULL, WNOHANG); block_signals (); pids [node] = (pid_t) -1; } static void init (void) { /* arrays */ pids = xmalloc (nodes_count * sizeof (*pids)); memset (pids,-1, nodes_count * sizeof (*pids)); fd_in = xmalloc (nodes_count * sizeof (*fd_in)); memset (fd_in, -1, nodes_count * sizeof (*fd_in)); fd_out = xmalloc (nodes_count * sizeof (*fd_out)); memset (fd_out, -1, nodes_count * sizeof (*fd_out)); node2task = xmalloc (nodes_count * sizeof (*node2task)); node2task_buf_sz = xmalloc (nodes_count * sizeof (*node2task_buf_sz)); memset (node2task, 0, nodes_count * sizeof (*node2task)); memset (node2task_buf_sz, 0, nodes_count * sizeof (*node2task_buf_sz)); buf_out = xmalloc (nodes_count * sizeof (*buf_out)); memset (buf_out, 0, nodes_count * sizeof (*buf_out)); bufsize_out = xmalloc (nodes_count * sizeof (*bufsize_out)); memset (bufsize_out, 0, nodes_count * sizeof (*bufsize_out)); size_out = xmalloc (nodes_count * sizeof (*size_out)); memset (size_out, 0, nodes_count * sizeof (*size_out)); busy = xmalloc (nodes_count * sizeof (*busy)); memset (busy, 0, nodes_count * sizeof (*busy)); node2taskid = xmalloc (nodes_count * sizeof (*node2taskid)); ret_codes = xmalloc (nodes_count * sizeof (*ret_codes)); /* stdin */ buf_stdin = xmalloc (initial_bufsize); buf_stdin [0] = 0; /* tasks */ tasks__init (); /**/ init__read_graph_tasks (); /**/ tasks__check_for_cycles (); /**/ switch (use_weights){ case 1: tasks__make_sum_weights (); break; case 2: tasks__make_max_weights (); break; } if (debug) tasks__print_sum_weights (); /* */ init__postproc_arg_cmd (); /* in/out */ init__child_processes (); /* signal handlers */ set_sigchld_handler (); set_sigalrm_handler (); /* alarm(2) */ if (resistance_timeout) alarm (1); /* ignore SIGPIPE signal */ ignore_sigpipe (); } void kill_childs (void) { int i; if (!pids) return; for (i=0; i < nodes_count; ++i){ if (pids [i] != (pid_t) -1){ kill (pids [i], SIGTERM); } } } void wait_for_childs (void) { int i; if (!pids) return; if (debug) printf ("wait for childs\n"); for (i=0; i < nodes_count; ++i){ if (pids [i] != (pid_t) -1){ mark_node_as_dead (i); } } } static int find_free_node (void) { int i; for (i=0; i < nodes_count; ++i){ if (pids [i] != (pid_t) -1 && !busy [i]) return i; } err_internal (__func__, "there is no free node"); return -1; } static void print_header (int num) { if (show_node){ if (nodes && nodes [num]) printf ("%s ", nodes [num]); else printf ("%d ", num); } if (show_taskid){ printf ("%d ", node2taskid [num]); } if (show_pid){ printf ("%ld ", (long) pids [num]); } } static void print_line (int num, const char *line) { print_header (num); printf ("%s\n", line); } static void print_EOT (int num) { if (print_eot){ print_line (num, msg_eot); if (flush_eot) fflush (stdout); } } static void send_to_node (void) { int n = find_free_node (); size_t task_len = strlen (current_task); assert (n >= 0); if (debug){ printf ("send to %d (pid: %ld)\n", n, (long) pids [n]); } busy [n] = 1; size_out [n] = 0; node2taskid [n] = current_taskid; ++busy_count; if (task_len >= node2task_buf_sz [n]){ node2task_buf_sz [n] = task_len + 1; node2task [n] = xrealloc (node2task [n], node2task_buf_sz [n]); } memcpy (node2task [n], current_task, task_len + 1); if (print_i2o){ print_line (n, current_task); if (flush_i2o){ fflush (stdout); } } if (-1 == write (fd_in [n], current_task, task_len) || -1 == write (fd_in [n], "\n", 1)) { if (resistant){ mark_node_as_dead (n); if (msg_fatal [0]) print_line (n, msg_fatal); print_EOT (n); if (alive_nodes_count == 0 && !wait_mode){ err_fatal ("all nodes failed"); } return; }else{ err_fatal_errno ("paexec: Sending task to the node failed:"); } } } static int unblock_select_block ( int nfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, struct timeval * timeout) { int ret; char msg [200]; unblock_signals (); do { errno = 0; ret = select (nfds, readfds, writefds, exceptfds, timeout); }while (ret == -1 && errno == EINTR); if (ret == -1){ snprintf (msg, sizeof (msg), "select(2) failed: %s", strerror (errno)); err_fatal (msg); } block_signals (); return ret; } static int try_to_reinit_failed_nodes (void) { if (resistance_timeout && sigalrm_tics - resistance_last_restart >= resistance_timeout) { resistance_last_restart = sigalrm_tics; init__child_processes (); return 1; } return 0; } static int condition ( fd_set *rset, int max_descr, int *ret, const char **task) { *ret = -777; *task = NULL; if (busy_count < alive_nodes_count && !end_of_stdin && (*task = tasks__get_new_task ()) != NULL) { return 1; } if (!task && !graph_mode && feof (stdin)){ end_of_stdin = 1; close_all_ins (); } if (busy_count > 0 && (*ret = unblock_select_block ( max_descr+1, rset, NULL, NULL, NULL)) != 0) { return 1; } if (failed_taskids_count > 0 && wait_mode){ wait_for_sigalrm (); try_to_reinit_failed_nodes (); return 1; } return 0; } static void loop (void) { char msg [2000]; fd_set rset; int printed = 0; int ret = 0; int cnt = 0; int i, j; char *buf_out_i = 0; const char *task = NULL; const char *curr_line = NULL; if (graph_mode && tasks_count == 1){ /* no tasks */ close_all_ins (); wait_for_childs (); return; } FD_ZERO (&rset); FD_CLR (0, &rset); while (condition (&rset, max_fd, &ret, &task)){ /* ret == -777 means select(2) was not called */ if (try_to_reinit_failed_nodes ()) continue; if (ret == -1 && errno == EINTR){ continue; } if (debug){ printf ("select ret=%d\n", ret); } if (ret == -777 && task) send_to_node (); /* fd_out */ for (i=0; ret != -777 && i < nodes_count; ++i){ if (fd_out [i] >= 0 && FD_ISSET (fd_out [i], &rset)){ buf_out_i = buf_out [i]; assert (bufsize_out [i] > size_out [i]); cnt = read (fd_out [i], buf_out_i + size_out [i], bufsize_out [i] - size_out [i]); if (debug && cnt >= 0){ buf_out_i [size_out [i] + cnt] = 0; printf ("cnt = %d\n", cnt); printf ("fd_out [%d] = %d\n", i, fd_out [i]); printf ("buf_out [%d] = %s\n", i, buf_out_i); printf ("size_out [%d] = %d\n", i, (int) size_out [i]); } if (cnt == -1 || cnt == 0){ /* read error or unexpected end of file */ if (resistant){ FD_CLR (fd_out [i], &rset); mark_node_as_dead (i); if (msg_fatal [0]) print_line (i, msg_fatal); print_EOT (i); if (alive_nodes_count == 0 && !wait_mode){ err_fatal ("all nodes failed"); } continue; }else{ if (cnt == 0){ snprintf ( msg, sizeof (msg), "Node %s exited unexpectedly", nodes [i]); }else{ snprintf ( msg, sizeof (msg), "reading from node %s failed: %s", nodes [i], strerror (errno)); } err_fatal (msg); } } printed = 0; cnt += size_out [i]; for (j=size_out [i]; j < cnt; ++j){ if (buf_out_i [j] == '\n'){ buf_out_i [j] = 0; curr_line = buf_out_i + printed; if (!strcmp (curr_line, msg_eot)){ /* end of task marker */ assert (busy [i] == 1); busy [i] = 0; --busy_count; if (end_of_stdin){ close (fd_in [i]); fd_in [i] = -1; } /* EOT line means end-of-task */ if (graph_mode){ switch (ret_codes [i]){ case rt_failure: print_header (i); tasks__delete_task_rec (node2taskid [i]); printf ("\n"); break; case rt_success: tasks__delete_task (node2taskid [i], 0, 0); break; case rt_undef: print_line (i, "?"); break; default: abort (); } end_of_stdin = (remained_tasks_count == 0); if (end_of_stdin) close_all_ins (); }else{ tasks__delete_task (node2taskid [i], 0, 0); } print_EOT (i); break; } if (graph_mode){ if (!strcmp (curr_line, msg_success)){ ret_codes [i] = rt_success; }else if (!strcmp (curr_line, msg_failure)){ ret_codes [i] = rt_failure; }else{ ret_codes [i] = rt_undef; } } print_line (i, curr_line); printed = j + 1; } } if (printed){ cnt -= printed; memmove (buf_out_i, buf_out_i + printed, cnt); } size_out [i] = cnt; if (size_out [i] == bufsize_out [i]){ bufsize_out [i] *= 2; /* +1 for \0 and -d option */ buf_out [i] = xrealloc (buf_out [i], bufsize_out [i]+1); } } } /* fd_out */ for (i=0; i < nodes_count; ++i){ if (fd_out [i] < 0) continue; if (busy [i]){ FD_SET (fd_out [i], &rset); }else{ FD_CLR (fd_out [i], &rset); } } if (debug){ printf ("alive_nodes_count = %d\n", alive_nodes_count); printf ("busy_count = %d\n", busy_count); printf ("end_of_stdin = %d\n", end_of_stdin); for (i=0; i < nodes_count; ++i){ printf ("busy [%d]=%d\n", i, busy [i]); printf ("pid [%d]=%d\n", i, (int) pids [i]); } } /* exit ? */ if (graph_mode) end_of_stdin = (remained_tasks_count == 0); if (!busy_count && end_of_stdin) break; } close_all_ins (); } static void check_msg (const char *msg) { if (strpbrk (msg, "'\"")){ err_fatal ("paexec: symbols ' and \" are not allowed in -m argument"); } } static char *gen_cmd (int *argc, char ***argv) { char cmd [4096]; char *curr_token; size_t len; size_t curr_len; int i; len = 0; for (i=0; i < *argc; ++i){ curr_token = (*argv) [i]; if (replstr[0] && !strcmp(curr_token, replstr)){ cmd[len+0] = '"'; cmd[len+1] = '$'; cmd[len+2] = '1'; cmd[len+3] = '"'; curr_len = 4; }else{ curr_len = shquote (curr_token, cmd+len, sizeof (cmd)-len-1); } if (curr_len == (size_t)-1){ err_fatal ("paexec: Internal error4! (buffer size)"); } len += curr_len; cmd [len++] = ' '; if (len >= sizeof (cmd)-20){ /* 20 chars is enough for "$1" :-) */ err_fatal ("paexec: Internal error5! (buffer size)"); } } cmd [len++] = 0; assert (!arg_cmd); return xstrdup (cmd); } static void process_args (int *argc, char ***argv) { int c; int mode_C = 0; /* leading + is for shitty GNU libc */ static const char optstring [] = "+0c:CdeEghiIJ:lm:n:prst:VwW:xXyzZ:"; while (c = getopt (*argc, *argv, optstring), c != EOF){ switch (c) { case 'V': printf ("paexec %s written by Aleksey Cheusov\n", PAEXEC_VERSION); exit (0); break; case 'h': usage (); exit (0); break; case 'd': debug = 1; break; case 'n': assign_str (&arg_nodes, optarg); break; case 'c': mode_C = 0; arg_cmd = xstrdup (optarg); break; case 'C': mode_C = 1; break; case 't': optarg += strspn (optarg, " \t"); if (optarg [0]) assign_str (&arg_transport, optarg); break; case 'p': show_pid = 1; break; case 'l': show_taskid = 1; break; case 'r': show_node = 1; break; case 'e': print_eot = 1; break; case 'E': print_eot = 1; flush_eot = 1; break; case 'i': print_i2o = 1; break; case 'I': print_i2o = 1; flush_i2o = 1; break; case 'J': if (strlen(optarg) != 2){ fprintf(stderr, "-Jreplstr argument must have 2-characters length"); exit(2); } replstr[0] = optarg[0]; replstr[1] = optarg[1]; if (!msg_eot) msg_eot = magic_eot; if (!exec_mode) exec_mode = 'x'; break; case 's': case 'g': graph_mode = 1; break; case 'w': wait_mode = 1; break; case 'z': resistant = 1; break; case 'Z': resistant = 1; resistance_timeout = atoi (optarg); break; case 'm': if (optarg [0] == 's' && optarg [1] == '='){ msg_success = xstrdup (optarg+2); check_msg (msg_success); }else if (optarg [0] == 'f' && optarg [1] == '='){ msg_failure = xstrdup (optarg+2); check_msg (msg_failure); }else if (optarg [0] == 'F' && optarg [1] == '='){ msg_fatal = xstrdup (optarg+2); check_msg (msg_fatal); }else if (optarg [0] == 't' && optarg [1] == '='){ msg_eot = xstrdup (optarg+2); }else if (optarg [0] == 'd' && optarg [1] == '='){ if (optarg [2] != 0 && optarg [3] != 0){ err_fatal ("paexec: bad argument for -md=. At most one character is allowed"); } msg_delim = optarg [2]; }else if (optarg [0] == 'w' && optarg [1] == '='){ msg_weight = xstrdup (optarg+2); }else{ err_fatal ("paexec: bad argument for -m"); } break; case 'W': use_weights = atoi (optarg); graph_mode = 1; break; case 'x': exec_mode = 'x'; msg_eot = magic_eot; break; case 'X': exec_mode = 'X'; msg_eot = magic_eot; break; case 'y': msg_eot = magic_eot; break; case '0': eol_char = '\0'; break; default: usage (); exit (1); } } *argv += optind; *argc -= optind; if (!msg_eot){ msg_eot = ""; } if (mode_C){ if (!*argc){ err_fatal ("paexec: missing arguments. Run paexec -h for details"); } arg_cmd = gen_cmd (argc, argv); }else{ if (*argc){ err_fatal ("paexec: extra arguments. Run paexec -h for details"); } } if (!resistance_timeout && wait_mode){ err_fatal ("paexec: -w is useless without -Z"); } if (arg_nodes){ if (arg_nodes [0] == '+'){ free (arg_transport); arg_transport = NULL; } nodes_create (arg_nodes); }else{ err_fatal ("paexec: -n option is mandatory!"); } if (!arg_cmd){ err_fatal ("paexec: -c option is mandatory!"); } if (use_weights < 0 || use_weights > 2){ err_fatal ("paexec: Only -W1 and -W2 are supported!"); } if (arg_transport && !arg_transport [0]){ free (arg_transport); arg_transport = NULL; } } static void free_memory (void) { int i; if (arg_nodes) xfree (arg_nodes); if (arg_transport) xfree (arg_transport); if (arg_cmd) xfree (arg_cmd); nodes_destroy (); if (fd_in) xfree (fd_in); if (fd_out) xfree (fd_out); if (buf_stdin) xfree (buf_stdin); if (buf_out){ for (i=0; i < nodes_count; ++i){ if (buf_out [i]) xfree (buf_out [i]); } xfree (buf_out); } if (node2task){ for (i=0; i < nodes_count; ++i){ if (node2task [i]) xfree (node2task [i]); } xfree (node2task); } if (node2task_buf_sz) xfree (node2task_buf_sz); if (size_out) xfree (size_out); if (busy) xfree (busy); if (pids) xfree (pids); if (node2taskid) xfree (node2taskid); if (ret_codes) xfree (ret_codes); tasks__destroy (); } static void init_env (void) { char *tok; char *env_msg_eot = getenv ("PAEXEC_EOT"); if (env_msg_eot) msg_eot = env_msg_eot; char *env_bufsize = getenv ("PAEXEC_BUFSIZE"); if (env_bufsize) initial_bufsize = atoi (env_bufsize); char *env_transport = getenv ("PAEXEC_TRANSPORT"); if (env_transport) assign_str (&arg_transport, env_transport); char *env_nodes = getenv ("PAEXEC_NODES"); if (env_nodes) assign_str (&arg_nodes, env_nodes); char *paexec_env = getenv ("PAEXEC_ENV"); if (paexec_env){ for (tok = strtok (paexec_env, " ,"); tok; tok = strtok (NULL, " ,")) { add_envvar (tok, getenv (tok)); } } } int main (int argc, char **argv) { int i; pid_t pid; int status; block_signals (); init_env (); process_args (&argc, &argv); if (debug){ printf ("nodes_count = %d\n", nodes_count); for (i=0; i < nodes_count; ++i){ printf ("nodes [%d]=%s\n", i, nodes [i]); } printf ("cmd = %s\n", arg_cmd); } init (); loop (); free_memory (); set_sig_handler (SIGCHLD, SIG_DFL); set_sig_handler (SIGALRM, SIG_IGN); unblock_signals (); while (pid = waitpid (-1, &status, WNOHANG), pid > 0){ } return 0; } paexec-1.1.1/paexec/pr.c0000644000175000017500000001220513431606350014724 0ustar cheusovcheusov/* The following code was derived from libmaa written by Rick Faith, relicensing was permitted by author */ /* * Copyright (c) 1996, 2002 Rickard E. Faith (faith@dict.org) * Copyright (c) 2013 Aleksey Cheusov * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include "wrappers.h" #include "pr.h" /* The idea for the max_fd call is from W. Richard Stevens; Advanced Programming in the UNIX Environment (Addison-Wesley Publishing Co., 1992); page 43. The implementation here, however, is different from that provided by Stevens for his open_max routine. */ struct _pr_Obj { int pid; }; static struct _pr_Obj *_pr_objects = NULL; static int max_fd (void) { static int maxFd = 0; if (maxFd) return maxFd; #if HAVE_FUNC1_SYSCONF && defined(_SC_OPEN_MAX) if ((maxFd = sysconf (_SC_OPEN_MAX)) > 0) return maxFd; #endif return maxFd = 1024; /* big enough number */ } static void _pr_init (void) { if (!_pr_objects) _pr_objects = xcalloc (max_fd (), sizeof (struct _pr_Obj)); } int pr_open (const char *command, int flags, int *infd, int *outfd, int *errfd) { int pid; int fdin[2]; int fdout[2]; int fderr[2]; int null; _pr_init (); if (flags & ~(PR_USE_STDIN | PR_USE_STDOUT | PR_USE_STDERR | PR_CREATE_STDIN | PR_CREATE_STDOUT | PR_CREATE_STDERR | PR_STDERR_TO_STDOUT)) err_internal (__func__, "Illegal flags passed to pr_open"); if ((flags & PR_USE_STDIN) && (flags & PR_CREATE_STDIN)) err_internal (__func__, "Cannot both use and create stdin"); if ((flags & PR_USE_STDOUT) && (flags & PR_CREATE_STDOUT)) err_internal (__func__, "Cannot both use and create stdout"); if ((flags & PR_USE_STDERR) && (flags & PR_CREATE_STDERR)) err_internal (__func__, "Cannot both use and create stderr"); if ((flags & PR_STDERR_TO_STDOUT) && ((flags & PR_USE_STDERR) || (flags & PR_CREATE_STDERR))) err_internal (__func__, "Cannot use/create stderr when duping to stdout"); if ((flags & PR_CREATE_STDIN) && pipe (fdin) < 0) err_fatal_errno ("paexec: Cannot create pipe for stdin" ); if ((flags & PR_CREATE_STDOUT) && pipe (fdout) < 0) err_fatal_errno ("paexec: Cannot create pipe for stdout" ); if ((flags & PR_CREATE_STDERR) && pipe (fderr) < 0) err_fatal_errno ("paexec: Cannot create pipe for stderr" ); if ((pid = fork ()) < 0) err_fatal_errno ("paexec: Cannot fork" ); if (pid == 0) { /* child */ int i; #define CHILD(CREATE,USE,fds,writefd,readfd,fd,FILENO,flag) \ if (flags & CREATE){ \ close (fds [writefd]); \ dup2 (fds [readfd], FILENO); \ close (fds [readfd]); \ }else if (flags & USE) { \ if (fd && *fd){ \ dup2 (*fd, FILENO); \ close (*fd); \ }else{ \ if ((null = open ("/dev/null", flag)) >= 0) { \ dup2 (null, FILENO); \ close (null); \ } \ } \ } CHILD (PR_CREATE_STDIN, PR_USE_STDIN, fdin, 1, 0, infd, STDIN_FILENO, O_RDONLY); CHILD (PR_CREATE_STDOUT, PR_USE_STDOUT, fdout, 0, 1, outfd, STDOUT_FILENO, O_WRONLY); CHILD (PR_CREATE_STDERR, PR_USE_STDERR, fderr, 0, 1, errfd, STDERR_FILENO, O_WRONLY); #undef CHILD if (flags & PR_STDERR_TO_STDOUT) dup2 (STDOUT_FILENO, STDERR_FILENO); for (i = 0; i < max_fd(); i++) if (_pr_objects [i].pid > 0) close (i); /* (void ) NULL is for Solaris where NULL is 0L */ execl ("/bin/sh", "/bin/sh", "-c", command, (void *)NULL); _exit (127); } /* parent */ #define PARENT(CREATE,USE,fds,readfd,writefd,fd,flag,name) \ if (flags & CREATE) { \ close (fds [readfd]); \ *fd = fds [writefd]; \ _pr_objects [*fd].pid = pid; \ }else if (flags & USE) { \ if (fd && *fd) { \ _pr_objects [*fd].pid =0; \ close (*fd); \ } \ } PARENT (PR_CREATE_STDIN, PR_USE_STDIN, fdin, 0, 1, infd, "w", "stdin"); PARENT (PR_CREATE_STDOUT, PR_USE_STDOUT, fdout, 1, 0, outfd, "r", "stdout"); PARENT (PR_CREATE_STDERR, PR_USE_STDERR, fderr, 1, 0, errfd, "r", "stderr"); #undef PARENT return pid; } paexec-1.1.1/paexec/Makefile0000644000175000017500000000207013431606350015576 0ustar cheusovcheusov# initial buffer size for the tasks and results BUFSIZE ?= 4096 ############################################################ BIRTHDATE = 2008-01-25 WARNS ?= 4 WARNERR ?= yes PROG = paexec SRCS = paexec.c wrappers.c tasks.c nodes.c signals.c pr.c SCRIPTS = paexec_reorder MAN = paexec.1 paexec_reorder.1 LINKS = ${BINDIR}/paexec_reorder ${BINDIR}/pareorder MLINKS = paexec_reorder.1 pareorder.1 CFLAGS += -DPAEXEC_VERSION='"${VERSION}"' CFLAGS += -DBUFSIZE=${BUFSIZE} MKC_FEATURES = strlcat strlcpy SLIST RB MKC_SOURCE_FUNCLIBS = shquote MKC_COMMON_DEFINES = -D_GNU_SOURCE MKC_COMMON_HEADERS = unistd.h stdlib.h MKC_CHECK_TYPES = intptr_t:stdint.h intptr_t:inttypes.h MKC_CHECK_HEADERS = sys/select.h MKC_CHECK_FUNCS3 = shquote MKC_CHECK_FUNCS1 = sysconf CLEANFILES = *~ core* *.1 *.html ktrace* ChangeLog *.tmp .PHONY: _prepdist _prepdist: ${MAN} ############################################################ .include CFLAGS.warns.gcc.4 += -Wno-uninitialized paexec-1.1.1/paexec/common.h0000644000175000017500000000024413431606350015600 0ustar cheusovcheusov#ifndef _COMMON_H_ #define _COMMON_H_ #if defined(__GNUC__) #define attr_unused __attribute__ ((unused)) #else #define attr_unused #endif #endif /* _COMMON_H_ */ paexec-1.1.1/checks/0000755000175000017500000000000013431606350014132 5ustar cheusovcheusovpaexec-1.1.1/checks/awk_fflush0000755000175000017500000000014013431606350016204 0ustar cheusovcheusov#!/usr/bin/env sh if echo | "$AWK" '{fflush()}' 2>/dev/null 1>&2; then echo 1 else echo 0 fi paexec-1.1.1/checks/sleep_fract0000755000175000017500000000011213431606350016341 0ustar cheusovcheusov#!/usr/bin/env sh if sleep 0.1 2>/dev/null; then echo 1 else echo 0 fi paexec-1.1.1/Makefile.inc0000644000175000017500000000110313431606350015075 0ustar cheusovcheusov# initial buffer size for the tasks and results BUFSIZE ?= 4096 # EGDIR ?= ${DATADIR}/doc/paexec/examples DOCDIR ?= ${DATADIR}/doc/paexec # Those poor souls who run Solaris can set AWK to gawk AWK ?= /usr/bin/awk MKC_REQUIRE_PROGS += ${AWK} runawk .export AWK MKC_CHECK_CUSTOM += awk_fflush MKC_CUSTOM_FN.awk_fflush = checks/awk_fflush .include "mkc.configure.mk" .if !${CUSTOM.awk_fflush:U1} MKC_ERR_MSG += "ERROR: ${AWK} doesnt not support fflush() function" .endif INTEXTS_REPLS += awk ${PROG.${AWK}:U${AWK}} INTEXTS_REPLS += version ${VERSION:U} # VERSION= 1.1.1 paexec-1.1.1/doc/0000755000175000017500000000000013431606350013437 5ustar cheusovcheusovpaexec-1.1.1/doc/INSTALL0000644000175000017500000000566013431606350014477 0ustar cheusovcheusov====================================================================== INSTALLATION 0) Maybe paexec has been already packaged for your platform. See PACKAGES section in README file and your system package management tools. 1) You need bmake (portable version of NetBSD make) for building paexec. I'd recommend to use latest stable version. http://crufty.net/help/sjg/bmake.html http://freshmeat.net/projects/bmake/ NOTE: !!! GNU make IS NOT GOOD !!! 2) We also need mk-configure >= 0.23.0. http://sourceforge.net/projects/mk-configure/ 3) "libmaa" library is also needed. It is a part of "dict" project available here: http://sourceforge.net/projects/dict/ 4) If you want to change the default build options, run mkcmake like this env [YOUR_ASSIGNMENTS] mkcmake [YOUR_ASSIGNMENTS] See example section below 5) Uncompress tarball you've downloaded like this gzip -dc paexec-X-Y-Z.tar.gz | tar -xf- 6) cd paexec-X-Y-Z 7) mkcmake 8) mkcmake test If this step fails on your system, please let me now. 9) mkcmake install 10) If you also want to install examples, run the following command mkcmake all-examples install-examples By default examples are installed to ${DATADIR}/doc/paexec/examples/. For changing it, set EGDIR environment variable. 11) If you also want to install README, NEWS, TODO etc., run the following command mkcmake all-doc install-doc By default these files are installed to ${PREFIX}/share/doc/. For changing it, set DOCDIR environment variable. 12) paexec project consists of the following subprojects: - paexec (paexec and paexec_reorder executables and appropriate manual pages) - doc (README, NEWS etc.) - examples (examples of use). By default only "paexec" is built and installed. You can build and install all "subprojects" like the following. env SUBPRJ_DFLT='paexec examples doc' mkcmake all install 13) paexec_reorder utility is written in runawk, so we need runawk>=1.4.3 at runtime. http://sourceforge.net/projects/runawk/ 14) There is a lot of Makefile variables that can be changed during build and installation. PREFIX - where paexec and paexec_reorder are installed to MANDIR - root directory for manual pages DESTDIR - fake root for installation CPPFLAGS CFLAGS LDFLAGS LDADD ... NOTE: Environment variable must be the same at build and installation time! See mk-configure(7) for details. ------------------------------ Examples of build and installation: 1) export PREFIX=/usr SYSCONFDIR=/etc MANDIR=/usr/share/man export SUBPRJ_DFLT='paexec examples doc' mkcmake all env DESTDIR=/tmp/fake-root mkcmake install 2) env CC='icc' \ PREFIX=/usr/pkg \ CPPFLAGS='-I/usr/pkg/include' \ LDFLAGS='-L/usr/pkg/lib -Wl,-rpath -Wl,/usr/pkg/lib' \ mkcmake -s all install paexec-1.1.1/doc/NEWS0000644000175000017500000004163513431606350014147 0ustar cheusovcheusov====================================================================== Version 1.1.1, by Aleksey Cheusov, Fri, 15 Feb 2019 21:58:39 +0300 Fix build using clang Verify snprintf didn't truncate the output ====================================================================== Version 1.1.0, by Aleksey Cheusov, Wed, 25 Apr 2018 23:21:24 +0300 paexec: - add new option -0. It works just like in "xargs -0". - add new option -J. - add new option -mw=. - fix help message display by -h. - -md= now allows no delimiter mode in -g mode. - -c and -C override each other if one is implied after another. Add new tool "paargs". It is a wrapper over paexec(1) that simplifies use of paexec. Fix transport_broken_rnd test script. This fixes regression test on Solaris. Update man page for paexec(1). ====================================================================== Version 1.0.1, by Aleksey Cheusov, Thu, 14 Aug 2014 01:44:39 +0300 Unflushed (broken) stdout seen on Darwin was fixes. Who knows, this may happen on other systems too. ====================================================================== Version 1.0.0, by Aleksey Cheusov, Sun, 13 Jul 2014 19:10:48 +0300 mk-configure>=0.27.0 is required for build. Option -X was introduced to paexec(1) for ignoring calculator's stdout. PAEXEC_ENV environment variable sets a list of variables passed to the calculator. PAEXEC_TRANSPORT environment variable sets the transport unless option -t was applied. PAEXEC_NODES environment variable sets the nodes unless option -n was applied. pareorder(1) is a synonym for paexec_reorder(1) ====================================================================== Version 0.19.1, by Aleksey Cheusov, Mon, 26 Aug 2013 19:05:53 +0300 paexec: Fix for segfault seen on Linux Version 0.19.0, by Aleksey Cheusov, Sun, 25 Aug 2013 17:21:03 +0300 This release of paexec was successfully tested on the following platforms: NetBSD-6.1/amd64, OpenBSD-5.3/i386, FreeBSD-8.3/i386, Solaris-10/sparc, Solaris-11/amd64 and diverse Linux/{i386,amd64}. paexec is now selfcontained, libmaa is not needed anymore. Presentation paexec.pdf was added to presentation/. I hope it will help easier understand how "paexec" works. It is installed to ${DOCDIR}. paexec: - POSIX-2008 getline(3) is used for reading lines instead of home-made function. - t '' is equivalent to "no transport", spaces are trimmed. - "-n +NNN" has higher priority than -t, i.e. if they both are specified, transport is ignored. - Fix for -W1. - Environment variable PAEXEC_EOT was introduced. - Option -y was added to paexec(1) and paexec_reorder(1). - Option -C was added to paexec(1). paexec_reorder: - Option -x was added to paexec_reorder(1). A number of fixes and improvements in regression tests. ====================================================================== Version 0.18.0, by Aleksey Cheusov, Thu, 7 Mar 2013 15:17:33 +0300 paexec: - fixed: NULL dereference when the first line given on input is empty. Thanks to Sergey Revyako for bug report! - fixed: entire command passed tp ssh-like transport should be shquoted. In particular this fixes -x that didn't work with -t. Thanks to Sergey Revyako for bug report! - 'paexec -g' accepts empty strings as tasks. - More regression tests were added paexec_reorder.1: - Mistype fix ====================================================================== Version 0.17.0, by Aleksey Cheusov, Sun, 9 Sep 2012 02:07:34 +0300 paexec: - Option -x was added. With its help paexec can run one command per task. If -g is also specified, command's exit status is analysed. Appropriate task and dependants are marked as "failed" if it is non-zero. - First character of -n argument must be alphanumeric, `+', `_', `:' or `/'. Other symbols are reserved for future extentions. - With '-n :filename' paexec reads a list of nodes from the specified file. - With a help of new option '-m t=' end of task string may be specified, which is an empty line by default. - Option -md= was added that overrides the default delimiter (space character) between tasks in graph mode (-g). - Output line that contains failed dependants no longer ends with unnecessary space. - Long options were completely removed. paexec_reorder: - Fix. "paexec_reorder -g" now handles correctly failed tasks' output. One extra line after "fatal" is expected. - Options -m was added. It does the same things as paexec's -m. More examples of use and regression tests. Documentation update, clean-ups and improvements. Regression tests: - Signals handling was fixed in. - LC_ALL is always set to C in regression tests, this fixes some problems in internationalized environment. mk-configure>=0.23.0 is required at build time ====================================================================== Version 0.16.1, by Aleksey Cheusov, Wed, 23 Mar 2011 00:14:15 +0200 paexec.1 and paexec_reorder.1 are included to paexec-0.16.1.tgz. Just like in paexec<=0.15.1 pod2man is not needed for building paexec. ====================================================================== Version 0.16, by Aleksey Cheusov, Fri, 11 Mar 2011 11:58:31 +0200 Project's structure has been reorganized. Now the top-level Makefile uses mkc.subprj.mk. This adds a lot of flexibility in building the project and development. See doc/INSTALL for updated installation instructions. New modes for reordering tasks were added: -W0 and -W2 See the manual page for details about option -W. Long options are considered deprecated. They are still supported but will be removed in the future. Please use POSIX short options. At the moment use of them produces warning message on stderr. Fix the compilation bug on old versions of OpenBSD (at least <=3.8) and probably other systems where intptr_t is declared in inttypes.h but not in stdint.h Fix for 'mkcmake test' failure on Solaris and HP-UX because their /usr/bin/awk sucks. On these platforms now it is possible to run the following command. env AWK=/full/path/to/gawk mkcmake all test ====================================================================== Version 0.15.0, by Aleksey Cheusov, Sun, 10 Oct 2010 18:06:31 +0300 After some thoughts I decided to switch from plain mk-files to mk-configure build system. It provides very cool features and makes development drammatically easier. It also makes Makefiles much cleaner and easier. Installation instructions has been updated in README file. PAEXEC reads the tasks from stdin and distributes them to all available hosts or CPU. If some tasks are easy and can be made quickly while others require much more CPU time it makes sense to reorder tasks calcultion in order to reduce total calculation time and reduce computers/CPUs idle time. For this purpose -W option is added to paexec(1) using weights assigned to each tasks. At the moment only two values are allowed for : 0 -- do not use weights at all, 1 -- run heavier tasks first as soon as possible. New tool paexec_reorder(1) for reordering sliced output of paexec(1). It is written in runawk. So, you'll need it at run time. FIXED: 1 byte buffer overflow if -d option is applied. Documentation update. Tons of new regression tests. Regression tests framework has been significantly reworked. Clean-ups. README: notes about my Debian/Lenny/x86 repository. Minor fixes (warning messages) for different compilers. ====================================================================== Version 0.14.0, by Aleksey Cheusov, Sun, 3 Jan 2010 12:38:54 +0200 fixed: "paexec -z" without -s never worked. Now it is fine. New options -g|--graph are synonyms for -s|--pos. New option -w for waiting for failed nodes if they ALL failed. By default (with -Z) if ALL nodes fail paexec exits with error. New option -m for setting alternative strings for success/failure/fatal. Target for installing directories has been renamed from install-dirs to installdirs. Other minor fixes and code clean-ups. ====================================================================== Version 0.13.0, by Aleksey Cheusov, Sat, 7 Mar 2009 19:17:03 +0200 FIXED: When 'paexec -s' retreives 10000 tasks, it allocates 10000*10000*sizeof(int) bytes for detecting cycles, i.e. ~400Mb on 32-bit system or 800Mb on 64-bit system. This is absolutely inacceptable. This bad algorithm is replaced with new one which doesn't need quadratic matrix and works much faster. ADDED: -Z option When I<-z> applied, if a I fails, appropriate node is marked as broken and is excluded from the following task distribution. But if B<-Z> applied, every I seconds an attempt to rerun a comand on a failed node is made. I<-Z> implies I<-z>. This option makes possible to organize clusters over unreliable networks/hardware. No EINTR wrappers anymore (iread, xread etc.). SIGCHLD and SIGALRM are blocked most of the time. They are unblocked before select(2) and blocked just after it. SA_RESTART is not used anymore. Minor clean-ups in Makefile. ====================================================================== Version 0.12.1, by Aleksey Cheusov, Tue, 23 Dec 2008 20:33:20 +0200 FIX: support for -z appeared in paexec-0.12.0 was actually incomplete :-/ Now everything should be fixed. More regression tests. Makefile: adapted for FreeBSD make which doesn't support .PARSEDIR ====================================================================== Version 0.12.0, by Aleksey Cheusov, Mon, 22 Dec 2008 21:48:01 +0200 ADDED: -z option. If applied, read/write(2) operations from/to nodes becomes not critical. In case paexec has lost connection to the node, it will reassign failed task to another node and, if -s option applied, will output string "fatal" to stdout. This makes paexec resistant to the I/O errors, as a result you can create paexec clusters even over network consisting of unreliable hosts (Internet?). Failed hosts are marked as such and will not be used during the current run of paexec. NOTE: "success", "failure" and "fatal" strings should be used to process the output of 'paexec -s'. select(2) do not listen stdin (fd=0) anymore. Blocking read(2) is used to read tasks from stdin. Makefile: CPPFLAGS -> CFLAGS, FreeBSD make Mk scripts don't use CPPFLAGS. ====================================================================== Version 0.11.0, by Aleksey Cheusov, Sat, 25 Oct 2008 17:49:47 +0300 paexec -s: before beginning actual work an input tasks graph is checked for cycles. If they are detected, paexec exits with error. minor fix in man page ====================================================================== Version 0.10.1, by Aleksey Cheusov, Sat, 25 Oct 2008 02:00:55 +0300 This version of paexec was sucessfully tested on the following platforms: NetBSD/x86 NetBSD/Alpha(64bit) Linux/x86 Linux/x86-64 Interix-3.5/x86 FreeBSD/x86 Solaris-10/x86 Minor fix for rhomb-like dependencies (paexec -s). Suppose A depends on (B1 and B2), (B1 and B2) depends on C. If C fails, earlier paexec versions produced the following output failure C B1 A B2 A That is, A was output twice. Now it is fixed and A is printed only once. New regression test for this. By default(!) getopt_long(3) is enabled on the following platforms (macro): __NetBSD__, __FreeBSD__, __OpenBSD__, __DragonFly__, __linux__ and __APPLE__. On others only short options provided by getopt(3) are used. This means that long option may to not work on your platform. fix in manual page: accept(2) -> select(2) code clean-ups .sinclude removed from Makefile tests/test.sh: diff -U ---> standard diff -C10 gawk appeared by mistake removed ====================================================================== Version 0.10.0, by Aleksey Cheusov, Sun, 31 Aug 2008 21:37:59 +0300 Lots of new regression tests README file: 'make test' is documented ADDED: -s option Partially ordered set of tasks are read from stdin. Instead of autonomous tasks, graph of the tasks is read from stdin. In this mode every task can either FAIL or SUCCEED. As always an empty line output by command means end of task. The line before it shows an EXIT STATUS of the task. The word "failure" means failure, "success" - success. See examples/1_div_x/1_div_X_cmd for the sample. An input line (paexec's stdin) should contain either single task without spaces inside or two tasks separated by single space character, e.g. task1task2. task1task2 line means that task1 must be done before task2 and it is mandatory, that is if task1 fail all dependent tasks (including task2) are also failed recursively. Tasks having dependencies are started only after all dependencies are succeeded. When a task succeeds paexec outputs "success" word just before end_of_task marker (see -e or -E), otherwise "failure" word is output followed by a list of tasks failed because of it. Samples: tasks (examples/make_package/make_package_tasks file) textproc/dictem devel/autoconf wip/libmaa devel/gmake wip/libmaa wip/libmaa wip/dict-server wip/libmaa wip/dict-client devel/m4 wip/dict-server devel/byacc wip/dict-server devel/byacc wip/dict-client devel/flex wip/dict-server devel/flex wip/dict-client devel/glib2 devel/libjudy command (examples/make_package/make_package_cmd__flex) #!/usr/bin/awk -f { print $0 # print a package name if ($0 == "devel/flex") print "failure" # cannot build flex ;-) else print "success" # all other packages are ok print "" # end of task marker fflush() } output of "paexec -s -l -c make_package_cmd__flex -n +10 \ < make_package_tasks" 3 devel/autoconf 3 success 4 devel/gmake 4 success 7 devel/m4 7 success 8 devel/byacc 8 success 9 devel/flex 9 failure 9 devel/flex wip/dict-server wip/dict-client 10 devel/glib2 10 success 11 devel/libjudy 11 success 1 textproc/dictem 1 success 2 wip/libmaa 2 success ====================================================================== Version 0.9.0, by Aleksey Cheusov, Sun, 15 Jun 2008 10:23:52 +0300 -t '' means "no transport". This significantly simplifies writing shell scripts with paexec. Added: tests for this case. paexec has no limited internal buffers anymore. All they are resized automatically as it is needed. PAEXEC_BUFSIZE environment variable sets an *initial* buffer size, not *maximum* one. README: note about non-standard function getopt_long, and advice how to build paexec on platforms with no getopt_long support (HP-UX, Solaris etc.). More regressions tests paexec.1: minor corrections. 'make test' fix: In case regression test fails, 'make test' exits with non-zero exit status. paexec can be built with ancient version pmake-1.45 (found in som Linux distributions). paexec -h|--help outputs messages to stderr - my new religion :-) ====================================================================== Version 0.8.0, by Aleksey Cheusov, Tue, 4 Mar 2008 00:32:56 +0200 New options implemented: -E, -i and -I See manual page for details. Fixes and minor improvements in the documentation ====================================================================== Version 0.7.0, by Aleksey Cheusov, Tue, 26 Feb 2008 23:57:15 +0200 new -e|--eot option implemented. It prints the end-of-task marker (an empty line) to stdout. See manual page. WARNS=4 to see compilation warnings. several gcc warnings fixed. fixed: '-n +0' and '-n ""' now fails with error message. minor fix in man page minor clean-ups ====================================================================== Version 0.6.0, by Aleksey Cheusov, Thu, 24 Jan 2008 21:31:26 +0200 First publicly available release ====================================================================== paexec-1.1.1/doc/TODO0000644000175000017500000000210013431606350014120 0ustar cheusovcheusovpaexec: - paexec: print exit status of task - EXIT STATUS section in man page - SIGUSR2 for graceful exit, i.e. complete currently running tasks and then exit (Thanks to Mikhailian for idea) - New option -gg (double -g) for reading graph of tasks in lower-to-upper order and running new tasks as soon as they appear on input. If tasks appears on input slowly (distbb/pkgsrc) this may significantly improve parallelism and reduce total running time - pamake -- 1) shell/whatever-based script with special section that describes hosts, dependency graph of targets and other metainfo, where functions are "targets" 2) preprocessing (m4,cpp,whatever). Maybe it make sense to see dsh/pdsh. - mimic dsh and pdsh - PAEXEC_COMMAND as a default for -c - pass PAEXEC_NODEID to appropriate nodes - -n 'server1 server2 +5' two remote servers and five local - Option -n%'node_[1-20,22-30]' - non-blocking write(2) for sending task to the slave hosts/CPUs. - SIGINFO for displaying current status of tasks - SIGUSR1 for trying restore connection to dead client hosts paexec-1.1.1/doc/LICENSE0000644000175000017500000000206613431606350014450 0ustar cheusovcheusovCopyright (c) 2007-2013 Aleksey Cheusov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. paexec-1.1.1/doc/Makefile0000644000175000017500000000012613431606350015076 0ustar cheusovcheusovFILES = LICENSE NEWS ../README TODO FILESDIR = ${DOCDIR} .include paexec-1.1.1/presentation/0000755000175000017500000000000013431606354015411 5ustar cheusovcheusovpaexec-1.1.1/presentation/paexec.pdf0000644000175000017500000032226013431606354017356 0ustar cheusovcheusov%PDF-1.4 %Çì¢ 8 0 obj <> stream xœmRMo1åì_á£-±“ù°½ö R*¤JmÄq(i ¨¤Ð6"þ<3›m³•ÐÊãY{fÞ{3¾õäѾq_mÜìœÐ¯ïùµ»õR¸Bî:î™ øNƒ©5i^jµ¬ùÂÍ'~{·»r³žÜì­™ùé‘n‹7þ…;^ø3‡VÔÑéÇmµñó¥Á²§’ ûå·çC>!`EòTš_nÜÇð3*.’ûp•M¢Ì"áJ1qN)…‡Ø%(µpyüU–6B$N…Œ¤ª{s 3ØFíB_µ ¿£Ž°%-«^®Ú¥Q¤(Öµ•jP$=¿õSªáÈJâ>œFd–Þë5PÉS)Ÿ–ïlÂIg  F¬ÏIªF£ýRgû:v9|W]Ê7)üÐ0~þhÝÄ Iá«Îvæ 0­Õd½ÉÖñʯ'dñ)nnu¨Ñb€ö~Ô¼2òˆDam¿3fÀÌÍcÜ>dkRàZþ§¯£Ú¼æ»$0¢˜<{9VŠöÚLäKki¤æbÚ†.\D=n6¿»ÝS†EKS}`ŒºH—Äl<Ž—îL¿ÌÙÏ)endstream endobj 9 0 obj 528 endobj 23 0 obj <> stream xœ­•MOÜ0†{ίðÑ®¯güûº€ÄV­íVJ|ƒÊ.>Úþ{fìàq@ jµIÖž¿ïãqöF Âðg¸­šÙ70âì¶qÖÜ0ê˜çZìt-CJ6 0:FΚ/šÙ⫸ëïOšÙž€f¶Í—ùÎÝ›âC³µ»á¢ ä%Åp;Z‰ù’—EN[P,O›¢DÔžCHãrÕü”;ÊjƒèƒìU‹ÚGtN^©Öio’ òP‘B Öwò’GÑtÁÉ5;ß\©ÖêdœýµüÜl-¦£1]LƒuÚÓ] ûè:m¢€h:Þä—V16½,!Ôª ÿ"zÑéÔ€)E[0 ð^#Œ ÕzÐ3¢ï¨©M%6Ú-hŠ>¦èmåä½jAž)O,[ë¢6àå&žHàKÀš/wa1GðÄ)'8Mˆå1Oç,ŠA~²ˆ:ÅP~_qbÈ‘×Ê‚¦FÙÓ(õ! y¤x/¼åh¾ýÏ}·£¯­O±˜x›å¥ŠMáòk¾æË g ÙÁ%‹µY|¶UuýVîÉŽçDë G1¨ƒ§çµàzH&‡à—°Îfxç•ÖC‰!Z!Ïæ¶cBQö“-É S"yK0æü¡ôšódiëIW r\aCÕѪ ¯#߃˜‹÷|R 6vQûƒ‘[ )ì+âÚoý¤#¬·Ìƒc*í’ÁPCqòÈñ ®–×Í?« N¡WQJî ’uÜËö%Ú²!䟱¬Òûç„‹©Wq¢}_Çn$ÆåY9±c—è˜X˜L>ÔŽìã·£ð±ö.÷ȾTV~¤¨9I”ßi#¹ÅL”›œÿ‰¹p;ùEñ)Ž.Mzý~Båïä9§•ØÉ=Š›äý[ƒ'ÏÃI€$ÿ(( ¢ÕøÝWüŸA¨ë ·y—°{endstream endobj 24 0 obj 711 endobj 32 0 obj <> stream xœÅXKo7îyo^5Åá›@уÓU¶y(è!ÈÁUÇhd;–”ôPô·w¸Ú%wW\Å\K) XÄ’óÍã›ýDÂü_ý»\³—ÀÈÕºrU|"BsKm57å†ÕdŠ‹Á9á µÖï:Ÿ³ù¯ds¿½,f(f?ûçÏŸâÏü'ò]ñlN^Ì+- :’Ô?Ë9_øc9I…Ôœ,Þ»û±TáaœpxÇŪxS¾šà´ÓBªòv2•T1ÇtùÑ93Z–Û Þ‘k¡L¹™à­¦¼®çmg×MXúvñKñlQà%©e¸¬6IåÎF£)¸4”áÌÿf¼:Æ„ÛW Öøq£”£<Û¨ã;}ÒßÒŠJs™Ê†Ð’P§TÐ’j¼:³ÔÈ:¯½AcΔk”2Òj(/&x!‰nS^M¦œ2Í•./ý`AëdIA娧Ù¸®`-‹(tˆÑj„Ìï”@2ÞHçjÂH§0>båtén‚Xƒñq± Ž`4²¿Ãh'³Ì–ËÉTq‡.lÊ7aú÷0ý<Èa4ß0ÈâºßÂèU˜}Ûȼà+lç¬ò0FïðÞ7“)P m[þÒ3kD(Û®ãڻ੒’bbÀs,§–ïš3â›1R«]y„«`Ç‹ [†Ñ‡0{ÝRÓÈ.ƒå×;P­5˜›éûxÞÓ>¾¸çu­Ã謙M"(Åw@p„݇4Ö)FP[êúnRnZöîÅb¬uÝÙmã>Èü!ãkâ]_5.Œð^%f/‚lõ@L%x`Æ`šÄ¦ZÚ¼ <S…çë>¨Ë¨ËDT~LÌn{³­ˆÆ¦t«³håõŒjí‰zb|þÕw§ª_A*ß¾©‚‹\À£àŽÑ#f4,«ÅŠ@›Ç[‘”p)“ª³Ç ÓKU7õÈðº2´HVê&òZËǰ1ŠkÌ8 HfMzÒeÅé꿌|`Ò ${{ ^ð=Ýô!,;eQ´ ¨º˜ Ö1}ÄœQø}Ò»_…âsMËÐþ9D£¬¦ +ZŸ±ó 5drŽeã„U8˜Ü÷‘G ºÓÖÂ\{%ÀoÒo?µ·•ƒ¬õtrr•Û+¼5íù:½¶|„2žýcSt9 šÞ…Qd{Ÿ«‘b¼µî&Œ¶½‹wFð’|l“y³UnjNæ‰z†ª3<7U †òqrΡj²öÁþ”‹ü&Ý€1qÒð=ÜåL®¢Q© ɱò¤stòªe© ýCôj掯GwþëÌhýg¯Ósv]p{X²•ŽÍòm«<ï÷i ÃÞ–ÛŽ[x}žzðѪ‡¾ŠŒî¿ò@R;õ-:jå¨9ÐPÏ‚p›h™ck= ³Ùu«Ä6VŸõ´tëó‡C˜8KG}§Ê7ä"JéoÑKEO#à ñ¿0{÷+Ç,o1P"´w½Q$8Í—+‰j]Õ{Òü­q¾¥SENÂQ¾DP3Àtv YœéEñ €aIendstream endobj 33 0 obj 1190 endobj 45 0 obj <> stream xœ½XÉnãFÍ™_Ñ“ä@a«—ê-G'âA2€9dr°=’bX’5Z²\òí©j.MKôBI1 ÅRóÕöºšåÏLpÉýÕ÷ÛE6úU 6Ûd’ͲÏL[广•Ê)É-+q± A† Á½§·.®²ÑÕOl»ÞM²Ñ&³Ñt¹øå;¼]}ϾÈ.¯ØûLh&£IVßnìbLf“À5XÅÆÓ¬òG2Ï SL‰>ŽÙoùeQ*Ò*›ÿ]”À­·(^èH£´ÎE©y |¾*Ð]eµqùœ+á,ä\ °¹$­Þ›ü[5†¨!ßxG]ÈÒﻄUÁš %Š¥œ6+¸e _G/½ø}ü#…0:d /`VKbtlü Ãú¹(%šÀ ¾ªµÈg…Aë†"r^šñ6¿£ç ­‘ñy‹–ÈM­-Âå·Ä÷–„õ']&¨Yo AÇz#¾¶Ž`q%™‹¨Š iP£g«ú¢t¶ÆG -“·ø£ÄÔF3”jUA4¶Èqz^QÉBðRy| ‰¼öùºƒ0¯CožÉ=RJ/ÇŠ{Dò5Y%úYÅ+p\àM;§X(¡Ã!l•P)¬ÁìgRBÀmလôš`d°ážÚH–÷t7’ÜJÍn ÚHÿÆÄÚ m>Š¢˜ÿ›¢4¸ÃA+,rÁ€§¢‘ÎS¯Œ/mIkT°õ.©Þߥµ«…"H®´¡"’RzGÔ‘\ëU[ОüËþ¨1hz—<£ÇÃh [Ãi8RuüÁ 稻´}u§†æÖߣu[þ+ªVp{Ú»$Ž’¸‹¢§>°Iâ:‰£$Þ$ñ.‰ËÞµ×µè\þWÒÞ£h·!äeZ0­Ý1Ð!Ç£ ¦R Na)°§Ú?[ §ÚRLi‹xÝóÅ(‡{×¥ šðþ/ÂawģΊ6ÄU/ƒú¹B-IÍãK•â„æçojìÛÄ”‡–)-q«ÍFí*i'I»NÚyRÔ"i?­úÅB Op¡Œ{ƒB»§ªÑ¢(ñ³ KO=¦*ß$åsÑ[’mÒþ“PçiÁ]Z°|TɸmuºFYk]×î2|z´´Ñv”ÚN³À‰Ðõñ:‰›$RsÀéy½O¶ˆuŸ´lŒâ»ví‹TN‘~ªyªá—dCµiâLGœ'±ÿú#‰õ–­ä‚x'-¥¿å݇ÇT‰m£¡`Ôîö Ù°±¡Õ4iç½-¦Sò,à¨$ýXñúU·G`xáú €€Ã>‘<ú”iƸÙëO¾áÎõ~ù)yLëÎ8Zà~ôK?t†xÍÀp§ úRxrÞ1èg;ñxk†q­x|@ýؽˆ6pÞ18~+æpÄ~nÚéÌ0 šF”Æ´\zç-‚Ú;7¬qù}ý`üÞH³—i,ÍÃSÐÇk$Ä9h} L§“`×:O#y~œ±ž»ª®M)¼i?ù‹SeÒŠ/õœáaôfÃ" Ï2Ô?Ÿ ¤S›w'1Ë}íþç\G»yuކ×›#£ß$G€¶ã?Û(M)!ëg22;†?ÃêÛÚ OBiœ9æ‰KÓy0é}ö±™nendstream endobj 46 0 obj 1232 endobj 52 0 obj <> stream xœµXÛnEåy¾b„2ƒ4½}¿ „„Á£œ°1޽1V|ˮט¾SÝ3=ã½8žÅQ¤ÞruWÕ©ÓÕÕ=ùXr&JNÿÚß“ËbòFðòlQˆò¬øX*+=óq®‘N fË‹E*”Ppæ=Y퓃_ËÛùrVLþ(E1ù™†½ÃðsðcùE±P¾.89-D Y¶?'—åÞ”ÂÊRh¦´•åô}‘ðˆÒ3ƒ`²”Fãô²x[í×$­´Õ}Ýhf½…x\˜F*U]Öbkî«›p¥UÆU´Xrgu5Øֶ¤5Ü{S}Q!E¥«Û¿Ð…꺟_ö¾’[”€ØHÍ‚Sn9ãZ­u5(½ÔúÏé/”žEÂDL/€ÕF± ¾œž"­©šÐðކs®²î–†k–4ÜäR¡`ª £‡aœ{&cˆ0U'5ÀÁ»&{+ɸ0Õßµ¨âÄE;(¥ãJ¤èù’Ì’¿® ‰"™üCë Þv€¼>F%ÊEí´Òøg˜¾çX­Cœ®îÏhg£Û˜-žßQÔ(‘Ž’oºl¡˜±\¦¤Žàm“€þK¸6.º>¦ b.§1·ˆs«±ŒÆ¦b°2@UuPËȦVŒsG¢LN?Ô½IN)m²è—ÄÚY%âì{ªbÎ…¨æDµtq&®ŽÆ§ŠÏÛ"v8ªêÖ~u3ˆPí1ç×! ˆ‰AnÚM§R&z3©/‹é×oÓ†ŸgÎhÝQ]«H|£ÓÚ“+iªyOn C¾QâM‰Ð(‚D&mÞgugO ¨s;ïo<\ Ij^¥á/@JǪˆ×[ŽJ?¦Ûºau µ?-ÐŘßvH•:uHgqª¥F‰ûR8áÐBÆ4GÄæ*¬»’óìÖj3Òmô<ïÜiéUôf¼×Á·uoò°kÆ<èÞESÇLjÞÔsÁT0h*µY¬M!œƒ3µRy}.½mE¬©h>_ž’¨fmS*§oNwW€–¡¹bû"êëyž¥»ÕÙ¼¤Ãf$^–A¯»y°ðq72K/à7.]áßBÄ“ï‡AÙgë/¼ H0\Ò¥Kh‚ÐÕw±êëfz±R}d}‘u·ëëžPFã7[I§ÆÝ¸;öB”„Ñ;ôÂÜÙ½O)CßV Чo†‹¬[féb¥-ô„·Ýë„§iáñéó,„Û„ãMŸ ‚°L„ïe¾O’’Õ«U¤W™¤^÷ûðfùIãSÛB0ÏtA?Ê‘Ì%†~Ëù¾É ­òBÒO™¡ý§ó2>›-´x£Ÿ©å?J‹Ã<~ 3= ‡™™Ã¬{™¥ý§¦ñiláÉ‘_ »õ.+˜‹ÿ‘±Þ¼Ot<¾Mhãv/ŸÁûy7 ynø®2ÚŽ;毋ÿÖ…endstream endobj 53 0 obj 1346 endobj 59 0 obj <> stream xœ½XMo7íyÅd÷°‡ß,Švk´.ÚÄIôPôàØnjÔ’Ér}êoïî.W’%Ãë:…í`H>ç=I.¥ Rò_÷=›“÷$ËOË‚ÊOÅçR;DHmòŠ„+t¦u,á"ux\LŽ)o«‹bòkIÅäGþ9<ùŸãïË¯Š£ãò]!´ 4eÙ}Îfåá”§U%¡Såô¢‡Ê ,&S¥²„§³â·ê¨n{•«îëÆÌÓ²JëjV7ZDid¨nj„«œ¶¾ºâÎJzgª tQã*b¯•!Øêk˜KÔ¦º­ñ…/V×CûjÀjamÔ³QFD¯-`¥FYcLµHQeÌïÓŸxy FP‘Òò"²Ú+‚Ž¡œžcYoë&&oTu‰y1¹­æìZÂÕâè HUÂhjeª3";"ø8,ã7bÍp—]ˆZ±Ë<Œ;‘Ü&H*ÒÂrBR:ò`Äè75° ˆ ûKJ_Õ&…‘ðrȼ «S‡4åu› I¶í“œ)Ó¬”Uh5p4-°çDÀøÐígÒF˜v?{ *,Y†’| ü±•Á¾Ôñ!,))Xå…]!ÊsÕ1dР͹‘hûj +X»QkûX£ 9+¬ik ïG!ctt#Ú»HÊ P×=w޸л¬öV(ŠØ8:â ­¢¢¦¤^{È£w·ÉîØÄ¹  ( †R ÆÊhÁ·ˆÊö@ˆŠ‡(Æ´®Ç ÎgA4xßöj¯œW™ƒ®¸º‘ª­ü]ż‰2xËÄöÖE¶î·|çÚYïJ÷€n”ˆ¥;)Ð;·¡@$™éá…­c¥ŸÕÅòÙ‰.³³µ¼t\3Ûfµ6²…R±ÞPý““<æcö]fkž['kS÷¾ël­²ÕfÐJÕ羋l-z«[lØX,j•ë—:Ïom¿l©jèhYí¨‰†wà Ôí¨íÎrÂ}ïW³L*«j>ú:;z!.²u·Ýš“Ì>Ü©,ÎçÍC˜ŽÃ¨l½ BÊVßtj"Õ)‚ÛOóèv¾H8“{A,Ûh"™êÛ~°$±6õrKX<ú*ûnö{‚FÆ3»O#ÚÚ/yúå"† †F Ëi­†år¡×´3±eö­²uµcÃg=!ßã³´/ߊܸ+Ñ3ó6çÚ„/ù a½ ŽòuB+Ók¼\º‹²º«t­øæ¡…±l=žCÛ{‡™€ƒœö7™Šƒl½É­ƒïÃzÆ'u=÷«ÿáL·4~£½8?z ?o3?ïw000õCn=ÁÊø\îa%âa÷2çØ£¤`²À÷“—"…2)4†”ƒLÊINûI¦âçl=ý¼ŸÀ=LøøEßJ=ë®ÃâñUŽn×CÃY7îßO»ßÏ€ÑXgÿÞ]{ ò?ËF·wÅ¿­RNendstream endobj 60 0 obj 1258 endobj 66 0 obj <> stream xœµXKoEæ<¿¢f„¦·ß„0X`Á +q@b³ ~lö…K~;_õÌÔx7»ÁcbYÚ©­îúºê«ÇôúPR Eýóò¦š½ÐJ¼^WZ¼®ÞL’©¬µ&-ƒh±Yçl³€BÉ”Èê䬚ý,6«í¢šý&t5û>NοÅãì;ñYuz&žWŠ@+]ŽýãòFœÌéX#´“Ö#毪Î-’ô8Ìã5|œßT¿×§MkHkBý®i )@|ÙÀ1§½±¶¾iZ+³r*ÕËîš`}¬¯i³Q1¸z *KçB­IëUJ¾þ¢EˆÖÕ›Oèr}7®oG¬Ög«!¶ÆÉ­¬’ÊWÅËdœûcþ#…ç0œÊº„—Ájë¼L6'1ÿaÍaPÿÕ´ºxgc½&ÂrˆÇ¥ñÄwº5m2R©Ø}¿ÀwW¾Þ5¾~;à \¿ ï[úØ.ÊWËî²°"x˜B}E€·¤Ä)Ø›“ËdØ»SV.¢qôCûE˜ðBë>ê°uÊ` y-¿¶Ö3â §àè V^ÊÛC;7¬¼ci;./Y¹• V®Xy(=1•<}Ù˜ ³³’›PXZ„抇Šà´I„ך¥q¢ÕVú LCHΚTØ+\^óÇ?MŠ ÑÙZ6†@Nç:F&ä4õݨ‘b×uc ¨ ã`’„Ž9ÑsB#"Teó‡°Ú(5ÂD1¹¿ENj€säd²-„‰hÇ&…E®P•ÞïL *ttŒ—Þu“bIÕ«rdà Gݳ(©Ò:iKóCË]HƒÎ:d§µ€Ñ)¡ ‘b A[ª¾{;šQíì4Åíœt˜WÙ£HáTΘN-@˜> ˜)DNø‡ô‘+ãO¸av[u/ £íÑ0–†DøŸ8ÚQˆì‘Š4©0h¤'…ñ–+ãsÎA×þ6ìXšn.÷í¿DUŠž&í -Xz·§KŠÚ»×õè;~9 š =zÛ´^ÚC¸Wb½¢ô+=Ø}Á§9 Ð •ÙÞs•ïY9ëüR4gÝK·¼:c݆¥;^ݲn¹'Ñê‚¥Õ Ý+ir «&—ÍOPMáP5y¼ø){ÚfIWª¦¯z®£ïùk…¸Y³îo–Ö½ ^¬_Ö+¶Y\³näýšW7{§@zÛÓ9:ƶõþ)‡:÷.î1ñ­{y u7CgØ¡BwzwÌÖ–¥ë½~ØÉËøžÎÒ1¾ÓÞôÓª›ùÆZá'LÃ7dMýl_é“4ê~½?ÿƒ¤é¡#IEÿ‰^(%)GËõXú…c~Á,ísCÒ÷ÌÒén¦Gt„›ŒËëNÇ–è]¨i8gjÎY÷K§ï¨éaá#æ'½”|„,ó¡ñõñ(§;wèÆ|˜ö+ýð…ï0qø%@ÿS˜ÔèÏ«ybmíendstream endobj 67 0 obj 1098 endobj 73 0 obj <> stream xœµXÛnÜ6í³¾B D* ™w‘EQÀnÄmš&é¢yHóøÄ—Í®í¤/ýöž!ER»Ö:–ë"ˆ–r†3gÎ )*YËKFÿúßý³bëgåñ²àåqñ©”FØÖú¹Ft‚·¦l°˜;'] k­%­½bkï·òrquXl½.y±õ”;/~ÂÏÞÏå7Åî^ù²`d´à~˲ÿÙ?+wf´­(¹j¥2¢œÁ^ÚVc3Q Íáãì¬xSíÖ ©0Õ—ºQ­±Ãw5S\ )«³º‘­cŠÙj^Ã]a¤îªSZ,XgTuˆ̵J™Š“T3kuõ=†!JU]Öø…ÌUyþ*Û fµ“ÃF¨ÖuRÃ,k™Z)U-¼—V(õvö …§0œr܇ç€j#àB9;@L3¬®Nê†{×dW-I€˜‚^(t ÔƒlI‹DËXÞßã]ù׋ZW×Ñ©Àï÷ô~EKÒã^ø¹æÕÒ½L[“n\&z¯ÍŠ× é0È‹÷ù«¶èAÛ“1 8¯Î)tç¬54‡—iþ"®òô< çYx˜„‹$ƒ³Sà!ãѳq1äö€Þ9EÍ|Ô1XF¶¸°‚e„¥ÃŽŠX•æ ^òL9' UŽ×ltXKá¨Îûµð@{Ïxµ]s¦}ú^“¿Rꜟ×ä—ºZPvŽñѳšaÍ¡QKK Iż}ŠÃ/ܯ£ÿ'4Ëý¬úœ<8 ‡½N£ƒÄ—Aô§ä¥ gL䡨>b+B\vž Ûµ µlK¹¼‰»§¹ñ ‰ê çÂ{Õ¹<Ò°v¶œ=+fß­C<´›µOû‡ä²æƒøXÃsì,îÆ×Ç«üݳÇÉ<1(.¿Ë²O¢®i!@Ï‹{ ŸŠ?ý|L‰Ÿ¸v ±˜ÀÒ=‰žð°!-Y\Gë‹0KŒXÐ;qå]M<âÂU‹ƒMF¯‘lJˆ GºXBD*`н^Ž÷ WI~ž8C¸RC U2»Öó’¢N¶õ•b1F !s“, Kø ïe¦ô|Øî¨é{Ùî¬ÀùÓZàcû³£gªp¶uýX 6™-¹q¼“Ž54"&ÝM³œÂVÙ0ÎK5ù¼,eÑ "7­ôÖþ4k›N^‰^ Lµ^9y9JWÑ6ØÓ„“—m™sÆ!gpBQ’}UsnAÚ/´ÀvÊØ(†³DüFÝrKý\Â¥Bú\õÆ®³š¯¬^©µÒò~3ÍñN9‡8®¤"Ȧ6Ѧ5]JùMøÈ•ûáWªx’,§A›i— U3’(bþ£h=S-M"]‘è°å¨¼ÈŒoSÂñ,ÍŠ&Jgco™#‰Ìvš./qt˜F_Öd·¸ý(ë­¯ø7õ¡ÞzS7º•¶3f@ÇQ¯Lè_I/¡é‚f.“0Œ:æÏÑ0-:çYçñˆNe‘F×gI†{©Fó¶Nß0C£¼0˜ÑLŒÎŠ4zG=v‹N´ ‰óØú*ZãZ¦íd²m¢-rFÿwÚâ‹Æ©@ÛÈÅc»é”ÜÀ5`ð£5Sê>'ÙÇž :áNZ¸›dO’l/¥éy”¥©“mòáèVr›Õb[åÖ‡m‡¤ßW¾ÉáER¹J²ùÚhÿªÒp;^%²>I²?ÓèÍ€ýqô6¬£ò(ƒ%}ĨïÎc­4ªöÑmåAw²Á÷Ť™NëM"ðùõ0¾+œ?T8U„êøèà+÷õž«„_GËÈ"Yý˜µsÏË-*wÖL­Ó4{¹¶K__z:@› æð|Ò𞽈ѭøGèþZ>h”Ž-«på ÍéºJ£ÓAùßHÌŸÓÀ±te¥vÄ¥ÈL¤÷ï †Ð•:| m'Ùó‘.:÷ס™Ðd,ÊéaNÅ[‘ÁÉÂe¤âNŠ};!ó|]–0"d²ì»c4=´ ÷P_B·b¤AvŽ/_QŽøEÂèE’=K£Ý»—Óô06à¡õÄØûu/…»ÓXïº=ÊéÎ}v)>ñOÏã_]÷0#çÈ縴”ç –^ÿ;òâŒendstream endobj 74 0 obj 1584 endobj 80 0 obj <> stream xœ½XÛnÜ6í³¾B( DzÍû¥( Ø©‘nЦŽk´I Çvøšõ&éß÷ %v×Z×r#Èj2$‡3g¥Ü”R¨RÒŸîytQlí+YžÎ Už7¥ñ:Š˜Ç´¾l0Y¥dR ‡1ÒªY±5ûµ¼ý¸8.¶þ,U±õ3ýìì=ÇcöSùM±;+_’‚*oYv£‹r瀶ե²ÂX¯Ëƒ“¢ÍG•Q8l¦Kír<¸(ÞT»u£É«}õ¥n¬ðÑÃ<¬‘˜UNS]ÔIZ«ëéjo\¨Îi²–ÁÛêdÖúJ‘×É]õ=Lƒ­nk<áKÕÕ0¾bµa]2 f£­HÁ8„•BZí¬µÕÇœeÔÖ¾;xIåYŒ¤’Êå% ÚX)Pì{Ô4«uu‚¤¬R†êsmP@Ò1gj¢K'kLåéÜDeç&¾¦m¤²¿—Êêd[*œüÜZFWzàm†w¸¥»ì{ÁÖŒG_õ¾1}h3è`>Yy=m¿z‚(øÐÕ³%Ú-“–îIe³r¶Î+^²`ßõš5kØ„¬·o³sŸ­<ú[o–èÛ[ïØz[÷T¥ ®ÒȺqú0pî'µoå¢õt2n¢µÅ{Õ¤7Œi´vxQÃý­„Ö-§ðÑ€—ÎŽƒø.I|Øš÷Ô1ÕÃê ƒ° r8ðéœGo×véôú_ žÐ&¨5Þ_ô\†*óˆ»ðhä.䫯ôÇ{å2ºµ`ë|éÈßéËðžŽÒ&¼éµñÿyù¸_±¥Á}Þþðϊ½Í>–ßNVûÐL/h4øþ}Š»,&aó×A³ÃÅo34¯Ö} A3ø~8HÓKÛ€Qtúk cQpÂÒ-1*ÞcŒöØ÷ [»?OÓËØ€GÀ·ö¨ޖݘxÝ_åôäÆ> \x> stream xœ½Yko5åóþŠBê b¿Ç®RS"*¡-•(ý¤i‘¤íæÑ¯ç\{Æö>f“Yš )k®íû8÷øúzú¡âLTœþë~Î'[ϯÞ^NDõvò¡RV:æÂÜT¶R0[M±Xx¯|gÎÑ®íÝÉÖî¯ÕÕìúx²õ¢“­ŸéÏöÓÇøÙý±új²³[=›pR:ÁdÕýWÛûdVVB3¥­¬ößL¢?¢rÌÀ˜¬¤ðqÿ|ò²Þi¦’¤ÒÖŸš©fÖY 8¦…‘JÕçÍT1Ï5wõûîJ«L[ŸÑbÉ[«ëc,àžimkARÃ3õC BTº¾j𠙯ßåùë¬+ª5^ §R3ß*µœq-Öºž/ÔúÕþ/žFÀpÊ‹žªSa˜²ñ¾FX/°¡>…5Çè.Â. \0dEĉ°„D$º„(Ps¬dVC5ʧªÿmÔJW$sÊ»~å»F9XÕ ¬RŒå¶Ôúg#VjÕ`ýÊBF.‚^·Ì;[5šÒ¦)¥8Ícº“!0‰Ó>FLÙ«ÿ  Ô³k ý"þAqMÉÇb!¯4€ã6âÕk“õßM¬dªÃ0Xvó:´3ò%˜% PhµÒt˜ÁŠ~*¸dgC(f À AŸÐ2²¬gˆa§vÁ‡ÝFÖoÈ2ÝÁ$M€IÙ°¦„IÄ?¤ôŠâ” ÈĈð‡\')-2ä{;—XìäaçYO¦ÞE¥d©n‘Bk™›šOC±¨ï»FJÆI¡’BÄÁ –Ió즷1û® ¤&4Ãùx2Ùÿöe<ìtö{`£ 1~lDÁ–3šÐØË×´ã4Ñ!84;M ½NG,z6Rr¢Í¬·ÓÕÏõ,K0HVdÀJ|»Œ."¤…Y‰‹HíìOP]™®«Ü¡ëX¹[‹j#q긫„w-JÛ˜¢CÍ•_V+œw'ÅÂnpTÞñ^¡&7 Úœ©mè^¡ò…T3w¯%™&3(îñZ!v1î½õÈ|бQ6„p 4޹V[׋ák¤Ÿ5L8Š µ¸1U8.²›¼-Ð+eØ„²ëDgÌpOù‡OÞãz‰Š`•¶HÒil¯ÓÙ6e|=re3ø*Ý_ôŠYô»©EuÆþO=BSˆÉ#©˜¼?^ÐýO÷–heOŒoR ºûÐÎmœ¿>ß7h‹¤Ñq}Z9t(G½,ß¶Y;x[^ãS´ ®µ÷.(h„äÖ ¸¥‹ûW&s:šCAæPF}ˆ•ÐÛOê…¾^eáe^&E'½¬sÄ•Ž8ËDÁE: ‰RY3:×C¬±8çãø7Ä»–5ýª‹´™¦\_dø$a2Óc–F7kgѳåõ ‡iáAÊÇë$K™Aég/‹´ö£‹4{dç… ÑœrË^cË,É–¼N³4’iô ­"ŒäT|7âËø,ñ-ügº}Öóf¬]äËQæË× å„°ý˜dc¡ÄB×ÄÚN w’ì§$ÛMIØ[wj½ÄÁËåãÍ\£²óÅÌ䬟.¬¯'ðÛ ]p03ô:ÉÞ/Œhöx…‘¿ê4|”FÏÃÈpÙ…O²?Òèe‰4z•6ýæUèPäRÉ{7p h sVøOx†~ÔOÛ¡ ¹¦þ辺ÜsxyÑkŸØÿ=ÐÁ‹moG‰yÎ_œÏ´c‘ªÈ»s5Ê5(W­L­³4{µ`¥;·@= !¨%Z¶ÏÒÑ8¿²Öf©AhÏÛö%ZN+¤ÑÅè$~Ñàè9Æ×‹Ôº~Ló­Q*6¢èXÃù K`N„Ã)ëŸDÞƒ´IY·¯5ñÅŠ„Ewg­•­¢NHQKã _Š=¥›øµ§m»ZË^³ÑqmÚ~›5²Ð¿ä´è¹/ÒÂê¾aÞÒ§"Á„^—*W +^/\²èç-Z·l®u¥·]à¯ð‡Í7ž&C„ô¶½GÂùØzÒ7‘¶k†ö«Öñ«K|”·&¥AÈÜ@˜bرDÊ%–(nâ#oYcË„.r[Û½»¼Uwk§ç´ V±=Ó%Yìx /éæ5Òˆ~³BƒZì8É`sRÕ"G¸ÏNÜã³:À¼0?OﳞÎAÞ•ÿÜô>è6 *œ¬¬(Kˆ*ÑתNKç<»xέ¦>:pцp’áôj6Ù9ËÉ¿=-ãÁÈŠÓ#?Ûlöîma]x¿ÁË÷háÚ¦Qz8ªâõr¼âV¿N£³…çÉÜý};ÞãaÀ»åígúΰö`9ëÀþ-A×Vɾ™…loE/ŸúûÛaÍ,ƺ/ñÖ–yú Èl§Ø%döe #B&Ë~¿;FãCÀHÓ¿™Ý?Fôo©€æˆŸ&Œž&Ù“4Ú¹ûQÆÒù/QºPhø@éZèxÿV~+ÅãnÓ#V~*¯F!ÎUŸÐ%÷By6ù¬=—endstream endobj 88 0 obj 1876 endobj 96 0 obj <> stream xœÅXËn%5eÝ_á ÷¢Wù͆Q˜H ÄÀ•X0,&Cf@"ó@ðù÷»oº‡¸ïÌE‘Ò•²]¶Ï9.—óFhEBçŸþûò®ºø´xý®"ñºz#Œç¨bÛÖp`R^4èL)™$àÐ*Æ<êòºº¸þV¼û×muñ“ êâëüëòû¯ð¹~*>«®®Å³Jç µSŠþóòN\ò´,È*c=‹Ã«ª[‰¨&cÁ.(FË]õ³¼ªÎnöòŸº±ÊGóE•YrlŒ¼«£’¶:Ê?k¬—½qAþ‘;³ÞÊ[tÐIYë%g¯Ó1:ùLƒ=;ö¢fÌáË·íÄ‘­]Ì6‹Û›Ñ&L¡•¶Æ$ÇÙm˜•ö,oÚÀ.ZĸŸÜ3³‹ÁÎbÆÙäÏež&øÄ,©[~ òy=z9|S]*®¢Ö!öd’±ÊvdZÙ¥ñÑÎÄ®6éaX2ÄS`J‘wD$§‡€6G‹¦‹Æ…Ѷ¤f¬ Rɹ…Ôˆ!ˆWþ‡B!ϪQÉ)4endstream endobj 97 0 obj 980 endobj 103 0 obj <> stream xœ½XYOGÎóþб%3Šv¶ï#—b;–B+v‚”Hq8Œ †Åv¤È¿=_õÌt÷Bž,KK¹¦ºî«ûMÅZ^1ú×ÿÝ9šÌ~ç¬Ú?›ðjò¦’F¸Ö…oSaoM51÷^ú Ö:G§oLfϪåéù|2û³â“ÙÏôóøùüÙø©úlòt£z1aÄtƒȪÿ³sT=Þ$±¢âª•ʈjsoÒéÃ+×j•Ð:nMþ®Ÿ6SAXaê÷ÍTµÆ€[ S\ )ë£f*[ÏsõIu…‘ÚÖ‡D,˜5ªžƒ€ùV)S Âj朮¿(a¢Tù±­F@†±¢> ‚PjEZÆ·òÁZ¦¤ôZZ Ñ2#êíÀX{ÉWx,:;B+HÌ„¿¬IŒ5^ˆšwê{[¿l"öŸÍ_È¡.†<õˆã”¸‹± G~€ZõŒ~¶éç€~w?lÅᇜGêÈ^ŒÊÅX²± "ÀSÕg …_=\ü®áõé!Ážªeð¸¥ð-’«Þ#!Çt@–Ì1¦UÖÛANAO°å<*+ÀÕ9|×â"×õ%›´nÅ h/ꕃ çS²€L£ÏH¬] /xrá‚zô"C*Ø»„á4yKÔ¯›ä6ߥØUL –”žÂë!²ÕÚ»Á-¨þ%E‘‚\%fĆÇ·”ù6ˆzÖLu§È~£;²RS¯*2œ…Š&˜#-X <§ïÁ°Äg'ñ…4£JYDAêng5ã:àŽѥʲ‘±J¦Üä—¨u•àTA)—c)_ûÎ9›]>mbÐ5¥ÀM߇!PL ù2D³Õ„H&::²ÆQ•èúôuƒpà„ìê¢mBM?Ýœ ‡¶Ú»¾?sÔêú³5ˆ¿P8ç*î)iGµf¤;“þ2[n½Šl“#Ù~œ+5ŒØvÈ~5†ÝUÃCª }s@åÃCk¶áx+]7<>„ Ï u9€–¡ŒÑ>4ú–’”¢È­%á4Â1K‡N6;RÉ;fm~l‘æ AÜYêÐÆ£ÜbD þŒ¡Q¯ã *2’,ùÝ߬ÏFR3·äÃEÒǺ±|®ZL)î4ÄiÊqË02»ÀBdi=Hà,ç} ÑxÎxšÀY·xÀE‘v¾’ö-@#Zã}”‚W½:ZeɱâÁŠñ.,‡Â˜Ûñ‰ Ý–Ñ Ö#—Ê5sC™Öv©ñ.%Á«$ðp%š«AhÒ—cÌulw{Z Še‘ ‹üëùú[€[7Ãg 8þøÔïÁr$”¼×H 9cÍ éð]ôÑ¢ÎW+”Ü%hG,†´ÆÊíqxÖƒõÃäÍ/’»— »•°åÐ<ìea ù/Üñ~,ÇCrAï7ðTÌÇ; |•Àãv[óê¦å´Þô‹ÐC¬J^2æ;ßcšÂµÏ,­ÖÀ³h,Z¥Çý}‘k\iþê†É©¬®Ÿ`™’žq—ù]J\LãôÄíI‡‰Pì÷·^Ÿû+©ø[Ø-®n¢ÞìlÀBÑ{ÀÆëLÆ+i\1©´¤Œ3—gGȬ+Lö8a÷vz1Ñx)ÑH‰nQŽš.ÐÒ®áY‹f51¿Dð1=j|.—k‚û{­‰8-¨‹.λi0'p‘ÀùJ]\ë†ñê÷;foÅ&ª³ÉŒ® ùjÏÔÈ›¶`id¸i¯²‚S﵊ Ý›=n±]x—´µkɼ¸P&Ø%Ñ‹4BöŸ|‰¿ >÷N Æë_бGe®;D²߆MVw^e³VÙ93<ú¤òÚºXiÞTiã.ÚM÷±O`7‚ÔÛý¾dl??Æîñ —’Ï2sýe 6W´cíèîÂ,Ï·„ѽ>A0,8•a-ï®}.O[ù’y%(æA£—«„¤G8¬5Ø—û' ìVùcÃÛtˆ¦kÖ :¬RÚçoY‹K¼ŽÓsHz¸ÈÛÛEÿ +)µÆ;°”a†Ù»x¡¸ ›¬ÌµuwSæå¤Ê\ùVƬHkqiA¤ýcX/õ‹W¢÷EìNñ¢t¸²¬\ÔX‹VfÏùSìÞFyOï²Xk…ôÞõÙ$¼ñõ÷4¹7Léú+¬»Îjmê?èÍ\xe]¶#ÿ÷âlËOüm8ò–I[³ôøÖ32ŒçØñЗĉ3 ¥¢ô²3•ŒŠ…±ÓߨaʇT™³n§ø aEÚ“D»]ܧ—@¢½rŸFl\n…s­Ïb³è€»ñ>:>¹‹5¢ôÕÈ5·Qi[ÝUG–±‹tµÿ:aEÂ~7\øÇ¼ºœ¥W—Òì4ÑÎWi{ìyÂ&ìr%p×c¼‹Áò“4,¡‡x¬v«ë,¯Zi>~+.ƒ2k°¹ê‚ãÙ¸]æÅäºwóendstream endobj 104 0 obj 1833 endobj 110 0 obj <> stream xœÕ™KoÜ6€{֯С@% ¢9¾zL . i ôÐô:n NÛšßj¥ÕÚtv¹v,Šçñ 9j?¶Ö@kõos=¿lN~Û¾¹n }Ó|lÉc41?0 ßò2¤D©•kbÔQON›“ÓgíÍÕ§‹æäך“õß“Ÿ¿—ËéíWÍÓÓöycUhYe»¹œ_¶OÎT-¶À†Øc{ög3Úm4N”a‹.”'—ÍoÝÓ~@íFßýÓl|ôÒ|Õ‹e ‰ºË~ “,ÛØ}èÅ^ôäB÷N_F!v0šŸB÷²Ÿ{?ûI‰za,d¢I9H8…âk¡øAlR(ÃP’›Ö¹þS¤Â)Ë¥D^JtNdÙQÚÕEŸ¡p÷º »–!B2 Ôóé²ÉwŸô|—ûoıîïž‚I RwõMy<£Œ÷òÄ#ò{´5ÝŽ*Â(æZV¤)EÀ(å-Ñg¬‰ó_z{¥ÒÞ/^š¥çáÙ¨Ï} 2FâmäÖ¥lÅ‹~MùVC©¦R÷v¶^+¡!#€Œs)Žd¾d?“±àFAê2Ú,xkËÛ‰™âÍdMŸ5==kd9™(vÆÍRbÃãR ^b,nÈÅ’“%R³J%–Ò]±àOb!y>bñ· ³]²H–Çje¤Qœ­w_!–¤‘¼§¸Ì#à¼!YQJÓÈ‹œ;“²¶&€›„¸6]Á@dÔu†eB¢Æ€8ëÆõˆ/_ë”\s X!¹¯2oôÍ”\˜cX Šâ$-Oɚ사Õë±bˆØêüyœÈ³91ÔŠ© ´æïh%àÑýuF´sÜ$1Ùi“„Fw˜M";ïÅLÖUøjl¹¤KÕJ\½D]:Å AŸZ×sëÓ<äÝÜw3µ!_r™ùÖƒÙÊ 8ó ’½ð1øÞâtp yGÆ ZÉG±mö±Þ¸²àÖñÑ{c«}¬6®è£gÉ»køèä!O>`T0®{&éͦh€´¹í¦õ½­<ý—­A4$ɺ·KÑâJ}ûøÖƒ)òu2«¶Å£ùJ6÷[¾N6g»P—½äC0¶À-¤}hê}*£±°ÖÂzD‡.¯zãŠ>2Už]ŽõQêÚ©â8ØÇzãŠ>’¤­v¯Ö¸ÉÅÝ\‘wÒ}¹bƒÞM/C®ƒš6ŽI%õ€ŠœQªÊU8#M5 Ü›©÷ä—3I½Ke2°R1~.FîGs»ïlm5Ól/Âjß‹WªulškãVñÎ>_]$Xä4v8Þz.E¼6¬Tfɶµ(³Æäv+áÍSõP~wK«}ÔêÝ-S³ëOI”ûm¾Û¢v:Gµ%‰Ö©—äðä—4þËZ²Þ§ Þ*U–ö^ÿ7§˜z0%¼!­SàɱÂÕ‚ë-+úëVrÌ/ÖUÅõs·bØÇ¢Ú‹ Ïë”R.„”€ãÑëôz×K5-®±Ó;”t“*|õÆ•>®:ûHÅÌ—¿­2™0{¸óuõ ß7ëm+}Íf´‘2s„²§B?\PªÜ'Ÿ7ÿ‡Ãþ#endstream endobj 111 0 obj 1263 endobj 119 0 obj <> stream xœÍYmk$EöóüŠDg>l§«ú]äôÀˆA£Oä̇p¹—M‡¿Þ§ff{f²“Kzw$°[©é®ª~êuzß×ZQ­åoø>¿¨Ž~&]¿º¬¨~U½¯ç¨b÷lÅIùz…Å”’I5ZÅ(»žWGÇ'õÕúúeuôkMÕÑwòñä§oðuümýIõô¸>­´­¨SY_çõ“3QË5Ye¬çúì覆‡ê¨”qÍ.(Æ“‹ê÷æi»ba³o>´+«|ô Ÿ·°Ì’ccš‹veTÒVÇæ] {ٚײ˜uð¶y‰:)k}ÃÂu:F×| ÒàŒÆN·=o:|àfÝ)ŽlíLÛDî@F› B+mIŽ…m˜•öÜüÕ vÉÐLÆ›‘=!{ì,4N”?kDMð‰¹¡Þüšgmæþqö½ ê1`HÔ!šàÈ•qŠ£ã€|³Ä Óá!`Ô9>DÆÓ³êT¢Ànb@€"^g,ºÄû·z~nçàyïU4IôJ¶÷ü:[øV>º_d^÷¯`cÓb(ìT…é5CMÛvEh‚Júú¢eA¥÷fó|üÛ®<”Øæ^XB×ÑFÚ¨JkgÂ)Åèß ÙÙÛ/ L‰åÂ%ûõÐ ¿€½°Ë`…&‹“¸æZB û‰csYbUf\ËyÁ%a RUËÙÙHh­C²ŸàyÛ{>À5Û .gÒܢćíÚ¤m±äQœkNHçÒŠRÅI€r4"Œ’/v[€‹:”¼7q $n€‡¼îÃóÇ,šûd Æ‘„')¢VÖ0œ><6ÁL‹L–@H-lZ|£¢õTp‚–â£U O:Á¥Xš’ “Ô½ ¡ŒÚ ©s 0z‚°-ks1ÆX-fì%'4¥lñ‡©IË.—æ Õ“¢W!öNÿ¬%”Tcã©èc“ Αþ•‹설Bt”“FÊi¨Û¼óLý™©u¦ÆuoóÞñé‹…uëͺÞÜù9ƒVnRWˆgo¥Ïö •|¤1Êš¯$ áäQ‚°‘Í;>Gà3² 90j_öÍNµž£ÜQ—>Œêy¯3u5_·AoH±y$Ž1]Š£$ç¤&1m,+¶7e“ö–´1)$탘´¤01ȤB1·Í"óÐÙJ|‡1ô$çòIŽ-^G­Ø[´ÏÐ3»4&º‚¢­Ý˜åÜ}yKQ¦èòˆ.†ßGB—ò/!s…"çÑSGj‡ {àb(¡0såçX„Ã%_˜F;“’]‚o6˜Ç â92…ñtlåç]†ÝaƱ»`“YÒç(¹˜ð~5ËÑ[¨)}.“FhyS€i1‹˜ZgS’˜1]‚2ᮼ „rëAÀ\P8=î ç©ïþ ¾ª—Ÿ÷–6.oŒ{ MÚWÒÆ$vþ@&í-)›¤iç(½aÒ’&ñ.îQ’^czðí?»”ÊiÝ?ÊÁXÄT‡nNÒB;LyÒœ¦|œf–+Ë=kjùA–ñÐ¥oäexXR$ïdɪÔÝGÞìÖóñø^A¶Zw‚U|Ê%°’9ÔEèDZÂûeú(P“À¹å–/?b8Èóor'j.sÊO±„EHô(¯J“¥ôÿ.Îå`,·à@»¿ÆÎ:ðÞ‚ƒ¼w‡1hAÑfsäæÿáo=1Øš…;Ï­k0;¯Ø°¥kfǻߤMn™wc4ŠÂðKÅä—› ïN«ÿ1"ýÓendstream endobj 120 0 obj 1379 endobj 126 0 obj <> stream xœÍY[o5æy~Å<ð0Ç>ÇWÄS¡ATP´-BÍ¥¡j“¦M‹@Büv¾ã™ÍNØxw¡H;žcû;Ç߹؞¼«µ2µ–¿áyzYýlt}qS™ú¢zW³§¨bîë(Q¾î0ؤĩ†@«eÖ£ãêèøIýáýÇóêè—ÚTGßÉÏ£Ÿ¾ÁãøÛú³êñqý´ÒZ™¬²§—õ£…¨¥ÚXÅÖS½xYõö˜:*eT“ ŠÐsY=k·‰˜|ógÛYå£GóE ˬqÄÜ\¶«¤­ŽÍu {ɳ ÍL:xÛœc€NÊZßHŽÑ5_¡ÉX#Ûé´-A‡Լϊ#Y»¦m‚;4£MP¡•¶ÌÉ‘ˆ™HiOÍIv‰ÍÆÕJ´„Žì~Çsö9ÏyÛ9Å% jsL<^THBá³8$¸ mŸàÁ#BÈ‚<4r[å6tkN›°Æ3+Z›dc!pF4&uÈŠ•‘3XŒIQ Ø]Õ‡-JMòžã´ú¡Z`ùP{~lQ£"‡Øçc`g²×•Fü8‰”eBÝì ´HVŒäàTĤÙ~'ÊJMÌ™¢Œ¥¨ZãNˆf MÉ…Ñ›ÌTJ»5µ]–zÖ†­Àí Ãl5 ô~8à߯ r¥@E.—ú/Ò„¨‚íþyk@%*Æiت&3œ#[Ô˜»°ÓöE3·œìh9M©¼);]¶zøu»PpsÁÐ;ÄŸºE)?±2k”Aœ¬M[*{3QÛ9 “÷Í?£UG}w’ú½”½eW3ã®GÙjÆ‹™W£ì|”! P'!N½…·~9ʰI;ëdåÍ×h¬ÔdÚÂܺɳ ›ç뉬_i´ÍßC3ÑÄðÛŽ’Ù·•[§cë·É–3VãÞ®÷æÖÙ̸±wÎñ$û¨_ó»“DïwNiRÖ3e•sÅ©²BrNjösÁû²ƒÞm Ñ¤½‘F“Œ$êALÚ)¬ ò¨»e0w„oeòíÂä5r¶/LOÆZód ª Ynuä-˜½0翱k)³1;'ß=esQ&ì–Ó2Ë®‹¥q³#»Ž•‰Kv;2YwgœÇ~rS#¯hâÐdŠ˜mt”¯cž„+ó9:p\Å sD´ÎLa˜Pôq[9ì㫳Ì|a¹_I-_È,ôiw‹¸ò]8M蘞—§Gã{…Øf`m£ªx‘sTEG‡ù²…ªTàÕYp–ªIàÜ‚rãç(±´öï–<”›Ppøä)_È,:=ÈMÔ;e½¦ÿw}.'c~ö¼û=vmÞh0ÈáqƒöŠv4‡âC|–µÈ²1×¾Ën| ³«Û6÷)\.Lø¾ kOËÿ¦Lþûa+sÜÓê_ˆ(Uendstream endobj 127 0 obj 1451 endobj 133 0 obj <> stream xœÍYKoEæ<¿bz„¦Ý]ÕOÄÉ`„‘"°”á°IL°gí¹ðÛ©êyîn›ÝÞ˜Š2Ûªž®ÇW_WWß×JêZñ¿þ÷õMuò£VõÛûJ×o«÷5:2¤¹*·•‰’$ª èoZ.NøñŠWL¥4cJàÅHïÉ4¼ç_£Õ4}›[~9 ×£0·ƒS#xD­<+cƒN¸[Æ $pæS ÿÃ0õƒqR6)Ç-€çð[ÒÚ:ƒ/d­M΢Kª_7}†8*£Ä—ƒ,%éªÏŸ»LSVÄú›§5:‡~ ¾Ñö"M ¯øq;<:¨Ø”ÛD]dÒbâ+æ ³¶ãh¯õÍȰ5;Ì$zõ®†Ÿ 9»¨¨ÎÈ@·¾†ib˜éj˜w´ Àx2Pƒ"hÊʹ¨0îªÕÎ{*½bãߺXk*Òu û°S§ Õ=VbÑP=%ç0ÌK¬¶N"¥5é»ûSªª‘AV”b§U¤ðÐO)h‰vÁÐF¿l@¢/pš6£²ÝÆðˆÞ̦ïy P ‚)%µ"({õ¬óߌÑú1‰@´Öœ±#©ÍpŒ¡š«%¯¹T¹OÔqz‡‚'þ»LóÙÆK:wúÃôó†}GúHÇðleLû†­xן†ËɪY>çhdx:ŒweD‹ ™Jí(|7Œ:››Îò2j4Ù6DE2iH=F; ²žjFn*íèKï ƒhÕÙ–JÔ »e—£l½åüÖ‹_Œ2è_$Æ5­yȼe×»²õ7ù12­œ “&#Ï<î¢Ê÷hÓ¶•„m¢‘»|*1Ñ`àN.JòmŒ±Ü¹|ŒÔM>IÕÜ££Æ¦4Äbß²!:j ÑŽG1]+K=®Ϩ̫¤FNÒa—?:JôŸZ2©·ÝžN»##Ûo9.Yx­/-ëÇÂK˜ðµÔ¥h¿ ê\ŠÜm ŸHû ))ROsPíƒÆÐåÆŒÐ¤`“c3J¼]ºíE­8Ü,j†n_‹ †ÄCQ›Ñé@4ÊÃÈ¢AwkV·ŠÏe¶WyLYh Øe ²×C£=¼ÊËǨêA´{Ãc,v.#—¯Eh†DoÅ©[ß[ÁÑMËl׈T7ô¡§ò1'u9@Yœ•_¨¢‹žÏà¼Ñí©/V’òòÈ_MC&Ò-¿íÁf[ ;­c Ïöbø ÷ò ÈËô:tÓ³8Uªc¶ñFcSÜ„+G‡ o9.9tƒ]¦' J"NwÑÿÿ-¦˜¼>,Ódy¤KAÙ=¸Ü¹lˆºð3î‘!:*àéO'»%.Û2îÖµ}p’ƒÃ™eú*¢gü48ž¼(= õË4mtëemi¹g³ïˆfŒO=Q³ôï™ J›ùļó}ÓLá;–ûªot|ŠúG¨Aå`ø‹Ðìï7 ÏÉçÕ?ªp½endstream endobj 134 0 obj 1445 endobj 140 0 obj <> stream xœ•YÛnÉÍ3¿b°OdŽú~É£#ë ‹$ûç"iI1eÙ’í8Ÿsª»gF²l·`Xâ»ÏTÕ©[·> jÔƒâ¿ú{³:ûU«áò~¥‡ËÕ‡Á“Æ$ßmM4z ËuÎ6¨1%îzñjuöê—áãݧãêì·A¯Î~æÿ#~½úÓð»ÕËWÃ?VŠ +-¯ê¯ýÍð✯5ƒv£uÁ çoVE=¤Ñãef0^CÇó›Õ¿Ö/7[C© ë/›­C ø¸Û@1§½±v}³ÙÚ1+§Òúýêš`}\Ÿ¸Ø¨Üúˆ*Î…µ¥Ô«”üúøha¢uëüíˆÊ™2ѶÆ9ÄÐÄÞ9·~'«}¶ºn”e…µÙ›åŠýbãÿ ‡Í£ y}YôÈq}'ö%ís3*¨äª%q…m:ŽÑ¦õí´í …yÌ)­?n`EÊiòJÈÖ¯ï7[=:esX¿åǘ4ì¨Râ¿ÏÿBˆó²2ØßjÞÏð=` jÅ…ôý´ç×kþÔòqƒŸÑ-½ ˜´k(O,¼^µuë ($\ ° £Òm mµÏ*–EŸøC0dùË•|-ËwÝÀÜù5Ù.¾åðŽP—\âeÉ,üHÿäœ\–÷“þe7Þ¤@{`ðÿíÆS#ÅÅÚ$îž>Ä:#6Ê˯ß›wúk+Új;ú LñÓë×À>P.&ïäË^ÑrúRžö ò¸©ø #$Q‰y?oÊwwÇâRʾäsû ®=ÃW—ø³™Ç] ‘Í5?%dñüÂ1KŠ÷•¶â§'pw?{i·1Ä zVÒ÷‹¤Ž*‰yw°˜Î£×|NÃù_Wç¿—hÕE_z:GhàŠ„{'÷Ð5>‹þ6EÖÕ)þâb꽫ÁfIÀ"LĶwWSXN¡]^õeR‡~|ÿ0ν,{¼íaÜÆýä‡á_.Ž–%ßõEI¬å¢GAÝüe—_T·ÑÙô°XóiŠ@цŽ:kκ 雂Yãkzýnʳ)Bf/W›-î÷˜o•½ÞnjŠ_7WOŽO¿°¥ïDËŒHÞHëõÔVˆí¢¨xxÐS¢š–š‹| M´­>^ðu Ã=/ÏWè£c‚KSíÑv¥GÇ€zm JƒNÈ!ó¬öŒ*þð5¬É¢4àèãó€?¬ ÐÈ’ÒƒEnÚ"WïŽÃoûZ³VÁÿEëÿeUFƒ_ÿ =è’œ}Ñ„i¦”oà ' #CTz´É 7+«Ð|œ$§Iâ]#48M»fÉÕêŸ2ðßÝ·FiÄù^Úšü˜²×‰}­¨©b[@¼&cVÂä²Þ}:\ßžíÛÃõýþú°9ÿOaóû6í8q ð\`£ŽÙÉM’Ó$1.`|±´]³¤ØøÓ¬r.ö؆ÀÂËð~…)Ã/mÛ]ìÇN»dš„‡P°ñr»"Î)´ÀÁ*t ïͱ1r%ìm¼íWZ+‹ƒ ityЄFl c’ T3Z¾¿»ÝŸ]Þ{Ã:‚…Á‡®£ % Æ`;Ž…QX¨°. 3¤ÑŒû­1¾vذU#7FÞXØ÷`5¡ ªû(^nÀ ,<W–Ñc#¾0…+—Æì„ϬBýq´FPur Á,¨X(¨ ªÄ]J¹7"NEÉ."@ó,Â"šduWଓ»Ýiôȧ*ÛûÝÝîÝíõ®7ÈXaÔd‰<]äq`ˆÂèÀy@~£â@4ú®j‡I¹Qš0öCWïÅC ü¹„:‡[ñ}Rð€TB†öJLT' ¦œ(é¦[Í®€ÝI¨‘‚·Lic ü̦<ÎĵõÏHfc“êêRSΙOpy}°ŸMo‡2Éøjæi¤I€]Îá=:à” Þø |²Õ£)ƒGäö”šF3ÃáOÍþ‰£p`A}Ÿ‰4*cÄa’£ŒºžÔÔTP抚҂IAÍÕ„^&3Ô7ËéÞT–ŹI|Ö]ý|âüžx¨éà3`@ƒŸŸä³—MjŒ–告^ ›38ûr@šyÌ—O=ÐGÞf|–äš+³q(‡¨êŽq`¬â•ÍàÎC 2GÜÑŒZ4úF¨‰Rq'‡Öá*áX½–7Ó“È‚*jtU³Ñ4IEMUjuýàѲ¬Ì1cR±ËÊ\% úë®~úMLàµw0ã°·¤ÿ³æÙÍÛý§Þ¹Lg‘cÄ¢ÜYfá$ÑHZ‹×ÔgIKœŸÁVLN¡ »3¥Á4›d< ^æÖŒa¢­é¨ËD5ºì@e™µT›*œÞÖôÑiy{¦dsfxPš«d&¯íê§óŒÖ]Ùl9¢À+K:﯎§ÓýÙÅîþª7Ÿq¢d“Š Å,> G8ÌdL‹,Öžg–ˆg,]´ ¤s@yd:GSÊ·eNpÅJ™Ï8!£5† “Í£|æsË<$žGU¨ÙœÙÎm‚ƒ%ﺳ™˜Á6L_0UIfU@MŠÝÉ5K“¶*bôY$“šIrš%Ú‡Q—SVÝ5I~Ø›c4¼ÖëHf8;óPÃs’òÇÏÇÓÙéúâãííi‹èÎé$zÊÄ,ó “ Oâepf_­`ˆçËy|Ä#&Ïþ¬1’£øYGjÌa[ºŽU`>áèÅèÁPj9ãN5À£áã¤y¡¤–`t¤ A _Úc 88YÛUˆ %‰Š“΄Zr7GÝPQ‹ˆŠ€ïžÍúq²[f3cJœš !sx«{fÉ+@Š!vÍÚ†×ÍHͬ9`>ê爃ޠऄÐ_³ô¡³‚þH‚Èåj‡£â/FíÄ£üù§æ³qü“ „Žq:@w;én†ó2tR— ÇP×@Sõ ÔÐg$t¹™©„‰\6ɂ̺ë9d‚®¾„FAâ°½$³dôåÍîm*c~%Ü\ÈÜÅù7qÎÍ<4[62 pªit̤¢ŸŽÁÁñ®|ˆ˜ŠSqOPB=31.õì+æ´ Ç‰IPÄ—€;fÕe""¨vŠ<èeS!å+/ÅjŒõ™sTÂÌ”ô ÈnƒÔBÓ—ެhÑ0Dõèo´:Ä Ñ†yõl¶Ñ&M)Ò±çîG@cuå@Wúálµä“ª ®×j-˜Vã˜\î*2NÂ(›I³ÞŽ^reÅà=žX "òÄuŽI®œ«MË<¯+X/“-““[öy¹ùñ PD›€šÜ@1n ¨ÜpÐ,¨®ûÆÓEâqr¶z’T«Ûs³zz^Zmä.&¡ó ÆÙ…ÕÆF9´5\˽Q*;´^(7›-¨ó’Þñ“舭Et@&É4nL»º4x¨çúæOvŸøõrã:‹•åŸ]ܲc5<À-j•Ì%·ízFÎξ.›xDÒOá‹ëûÛw½vi/S?ÜîØ’–ÃÉt˜žJŽdó3ÊæŸ£–µœžDj Ž\=J÷SBºF†™iÉCT@SÝ¡ÒR9:=Çjý´¦3F+Μ™“¤ff{n™9=/3³Y=gf³zÎÌjub6«çÄœÞ=%f³úy™‰Þ#GN´\±s4 “ä4Køgd©mSüð’'èØÁíÞ]ž½1ûî#¾•?›@¹4Ö¾Ò$H=Ï>RŸyIâåï"­¯8©§"QX°Ò(½>kÐÚ‚ž¦ÂKSßã–ŠS—¦Â·ŸÖ4×òßÿ‚ÿóendstream endobj 141 0 obj 2994 endobj 148 0 obj <> stream xœåš]oÛ6†wí_¡»Jbø-rÀnºX X‡»Ø,q\'hœ¤NZt7ûí{)“²-%‘º†6}D’ç9””g¢àô×~O“£_/æwQÌ' e¥c.\«e#³EÎÂ{å 8sŽF½>žÿ\Ü/?Î&G¿brô#}¼þå{|ÿP|3ys\¼pR:aÊ¢ýš.Š×'4­,„fJ[Yœ¼›ÄõˆÂ1ƒÉd!ÀO“ßË7U-I*mù¹ª5³Î¢yZaaZ©T¹¨jÅ<×Ü•·–+­2MyE%o¬.gèÀ=ÓÚ–Š¤†;gÊoÑTØ¢Òåy6C“ké­'mµÔÌÛÆ®ÄFk]^‡ÞÆ+Ñ ÍØC)od·Ç´3ðo¬Cy&­/çq¾)—aN¿Ú”åN·; *.0L4¬Q®¼IÃÞ‘Ð3ï\y_aλdë•)ïªZ0Í•·å{j6N`­ÔØæÏ“ŸƒÏ‹€Áƒ~- S–ƒË9Ìÿ扷ôqJdO‚Ѷ¦øˆÚ”îj3ä?<ª©+…=÷͉=X.RÇW¤ñUÒ(Ö4be䌫¾÷0­Hc‡ÊÂ0ý¬Ò´I¥%ƒ×†õ*Í8oÀªá2m㬠?¯Iž.†_Ó*‚9¯L¹¤yðKÀ‰nÉÌÞ;!]€/¢n7èvÝŽª¼¤…uÝþ;íû8–ÖùGY)Ò.ò°^@gFvöߺ#'‚VøÀM.³0÷ÄDI*²´Z5ûÌ^Kc™„c(fŒwqrr@L§\.ªC]ªdøiÈ=myR9ƒ ¥‰}h©à))2]žLhË%yT`icϘ >."^æ¹èê9™V­y>Ù8c•¤þoN&È·Ìa"׿r¿×1—7q-uÃ8¾0ÚQi«@ÙV+|Ó ÄWй#ȯLF…š–éiÞÉqÕf¨Ò )Áq¬U®[i<®A ò˜\ÆJóò(fw²< -©)p$ÓÞ£0Ä*#¬ ñŒˆ‡÷4žá)ÁÑø&œ– .zªuðžÕåyšqFó sHrW,É6Ò%®°:Ï –‘ôMX¿œ…$G ^·P¶ÆMX¹C‹”‚f‘pf©×yF ‡ËR²¥¦l Ò*gp¹á*4­à>¤ýØ¡³M‡T‹[í‘…^¦`›äØPÇwWƒrÆ)ÌöÒ#Zt^‘ö´Áý øK$:e9Ž˜s)µAà Ò*Γì2µnÒÕ#j°BT­Zç©U¯ËˆË$»ë{ÙQ›žmº±ù1^öf[!d[Ëò¦3ö¬“¶µÌV²ŽÏmÉG£‚Œ4ó<ød|Î+Œ³´ûÏI–¯Þ¦«Ëå¦Yvy‘Ñζ€âhš„[~öU€ŽÇ0´AUnwjqêv_&joSë´Ç2»ë·¸ìô‹¸Eóââw<¤!Üwßú¸ n›íþ¸/{p«Ôú”FHÀÛ±º1ø2 9¼ñ&‚gðk\­ÞžVL=C…í‡AY7T7s!PãÍ;Jó‘ϸv…;_9-6™¬ŠZMSë(]]$³¾ïÉ®ɬ%¦Ô‹ ­ñv"&ýÈ»Î]‰áöMµe0ã¹Xß}]m¶ÖN)9ÈÎz Ý]qñróâx“Á£,¹ó YÛ¢–s`>”~Ú”­ÁËÈ®z2dÆxß“ønzÆÖC.ÐýÀ¤6Î0ÇÝ^çšéfúGë¶ÇA–=²ëÍ-yÓq¸ÓN3õÓpœõQL½Ç‘Òûý½fžZ‹uÞ9‡'ÞÏò/ƒ÷xJ¼½}¦àvŽ™ÿi†È„ó•®^õhIÅäqOÏoÀœ‘¹jfèû¿÷SìÞq=9ŠÇ›|€]ƒ“Czk™QþžV<|ûº!R#E3 qïPÜ âxÛ@´ô&õaöY o; 8jîðÌ ?­Ë‚šœ7Žì™b÷h¿ÆóúétÆu€Ž‘#ßëíHGkÖD4ùFgëáÕêíÚë»dI™ZÓçAsÕƒæ,¡Ù*¼k¸òØz»ÂåSÏZá}2àñ\k¡RÿÖþÿã+Ô¿ÜqðåMž¤û0t²ÂÜ/Ÿ…Òò'6ÞÐÄ7©zR²&U½}ˆ=hþn~KÄò勞èÍ“l= “Lñáh»xz´7yÿKZ½Ï«ÞÎë»±jÇq¹ýÿŠî¿Cà`3ªJ¼ü Q6?+endstream endobj 149 0 obj 1749 endobj 155 0 obj <> stream xœ½WMo7íY¿b“ô° tirø] —´)êšÂ@uŽ$ÛA,Û•£&¹ô·÷ ¹Ë]ER굓"ˆw4$çë=É¿*)T%ù_÷¯fG¿)Y]ÜÍTu1û«ÒŽ‚i¬%OJ¸ªÅd£ŽR„À«žÏŽŽ©Þ®7ËÙÑýÄžÿú=>Ç?T_Í^W/g’ÎTrYuŸùªz~Ân©RFhã¨:9ŸåxT„…3ªÈ*Äx²šýQ¿hZb-¹ú}ÓႃxÖ 0£,i]¯šV‹( õmƒpÉiëë+žLÒ;S/1AFaŒ«5k­ ÁÖßBÔHQ›z1,[B”†¢‹l­%#¢ó®W[cL}fÛ¨U·0‰y†ÖÑÒxÆ|´ðâÐQ‹õEŽ#úzò ÊÆ>)'ƒé2I&.±Lyáu¨oʲsVFC¨ß6È"ÄPªâ¢¶õ]Ó*a¤Ž®~â ytZëüŸ'?3 À xQ%"Ðo¦:Y öÇ %GÐHéáÝrM<¶T¿F,IuÍi©4£m4§¦µàLžr—‡»øL¶þ0Dyβa ú“ÁA ,Y÷7ëXXsíŒJV“÷³Î4qvš²¿UÃXPHKHHÕMÜpub Š`1éÿ²)ε%ŒRÒi†F™"ç* *¥²cš‚Q) ?äS½®{¯:98f¦ – žK |*3±8àá¶o•ÖIÊÓxÊà>;ÞpÖLpr ³2tÅJJÑ/ú2Þ2\\ÞkÖ§Á´ìº`›0ã$쯚4»ÌÌÜBÄR šàPTS…lLÑüØPd¸ÔþR§.GXm³Èç 7ü›Svõ»†sb'#{Ì ã“Áa|™1UÆFuágŒÀ#{:¯¶Ã'%€l yJªÂ@ê ÀzYJÚÕ#oÔ5•t¨}¿¯4©ÄþÓS¬î ”—r§_Iߥ}Îoý‹DCã‹“:° E躻Ҽ³Sw÷;P *åø×¤ÆŽŽÎ²kV)‰4–Ž¿OŒJ)z‹†ãÄn`sÖL4wèðÑ'MtN‡ñá£Ðæú¡¦&>ÿ µÂ{ ú(Iмâ*A,˜¥ðÊ)ÓÞÈ^ên*/º”à£wàE7^`Bå® ¾ÏW~Ñ|£´•î«!ÞÍÞ,¯q‘ç’·Ø/$ šåÃÌkíÍ(·8‰üñ¬L=AÁZÀýÃÍ0(8?gÄgÞ÷©©–Ý’pMÚƒ_[‚dÆ»±{ÖÀ·áÖö$K¸PݦHwetÍ’‚y^’^éu‘®·í%ÝY‘Þ‰)!¾tKÎóp´#B|Tµ€Ée;î=Øb±T‚z¼©>(Šæólgeý'YÁwʬ8oЛqäè{”z|‡2Uøº/ÈcEБ¡åDo Áן¤0NL‹› "­Ÿîaýf{qZrUtèy¾šâÓÎ.Œ_—™rÙ§×èPµ¥7Ÿ§Ûì?&úbLjÄ%õå&®ƒs¥åã`ë ¶ŽC¾ÔX<+â¢b1·¡Öã%äqýêŽ~´ÌY‹ÊØ"RðÝùBÁõ«\‘,꟬—SÝ›f›4Îåø»{Ü3‡ó(ªöܦnvè=g̨{KæE7/ºeÑ-Gf¶tIZ”Ñ'p‚ ²Äƒö´.ã·EÊ—ÒK³×½ßcqÞqçòÐ…WEº+f¾+ºÓ¦ïÁÛél;ÀÛèìÄÆú°&«ºçïãÛpFy³h(ýõ¨Û¢»Ù=G½ýhÈö¦#öÐjÏÄõhâ.#Ö÷Gw:&À ÖL{R<\ïEP1ö‡]îyÁlhÞ›öë.‹”÷\Æïi5†ùݨ²‰zÅff=…¼éÛj*;áÄôZÜm43eïÞl{Þž÷ß0OGçÌž;Íÿp¥A÷üM0_ÜÿN3=¾}/ §¾+FŒ˜Á©J{^Âü®žÔƒ_ÎþpWjendstream endobj 156 0 obj 1515 endobj 164 0 obj <> stream xœÅYKÛ6îY¿B‡¡¦Éá»(zØvnMa ‡¦²öf³Øgö…(úÛ;¤$R’¥Øt½Zˆf‡äpæ›o†”ü¹d”—Ìÿ«Ÿ«ëbñ;gåùCÁËóâs)4XjÃØ pªË9NæÎ W¢‚Qkýª£“bqòkùxÿtV,þ(y±øÙÿwôÛø8ù©ü¦8>)ßÌ-xز¬«ëòhé·…’K*¤†rù±¨üᥥ 7ƒG—×ÅŸäx6¯M¾Ìæ’j«Qü0CÇ$W ¹žÍuL2Kîfè.h¡ ¹ò“-ÉN`ŽJ©‰ðZŬUä;†($Y§eg(2 N;om’:mt£VRJrf+'x½0ˆÕ !œ‚öŒUkáßè‡p´#ç•ÎûŸåÊ5AifeI0ñ —qC°ä6.û蕎:kÉã £°ÎFT´Š<ÌæœJ&œ&—^4–cµVió×ò—âxY`–¨e G+p!©¬`4r¤¡ ¡>+ù˜Ü}Ó,¦QކA ÷¹¬*‹¥wÓŠ` “˜gmŒŸB"Ö¶ùÉ9 pEEEÏ;(g*¢>`rr§ €”Eï¸6ÐÒ­0u–S†ÌqXKÏm$„ÐH­É¦ÞpÍ™C"¡u†©5ä9ZBàþÒ(oÉPn%´7ô9‡\nºEŽ FÖswG’wÄmd½OÅmíˆôã¾ÆbÁºtÈÑ–Í« Z‹}ªÖúølg¼™.ÜI*EÞͪ]±#7³©°þ÷Kg)›&Xb…²y«kFɼÿËç̳¾ñH0ÿ|)žú¾f/+ P1õÛŠÒzܱcn­t˜JßyY¹\Z‡„;ÑJýYE1¤í—ݪ‘*ó]¿ nŒ7ÖkÚ;‰´¯y9èV›Ó Ò²f3lî m $Ù<ú‚Õ ¸O£rëâ´ÅáFw30ï.ê.£tGßGÝiÔ=u-é*Ž®û`¹P$Ê*j[Þß$ïßDåCo-`­ÝGÝsw4HiРTÈÑ7“&ƒ_7ãô¦YQçJ™v®€ó@õ©L°`\«Æ{•Š*»ÆŠ /*‡iþ}ÖU¥X¸ž”ÀdÓþ%%¢2IŸªaÀþþ}•iÇMÅÓ0¾hj¿àäOS‰®âèew4èÎý0ÀìǨ»º÷uÔã}½Šº5†éO‚ü“"ò:qûË€‡«®=ò¦y·ÝÑÚ‡Íy¾öŒ?Æù!ùu?Š „ó­S×5J;;Ÿ’cäfþ¯—?1¸ÔdŸ«ã1‘þ>ò;©:zø¦:h”-0çƒ33wÌÇür=$âl±WÈ çÓÝÆI‚º«(­ëŽ®l§*÷ZÈ]Ô¥ÜnžÙ­ösÞ£uŸí”—¶'e(Ç’b\æ›çžÜ7xß­oKõ•™û”îÆõ}[o‹Õ5W(Ù,2`Óú€Êo (mù‹ž€)|CP{“w=@Þç®®× zô Òu”>D)zñ®µþù¨á–)ð—ŽJÝ0u3©'iãÌowàPÊm %©á0/?ÛP–ªý{l"ØÅÀ‘•®%‹J^ôاMŠï{>Xc° ‡é¢Û`C5LKÎüØÆPy /HÛPâš*û*=4ÑTf@œÌÄácà3Äjâ.™ÛJ ä$]ÒIj„{&ž~µÅ¦7º›ŒÓ<·‘ 8.'é—¸›™”¤ù d}M€Þ<Œh„F¢n{ðù>¯šäMQsjýGÐ}ë3ÝŽÓdÝ­»ôý¤WŸ+D·Êëo;×g>l#ø+«'é _ÎüW¿)+4?¶¤ÿo„£îUšÖ¦³dÕµ’û>˜ÙøBëIî9€c±=NÄÐüØÆ>l*s˜6ºíÛuñ–Óù°¹åÓb¶{C¿@â[Ü!~€ÜÃŒ`øþ¸ùC9ç6¯Á¼-þà2 Äendstream endobj 165 0 obj 1511 endobj 171 0 obj <> stream xœ½XKoÜ6îY¿Bq”:,—ïG\ܨ‹m =Ô=ØÞõ~ÆÎ&í¥¿½ß¥õîÆ–EÕxH‡ó}œéc-¸¬ýkŸG—Õôw)ê“»JÖ'ÕÇZ;xHcå•䮞`²ŒQÇ ÁC UÛ»Õt÷—úÓíb^Mÿ¨e5ý‘~¶ûÝêoªÝúC%Èh%Ó–uû8º¬·÷h[UKõqªÞ;®²?²Üb3U++áãÞeõ'Ûi&Š´Ê±¿›‰á.8ˆ 3Ò*­Ùe3Ñ< #»ià®rÚzvA“•ðΰ9&ˆÈqL“ÖŠ,û¢Æµa³~Ù¢0*ºHÖ&Êðè¼ëÔÖîÒlµl&1ÏÐ:Z5œq4XøüБ+ÙIö#zv›Î¤Ý¡œ¦=I2qŠeÒs¯».ËŽIy }jpŠC‰Š‹Ú²»f"¹::vN¢çhµÖù¿ö~" €Að¢L0D ?Ñæ3„ÿçFáh›LûÀ‚6š iHTl‹©ô£ 9ü´y”B¸ÒêSš“1ÐG °¿©3¡]>w¡Ç¦:ÁÿKl›Ö7ÚѪìÒ¬¸H¦hä)gô“V“£Jæ­¯I¶pZ³CŠQŒAª}/+`I‚"³ÁÞ(ŠÓÎ^6ó€­B{S$ŽjòMñQSÆs‡–«Q—ÑJ«f¥W\gXFƒ‘Ñ·¯–R†Î¢!?ƒNæBinÓEÖ·6:§Ãð"KxÀ­à9 ÐEþ4ÅîAW’b}Ht ® ‚{餈¸>ÐJ°´SiÑM¯Ÿ-×Úz´ã&QôÇ…íy}xÕóFÁÕÒq{kOyÑ‹³Ü ZÿÑQÛoä3‘,N=ßTç”Ór\–ÝH ë¿J k¹q™Ç nÊ–~DøÇû·é¤V)z¾ýåAǶQù¤7…á·_å0J«ÕŠò/jñ*íˋӒ‹¢CγØÜ!)nµv¢bïÊL1‚íヴ)ÜFªWÍ6%ÜZs›£}V¢}œã …dû¬ê]‘D'çØû¢|%jBXaV¤y èç. ÝEÑM‹î¤H—eô èÎ×XÙ*Ò~3µñ±Þ„šê5‹»Ã¢&½»Šxëb)ÑhDÚÂîÃRûB®8FÉÑaÆŒ³¤.ݺAî_m ÈÔ¢7Õ·ƒ!Ÿ“m;¿Ì:G—SÐ1R/ÿ6S%JÏ~-¶¤Üëë‚1/:¾ª{ÄãÙ±Œú…2þSJnMz^nfŸ¶îVoÖ#â0ÞûMqÀ»á«Ö⺀ÓÃRŽû„RÐǪ/GeI/Í ·úŽên]r¡01¸-‡e|QV¯”™˜^-³cf`²_rÏ{‰m>0C:\«Séå¿›÷fƸ o6/Ó˜=ßRëRp/ôRùÀ%Å»œsâ%ºJ  uÈ«avìpu¤›Ýõjo>è×?é` Á©Å·È\gïM¼]®¸=û÷Çn<&Àõvä—'‚ëèSW ]ÓÝ7Gf}2^,§‹¤;-Ò ‡B_œ•ãró—AdÛ"ØC±XƒYG!Ôàã5¹fÅèN×埞³’M®—w^ž÷0ÌãÑÙ³£/7ÿë•u<È3Ì'·ïߺV?ësIçÌÌ YTk>ÈYaÇåàÕ5%á endstream endobj 172 0 obj 1407 endobj 178 0 obj <> stream xœÅYmk7îçûK)dz:½ŒÞJ釴†ºPHŠ¡šê;çâ³³ºPúÛ;#i%Ýy7ö^’ œ<ÒŒfžy4zÙw g¢áô/ý.Ö“ùo‚7«ë‰hV“w2Ò1úfÒJÁL3ÃÁÂ{åpæi==žÌmn6·g“ùï˜Ì¦ÿž>ûŽj¾š7Ï'œŒND˜²I?‹uóô„¦•¦ÀÈæäÕ$ú#Ç4N&©úx²žüÑMg’¤Ò´wÓ0ã 6ÿš¢c ´Tª]OgŠyܵWStW¥m{Nƒ%·Ú3À=0­"©æÎéö;l* QA»,jgØä ½ñdm&ycM'ÖÐ^„ÑÚ+‘C3ŽPÊkYXTŠÿ Ê3i|»Š~xÛnB|Nhße¸ƒI0ñÕ„eV¹ö2«½"¡gÞ¹öfŠQ8ï2*Æ+Ý^Og‚WÞ´o©iÀ8’TûçÉ/”ÀÄ x^„4xÌþLh¦ Ǽ,þgSDíFhIÙø×jª®Ú1šùÅ ü{‰ÆQíû®AIhçØEÃ×SuÑŠA-ŠÆ|­p±÷‚”—•@¡ŽÂóôŸR„yª+’‘ *üÙ)‹ÊÖ Åì½Oá+%Ña%=ã܈vCqLòQRP÷†â%Ï¢qrJ+R Ö±! @ª¤þSRHšfSÿ£ ^zÅ åÆl*I8KÒ™PLkïbçÑT<1è?·Áx˜óC?eÊ8Ù-élH©rðuFæŠZ”øZßÒhKé!àdTéòª=¥¿ƒñ2WÌV`È%&ºC]Æ!IƒS„tmrJvL°X0‡a¹Tˆú±Yƒ¤”€yÀؘQ5É‹à¾Yá­ÅúÖæ F­6Ñ“N‘-áW(‡Š¤¬ˆÞåê")¸CÇÑ&e¬‘”L&8ŠÉE°BÐê” -ë&z'Œ••l)s¸,¤mgØm€ ,V%eJJ.gVÁ}Èã¸:,±³„•HjV“%Ë„YO~Cy¯mmè bädà±ÕÌIݾhɼ4—çßÓÚĦKjÎ)QÙ¢Jhð æ ªÿXþ¤à±~VSõÛŽDWC­µJp‘¡N"4º2®àîi¹›bíp#Ù+Ç t[«â…*ÖÑï¾f°r¢íGÙ¸@ñp‡ú|ä¥×q$±CÒ@¤ï7‘àÒž„gƒJÓc"éLŠåUL·WUâÏ"ïËw=2$¨Æ¢/½DªwÂUn§ncªî¤£¸lÿË&ç™Þ§ç:ÙEϸ«,{›[«Üû2ËN³ìvÛrhçÞånx>Z[$3®¥Yî¾Hþ·O²èzGWâÚØdÙûíÞÐ*½ÍÆÌ©]3e`0øa3"·žt)åÚÖ)—YÊøÀ=ÉW‹r‡¼eŒfïÐ:À:õiŠø»… y8ë6x*Ëu¼ðï¦ãŸˆ€ai½.œý›í ™úç•¡òu+û˜Z–Õ"÷¾Ýî ²UOª¯{¸}“e—Yö²g%í0?ôžg1´÷¸Ï¨ößqŸ×…Ýw=.¶}Ø¡ow¹Ý›|¸?®[}x„ú¡øµÄF†ike'”Áîñœb·ÅÃï¨ãΞUÞhLÙU~ÑSåo é7™ß¥Ì—Õ±ƒoYÔzÌãÁ‚Ùà•>cÉ8k¼ëšˆói†îÞ^‚²óÜZ¦š®]·¨;èBk™[o¶ÅNYôh̶e;‹ºì ‹žÞ¬ñˆD‡w(Qÿw~Ú3Q ˜JÇžëžDÞ—Ö½òZ“ý(m%à#_€öE‰¶¾/Âæ7=jÖãÂZú‘Ò}±–‚)wXFŽm%áħ¹­<„ͺ-d*ûÕûmÙÎ~U(Yn*ëÜ*/'³|#xDÆÃ6”އŸOR8?|À£Ði9$ Þý6ÝáÁNw뺻¿ðÝÝŸFÒÝ_q“îþJÃ#ßRÞ|ÖG¡(瘎(-Kì9àê'Éd½šÌóÍ*¶¤×uaœØb Ï/2¼ Zº\‹­º›§^ÆÇ#z‘î} *SVïH•ëWåñ)¼Ø:%}Î¥…êxX=SEóLšÓBxµVA²ºÒ¹-:Õœ8ZÔOÑË„âØç}BGíNYa30%Þ$Ò”%Œðœµ,ÏY*,i•é /Á£!A^ÁtçëêÕ+y.­&¬tc®5®›jdõ¨–ß^Mã×ÀÀbrZä\m-Óôû%ê~©öðø­u<0[<¨bc5†iå{þÛH†¾ž$lÊ»ß4¼é¡áÝöÕ8˜¹Ê²rÁ.§äEIW»™:Ùˆ»Üx(r¢åÈ/D{æ€Ùƒ²v|`€ƒO…þ†ïÈëð³ƒe²ìáàÇû<¼âúŸ7$O|ßËׇãï^ÿg%ø˜SÕkúX3x¼–ÝÖú“(–ùQ«ûùäôu)¬endstream endobj 179 0 obj 1899 endobj 185 0 obj <> stream xœ½YmoÛ6Þgý µ:i˜¾¿è—®–aÖÁÀ0´ûàÄq´±ÓØnS`Øoß%‘”,¹QÞĦŽäñîžããü)§„åÿêïã‹ìàOFóÓuÆòÓìS.4·Äú¾ 7œO`0sN¸”X‹³^f‡¿ç›«íIvðWβƒ_ðãÕ?Ã×áëü»ìÍaþ6£¨4c~ɼþ:¾È_MqYž3I„Ô<Ÿ.²Ê–[¢`1žsÅÀÆéEö®xSN8J¹.®Ë‰$ÚjhÎJ0L2Å…(.ʉ ŽJj‹ËÌåZ(S|ÄÁœ-‹@‘R¥ŠZ«ŠÐà¢ÅGŒ&RDGHÉqÔ›ilB, ak¦bBY1̱9k)|1ˆªER°6ì’]µÌØ(¦’Tì52Æl£Q¢V :æ r£ÈtˆH3 ¥…M‰”IX "ë á¼"Òÿ€&`uË‹ßâ³GH¶ncJ ÓŒ:¿½£–z(NºŒBØV@BR :‚ˆFR2¤ žö¯¤ûúêñ A-éÈ»í°QwWÕÅÝÈ’ó¶ù7}Q“ìyÈ¿E…¬ ¬x_„Ô¹oBz澬×kØDë„Q:'=È>÷0ÔU±ÐzZ/&]ñ<Ÿ7«õfý^«6u9\:¯{z/Û6';ƒûÊF¹„s×a\ô|žxÔ´Þ—#¶Ëø|ÊLfÙý…ýÕ¼†\¯>«š\(|ÿ1 5}]Èë©P@­Æ™Ðýuîû"\\\#»A„Æû5! =äÙ!rŽH¼Ÿ×%³O^ÇLñzïÖ[Ö„mTr®Ä}ûS,C–ýðtèŽéøuo1“šiËn˜¿ãc:€ŽÓ÷tùÇZ¢v™ö ó¡EŠ52³xª.;ÜѮÙÏÂÀÙN½`dÂ(×=À%ûïYl›ÐV(,æm»;|¹n'J̲`ƒ¯Ó »2ªéPq‡lGäÖøŒH-«ø£\Œ! /H5A6‡v¬ñÖI^Ý8 ã­ƒ’ö!ßÀÓš(ŒD,›½··(›c¨bÙçãNú¶ËÚØJÊŒgqûþ½wö“¸Ù^á$ sºøtZÈ;²lcÒÝ5Õ&Á^”BXJbîá™ 9ãÄð”ü#CųqÞz¤Ëð¾)yoÖ“OøÚ ð¬KœêøÃ>âüv²dYÉä£Ð¥{ýoZÕ‹¤ÜEÀ,ç¶½·;·žä*»pæš°æ/ݳY$Pl{0KÜEÆ÷+;æ€ì¬Éº3:^üù¸j¯Ü÷m˜Ç£3³ êžŽƒý¯ 9¾±o΄ӛ¿/o_ÿÛ{y—ß’wÇcÕ õKϯLpFŽ"à·ÙÿJÌŸendstream endobj 186 0 obj 1785 endobj 192 0 obj <> stream xœíYYoGÎóþŠŠÄLÄ´û>¢¢8‡"K‘€a¯Y[øbm–¢üöTõ½ëìYÀ¼DÈÞ¦º«ºª¾¯«º×oJXCñ_üÜ;žmýÉh³8Ÿ±f1{ÓÍ-±~®ç†3¢›3ç„k@@‰µ¨õh{¶µý{s±¼ÜŸmýÕ°ÙÖÏøëÑ?ÀÇöÍW³ÇÛÍ“E£3æ·lâÇÞqóh·å “DHÍ›W³àk,Q°o¸bàãÎñìYû¸ë9J¹nßw½$Új¾ìÀ1É¢=îzA•Ô¶g¸ËµP¦=ÂÅœ-Û}X@‘R·¥ŠZ«Úoa( D!ÛyQÛ‡!•Üi‡Öz.‰ÓF'±’R¶'~µr‚EE? +„pŠ×+ö*Å+ðC8µkÁgÚ¥Ï2åRPšZ#ñ&@b„mO³Ú+:â¬m/:ˆÂ:›³¢Píy×3"©pº}CcÄ¥J›¿w~A$ÉsÌÃàýž)"4\æþçÏ;;ô”ˆ ÿ;ë'”IÑ.Á)  ¥‚•í¬_t~ÿ 3G{லÞkôR¶‡ø 1Jk`A™‚ä¯Ò›ûg[Ë·hÌÈѪÔèÙîâÄetm9ý>À¤8g·^3Áîe5àÏ~'‹ïÉA%¼Rt0é`™ J9Ûìü6ÛùæÙ¸ÏÜû¬Zq0=îD[\y߀¥ª¥þ'Ägu1‡îEXðïW‰ö]'¦‚y¾‹ŸoVÐ"8 (ÕíòšÍ“µ|á$æTɢ̕OÅ à` óƒIùµ sW¸(úÊna#r0ª†ÝcZãâ¥þîðÖkֱ˫û ïE¿¡Lø5)‰xk&|¬8 •Ã[ó6¤Oäq‡Ó@|gá`^RíâÐcu ® X¬óŒ&ÑL2oÿäë°¬¾Àƒ «¥{˜Sî”/Õþ”³8Õ‡¹>Ó—$p| gq#`Öi [Ÿ†¾ ±ù ?ĵBÙž&}š%tv0¡iñOXáÀuØË«®åRâÁÊô‹l^f¨ÑUÜ…¹šŽQííYJÆ®:‹GǰÄÂÇ;3èIÄB 6ö;&$‘¡ß )ãÒjfÇÏ ­j(ÔÚëf™QÅ,ìKøäÚh'SWÆ·"Xã­õb!¡ñ:­…­{1£œHÜÐÔ¡#f„Qˆ' !oaŸCw÷˜6¼’ízµãHèÞùS˜¶@¬tƒ°j]  ,8„.h˜fÔyr „5zÚ["Ò(ÜÇf%¯]»@7œƒ¶^:Ía'0pR  =oÑ<×|z×õh“ò¨e­`•)lÇþ ý˜‚KˆµaOé ‰W;õË9žú†o£,¦ kO—·ÏL½Ž;$/ 2ø&´ð‡i4·©8Èîg‡ÁíCf´5hñs1o{–³u¾]~È m¼Áµ´Rt^Gc•= ;QÁ½Èô~? V*¸'qDZFá"Žâ´ÖÕôÓlGäÍ”†Ã¡¤".S}ž†z¨ÜÜ-–í$<Ï:kÛøéèšhÿÍ¢­¬±[Ñ9ÉNÖeÙëk”§6áÓ÷© ÷„gõ°@\å6ëßœ§éáäI¹‰_§nØN ç¾È•êp@C$Ó_ðV4=÷# JË?MÍ¿Dp[Ýéhz`#†ßÉ­‘;¢r# 9 $§!Ën~ºÏ#Ás-]åËàÊëôÃqNwoð;sµ9Uê¯Ì§›þËÓß”ê?q9ít?™ýöͶendstream endobj 193 0 obj 1951 endobj 199 0 obj <> stream xœåX[oÕFîóQ„UUª õfïÞíC¥B¤¢j¡‘xh*D“"rã$ õÇ÷›µ=ësâ“ćÀC+2ÙÏå›ogÖ~WH¡ Iÿºß;G³çJûg3UìÏÞÆë BÚ«u£•ðE e£‰¤žz°9ÛØüµ8Ÿ_ìÍ6^j¶ñ„þ{ðûCüÚü¹øjöh³x6“dt¦’Ë¢ûµsT<Ø"·ºPVëu±õzÖÆ£Š œéB;…·Žf–ªZÓªöåeU[ჇøªB`V9mLyTÕFDie(O+„«½qMyHÊZ6Þ–{PQXëKK«N†àÊ ¤hlù°ªbѺ)O²Âqk¬ º|ßyöƤV;km9O± ñ¼‚©¥*²ãÖ‚‹F•ûˆAkaœ)EU;!´®üPÓ¨ƒ]HÞ ÀQÞ•_§Ü¼‡ÆBB9†3RŽô1OY#E£ÃÐÛö<[úÛ!x á8X Ì dk ôàP6$Ä&KmýBeµ(4ŠU*k›jå„ñuÞE97+ Xj€-¤¢k]Î 2ʺbKéM±uŸ‘æ^Õ&lð´lŸA>/•Øx’Ë]²sRQý |çäÏ$i¬ÐÏnŠ£œ“|ÈŽSH9"ÞüH.T²BA‘‡#?%¥¤@š—]jn{}øXQ _Ò£µ ‚?Æ P¡Ã¼?P='NBÃF¸2 DËù7á¬'¼¥C“0•¦Õº_®•ÎÅÐî>'Ÿå1ÿ—ÒKRâ%ê‹¢¾¢mŠýVeé ŸWlp·/®ë6ÐRbp:á×UýoSÍp” ¶ã®f”{0m´û0ÿfxh½L†€’\˜/€@nu:n¨˜üXˆs1ïq Ó»m¢C/óŽ(Á˜ˆût¶u/ÁÜ[ա͘NªUÉt²tÒÒ $ítàZMlÑ2·Ÿ~(0Æ2Àœ›w‘Õœ(ïlJ«¯\¢"Ü$úeç}‘læd½Ä"“ŽàkêNµÇÖ,[Ÿ¦@¢O]iÂ&Pûu£‡†‚d2t‡•Œ¡Rút€s>6}œéà~O¤™„ùì¿m™Jô>:Ú£·‡°Äú—þaî»ý)vW*Æ­fxJÕrgÆ–lTüÞ‘ÑmƒxÅU’)`(’0 ŸìÒé`î'ÓÝ9~´5Ãìú¡›Ë çÒ¶s¹¡ÚhðY†B¡äô{ÂHFÙ¤‰WÍb”°U¸zò '¼º3GAÓšÓÍ­º3€¥Æ— Ã;ƒ2˜~ðä}{e Ú %‘(€G OÔ.´°4ãÁcD§|£k4‘uÄ  Æ¶·Ý}Ãxp+F0ÓTy%cª—¨zƒÃÚ[ÀMÛPǯ¡‚Õs]Dyá(F\K†N*ÂũКLsýGàÔAŽkàYØþVgd.‹ò®oÆ÷ý'ÚQè#–#ò¡!‹Ÿ‹(tÙ£FôûËå·©Ɔ®±áV:x0¢Rtí:Ûa[Ngœt” MÇ€-‰`àÂ"î%WÀ{¼(XúÀR¦š½³˜Ù.”ÿ´&£¢–ÞïÙÛ¯]ެíôkÜ͇YP ¹?éݱw4yÆ.<–uÉk\®úÅ×ÕáHô;9Ïl猷¿ë,F3Ø>fé~RÔ¸å™ÞNù#ïn°´Ëz{„¯êeËüDŽš¥ÁQ\â+S:aWQß5aâ!ZúNr—\àþ ‰No´åX¦«-g ;Fzͳn0œ,Miô6ƒYãÕg3VfT"¥3¬ìDÊ]?›ñ¢;í~­Ù,ñr©ÿ³y:ž£E{'åSì,6(éÜç¼Äõ *6¢1t‡ÿOMçÖŽoãí€/yía£nìòLŠ÷yÍdÅ^ÜgÅ}^Ûz;ÝÃQ¼<ëàI™v»ÙÌ|Ñ`š˜§} ¾…ñ–#s:V02Z{7kùÞ³ÄÈ€¶žµŒ”L2ÅÔ¼ö¥ ØG&ÖKÇ,í³ô’ŸxÁk',²ôzy3%óŧ¿^_“éH®(I0înîï7”¤q¢¡ßK%Ñ#%ù‰¥‹AÃï»`éh¤8Lëåî¤÷½t3ÀÓqYp£§¾j­°‡ûôák`3ðK¼›ÁÜ[äw’ž,î[éÓÏnݦoÝ}¦ã·¢ï¼Óæêz…pFD‡¹öZ¦çw™Ürv®-ÉvÉ<Q<‘–ºYž@Izɳè1¯åIµ]ñö•3†µµšØôЬ(­“þ‹Ì«Å•¡â®=`oFêz6RÍ?‹4x7^UÿßFÆKH[,½¹Ýd½§¼{²Xô´öväê3¤N"àº?tü˜Ç>*œµhׂvïgbÒSÎMiÓi°‚O&ÞÑG­ø”>·÷CQ0iÄ"6´vsòÓc^‘¼Í—xk ¯î<¯&|טÞø—Ôõ©²ð!u²™•5&~y6ûM0¡ûendstream endobj 200 0 obj 1858 endobj 206 0 obj <> stream xœ½XÉnÜFÍ™ù Fñ Bªwv'ÈʼnŒ(H‚8À;YIÍH²g9äÛóª7r6[9‚€a³º»–÷ª»ŠzW²–—ŒþâóxQìÿÎYyv[ðò¬xWJ#lký\#:Á[S6XÌ“®„€µÖÒ®ç‡Åþá/åÝÍý´ØUòbÿGúyþÛ÷xþP~V–/ FJ îM–ñq¼(ŸOȬ(¹j¥2¢œœÁ^ÚVØ(…æðq²(^Wu#H*LõWݨÖXƒáQ Ç×BÊjQ7²uL1[]×pW©»jN‹댪¦XÀ\«”©4I5³VWß`(¢TÃmCÅSˆ™Z)•lk«–ÄÇP-LË;S5´SðΊ®zENsƬúcòE«?|tÜGër#áˆaÿQÖ¢:….¥Zƺê¤nx5ƒÉêói­ªú¹$ÙÖHÑ2®i(È]UÝÒè¢ö‰@×`ö¢–¦uV 1ýAJz'üuuO“«.ÐÄÀkos–v‘5¡a9N\ëŒà¼´Õ ¤È9ì6À’°áøŸ¯I·ƒ TœÄÎY.¬÷û8H…[˜:ç‚uZK¸sÙjíl9ù¹˜|õÚ;•éà¶&µô6¼ÍŒD|‹A˜• ºÿ`R ø›7ÀêœôÒ¬wã}æÀS°G‹»ŒëeZ{‰þÕˆ0;ï!èÕÃΛô²ËäðU--©‘ÕÍIRNË5…!ÖH"¸fK gìâ´ªú§&È…ëp}JC=I5DENöhi˜Âs²X8NøPxþÍçž;Jô›')YŸóƒüSU‹$a÷¢°ð!-[ʯÈH:IV¯ñþgMŽ®(º䑦èTËŸºÀk m·Þuž”rçÝö.œ…„‘Zxz¦Ë{IÍ*rR-]žÛÑ¥™¸¸HÙÖ"ç›|FhÙ¯µêy!¿•í¶' Åò °™xqÀP“-¢ ú敽Íä¦d—"œàƯ¹¦5ÞÊžçaYù&¤HÝVäÌKwA\9«Ü0·Wèšç¤ü»¶] >ây0)PîZ °l,¥÷» ¥´3¸ïm[r#êȘ*ŠºÁ¤[WËjJ¯X»Cy.Q÷lÒ¨H•A©n[¥— eÝ#í°Òs"ˆªˆÓiE¨ôÿÖ¼…u+ª}?Àœ²£eȧݶã†3糇Ê+“q)mB)îZn• 1hæ4èÊ›úùÌØ†èY×í~©Rë$ÙEEÏ]ÕHºžÌ#õp¤‰Ê©N°OÀ+G ·Xj©,ÁÈóNf¿$>Ý_„‘v .ÉÞæÑ,Ï^ÑJíçÑm§Ñ€É•p3rãã݆œ4f$;"GM¸HÈ5Í–@x–aâA(GÓ™0Aû©9å,]ÊIx´¼‹¨²£6 gyô>s0ͧçM+Ým©æeŠ¢A±Îö\gÙ}–Ý%Ùxö6Þ„ÖãnÜ]yãhm³ÌÕiÏÕ]N7Ðr×Óò, Làv|þ ZŒÎ6ÐömO[F>mÆôtµð2Ím¼ ¦¶êäE3ÿ5‰Õ¨¿&Óã=Ï£éòÈ#rÝCgF\6ãCÚC#ó×´ÃǤþoá[ö”¡óŒÄírÖÒè@Œw øîÿ4mÈG’Äj4tÎíœ%üáY2>¤-ØX\8Oq±uôaÆâÿcN׫õÇCïé–;´e;`É¥ÇkŠ.áëéIÚ|ò 'õxùf÷²«”—ø^êëË–¦ÀïMMº‡Õç$ ¯–«ÆJÉÙ{xNŒÇmS‡­ì£úôäÌj$3bÇ“2l\X/‹ÿÂŒzýendstream endobj 207 0 obj 1398 endobj 213 0 obj <> stream xœÅXMoÛF홿‚‡![p½ß=º5P-ÐrzpeE6lÙŽl¥)ô·÷Í’\R²)›ŠäÚ€´îμy;3;Ü9g"çôß|OÙÑ‚çóûLäóìc®¬ôÌÇg•tR0›W˜,BP!‡€3ïiÕñivtú[þ°\Ͳ£w¹ÈŽ~¦ãßÄ×éOù7ÙÉiþ6ã¤4ÑdÞ|Mùñ„ÌÊ\h¦´•ùäCVã¹gÆd.ÆÉ"{_œ”•$©´Åç²ÒÌz‹áY `Z©T±(+Å×Üw%àJ«Œ+®i²äÎêb† <0­maHj¸÷¦øC•î/ë+žA̵4ZëÖ¶ñzM<…ji™p¶¨h¥ÎKW¼#Ђs¯ÿœüBÞjøŒADoHÆ:&=‡à^N° ¸(+Q\ÂPqµÀÞ×{[Oº-•ÃSiŠ¿ñD ¡RµV6._®hþ ͪõµ¿E3߉ùº¶3/MmàðøœVÊú÷YEWe3`iÁ²àu¨UÌjj8w°$ZÜ&nLBˆuweí©/–·Péi…±:ÚVî#ˆ¿rUF üÞ_b](fLðùä×lòÝûZÍ$Í„#rpN'’VL2.óᛤJ3]'…³Ø9©ã>ôÙQù€à*RÝPÎ* Ö*ßÏY¡a ñ퓲ÎÙ; „?WØ*€0Jk˜Õ<¡¼AP"~…}Ò%œ4– ÛMníÞ§`]$YÀ×›ø “[QÁmgÿTꀨ*„«RJÖ°¢áE2¼±…Í(.Áñ§·ÃR눤 _‡¨G”TâIDæÀˆ.’ÍUÍ¢ÙVëRŦë¥ÖÜ?ž7eeµ Š/}sMݨB]A]†† šµ|diêL×=~TÑŒOçÜC*R—›!¨}¬ŒF½0h Ûê‚“‡ŽUW¸® ÅÑ,>'…lÚ(ÄiX¥ÇÓºì©âß$:Jyò×fí ¦·gݼézo¤yk×øžÝ›Öî÷I$[çdoÞç^@Ö„|éjõ<=_n¸L¡{×LŒýuûøSkºKÄUvít]_WãÖG/ˆÒñ±5¥F‡q=ã®QŠVRméÙ¦ó]¥ <*»rãДÝ.ž'áíú!Ý…õ ¹ÏÐ×õkp÷zrX²Å!ÈOÑÙôzº—~ò9²Ñú£å<0Ùêd§hˆl¼ž¼ÎY'Ð <:ëöM¶>Ùã)"¯S²9±CsmÁõx††¸æxÝ~’`†^MF±}‘ÈY¥Ñ¼GXÓ©˜=2;žf}P¯Rž½`F…æ0\öZáþ2ºtJ³>‘ÃÒˆ§%ºmDŸ'l¼›|9¿§;³gør€M/_‘¯Uâ¦kSgI¶ìøâ[ùR/çk¼›|Y7ò.tG¾L`&^š_]’þÓKÜÊHc™ÝIã} ÉX½Ÿê¶ýÎM{¼"¶ÅmíÒm»Ÿãá=uשÞÇUçj·ò‰ûoŽqTMx›ýšV›¬endstream endobj 214 0 obj 1356 endobj 220 0 obj <> stream xœÅXÛnÛFí3Ñ Š!Ûj½÷KÓ¨ƒh yHúÊŠcIJÙÎúí=³K.)ÚTLÅra@ZwgΜ=³â»’3Qrúk¾«âà/ÁËãËB”ÇÅ»RYé™ÏfÒIÁl9Ãd‚ % œyO«‡”Wëëeqð¼ÅÁoôñøÏ_ðuøkùMñä°|VprZˆ²l¾«òñœÂÊRh¦´•åüu‘ðˆÒ3ƒ`²”Fã|U¼¨žÔ3IVi«õL3ë-†¯jÓÂH¥ªU=S,pÍ}uQ®´Ê¸ê”&K–˜ÀÓÚV†¬†{oªŸ1THQéþ²¾ã%Ì\K£µnc¯7Ì ¸–– g«­”ÂyéªçZpîõßó§”­FþÀDÌ6€ä–yÏa8B–‡µ¬^×֌sW}¨R ÒGìÊb¬ªK8>â”Oô>‘ÉE=œ E¤"›rqò-}“§]Ñ×vO–1•dˆ³b¼·d51þË—µIS¯éãÿQ˜ïvBxÒ,KÎS Ôš’!ªóZye«õªÆ¼àuˆsŽ0ÅH,Ô•%)jįÀÍë M†CSõ­kb](fLðåü÷bþË!g }ˆ@ëû4ÀALý'šâǦø‘5™hiXÂqQ­ãÿñÉ6–\õ-¾÷äNòè¾E$"È‹!$«%l⥠¼ˆuÒÂfp¦lªª³®Nâ¢fuK<…¦}ÁÙ8¥™*òÚÔŸˆCdƒÑ{·¥xQc½=‹3S ö¶çˆ>h󴊵+›C†ÓæC)ÝÑЯÇfÀjIÀžÌ  ó@àX©“ˆ9œ±Rj_ o““ô '–«pÓ­0*@j<Ñqô(Àzò§ ¥WÉ™”LOq6¦°JCNƒµÊ÷6e!ôÕ'%õ ­â 4ƒáJ(PprtÂ:Ù³‘² 祛á±Õ¤ÎÐb†aî9:¯‰o#|r±çZ¸Á+Õ§Þ‰ØR·ÍPñn„CØÙ¢b·_éG ™èŒÈú©ž&U õHêSà¾íÉßÇ PÚ7Ý Í¼·0`Ÿ¨‰óÔÚ.ÒfBÖy[OR¡¡~Îz[ÝÚ FI&ƒ¬eãe­ò¨«“ÓlëF¢}Ú 4®ÒÔ-Ï(ÏP‘(naoM wË…í&·q/ó‰Ye[wŠN‡ø`“[Q!mgÿTj¨f¨V•:gx•¶°Å%ÒTz;,µ‰Hº0чs9¨M©¨w·¶7ÑU¶áþhB ·Æë<:Înp±2ÕfÐ"·¥MÖ;&Ô}”NŽª>÷#5º8¬DÓõcL‰Œó÷Ó»ùÞ"ƒæb“]ey9Ù,¯h븟e]@ÃCïÀå[%mê¤$Ž–yôq³:¢mÑ8´.yŒ-íÿfÓA®ð†ªLoǺy‹Í£:8 m\ã{qÏÚ¸?f“l““½y7ën óØ´N­c?7ÜÊÍ~Þ4Ü[«}5/ÿÜIwwzÖéP\4ã§öñû6ŸN)®{$·k›þ:ÉÛÝ¡ô§ìXék¦Ýw-}ÜÈžNÑÙ\ÑoÔý“ n›aï¥möÁötŽFØSßïH¶ÇÅ??§‘ý&ssGÇ=¾š»Š¹?b§Ó1«âAäÙ)¦âëjâuÝ»`n­°Ñ+<§tþŹayÄ{—Õæzûe¾¦§9—ã_ÖíÈ—•LÓoæÈ×u榻§.³mÝñÅ·ò¥îÎ×ô4Gø2A>ˆHÁLÉîŒ~êÛ™‘Æ2û’&ÕôÜFHÒ^Þ¸mÔæ–7pÛ“œŽí¶÷žÊ}ÕÛÓÌn§£T_”+­¦ ³â?1“endstream endobj 221 0 obj 1552 endobj 227 0 obj <> stream xœ=PMOÃ0 åœ_ácrhÛmê\C ‰¡H‡i‰ûúÿ8]7E²­gû½çì x„PÞ”Wƒ©_0Àö`¶fI¼Œ½Š:B¡ÒaL‰(¼HÙšõ¦îŸà¸?mLý hê‡fÏ·šú;¸1ó&Rƒ£$Li5À,ÙFŸBBÈæìAåYÕ;öBófï%Ÿ‰ýu,>`Ãvï*n©Ôví*´ר£«È.]ÕØ¯¾K8蜺NKIãÜF1ŽÊÈç•Ï3ÁÜDóS§–!Û¿+°uíHè½çG½‰H)ø)ŽG¡ºPb/œòZ¯É=F¦VuÕX‘Q\÷Úí\yæ®#•¿ô×—ªÈ̳Yèû=`•endstream endobj 228 0 obj 292 endobj 4 0 obj <> /Contents 8 0 R /Trans<< /S /R >> >> endobj 20 0 obj <> /Contents 23 0 R /Trans<< /S /R >> >> endobj 29 0 obj <> /Contents 32 0 R /Trans<< /S /R >> >> endobj 42 0 obj <> /Contents 45 0 R /Trans<< /S /R >> >> endobj 49 0 obj <> /Contents 52 0 R /Trans<< /S /R >> >> endobj 56 0 obj <> /Contents 59 0 R /Trans<< /S /R >> >> endobj 63 0 obj <> /Contents 66 0 R /Trans<< /S /R >> >> endobj 70 0 obj <> /Contents 73 0 R /Trans<< /S /R >> >> endobj 77 0 obj <> /Contents 80 0 R /Trans<< /S /R >> >> endobj 84 0 obj <> /Contents 87 0 R /Trans<< /S /R >> >> endobj 93 0 obj <> /Contents 96 0 R /Trans<< /S /R >> >> endobj 100 0 obj <> /Contents 103 0 R /Trans<< /S /R >> >> endobj 107 0 obj <> /Contents 110 0 R /Trans<< /S /R >> >> endobj 116 0 obj <> /Contents 119 0 R /Trans<< /S /R >> >> endobj 123 0 obj <> /Contents 126 0 R /Trans<< /S /R >> >> endobj 130 0 obj <> /Contents 133 0 R /Trans<< /S /R >> >> endobj 137 0 obj <> /Contents 140 0 R /Trans<< /S /R >> >> endobj 145 0 obj <> /Contents 148 0 R /Trans<< /S /R >> >> endobj 152 0 obj <> /Contents 155 0 R /Trans<< /S /R >> >> endobj 161 0 obj <> /Contents 164 0 R /Trans<< /S /R >> >> endobj 168 0 obj <> /Contents 171 0 R /Trans<< /S /R >> >> endobj 175 0 obj <> /Contents 178 0 R /Trans<< /S /R >> >> endobj 182 0 obj <> /Contents 185 0 R /Trans<< /S /R >> >> endobj 189 0 obj <> /Contents 192 0 R /Trans<< /S /R >> >> endobj 196 0 obj <> /Contents 199 0 R /Trans<< /S /R >> >> endobj 203 0 obj <> /Contents 206 0 R /Trans<< /S /R >> >> endobj 210 0 obj <> /Contents 213 0 R /Trans<< /S /R >> >> endobj 217 0 obj <> /Contents 220 0 R /Trans<< /S /R >> >> endobj 224 0 obj <> /Contents 227 0 R /Trans<< /S /R >> >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 20 0 R 29 0 R 42 0 R 49 0 R 56 0 R 63 0 R 70 0 R 77 0 R 84 0 R 93 0 R 100 0 R 107 0 R 116 0 R 123 0 R 130 0 R 137 0 R 145 0 R 152 0 R 161 0 R 168 0 R 175 0 R 182 0 R 189 0 R 196 0 R 203 0 R 210 0 R 217 0 R 224 0 R ] /Count 29 >> endobj 1 0 obj <> >> /OpenAction [4 0 R /Fit] /PageMode/UseOutlines /PageLabels<< /Nums [0 << /P (1) >> 1 << /P (2) >> 2 << /P (3) >> 3 << /P (4) >> 4 << /P (5) >> 5 << /P (6) >> 6 << /P (7) >> 7 << /P (8) >> 8 << /P (9) >> 9 << /P (10) >> 10 << /P (11) >> 11 << /P (12) >> 12 << /P (13) >> 13 << /P (14) >> 14 << /P (15) >> 15 << /P (16) >> 16 << /P (17) >> 17 << /P (18) >> 18 << /P (19) >> 19 << /P (20) >> 20 << /P (21) >> 21 << /P (22) >> 22 << /P (23) >> 23 << /P (24) >> 24 << /P (25) >> 25 << /P (26) >> 26 << /P (27) >> 27 << /P (28) >> 28 << /P (29) >>] >> /Metadata 254 0 R >> endobj 6 0 obj <>endobj 7 0 obj <>endobj 10 0 obj <>endobj 11 0 obj <>endobj 18 0 obj <> endobj 19 0 obj <> endobj 21 0 obj <>endobj 22 0 obj <>endobj 27 0 obj <> endobj 28 0 obj <> endobj 30 0 obj <>endobj 31 0 obj <>endobj 40 0 obj <> endobj 41 0 obj <> endobj 43 0 obj <>endobj 44 0 obj <>endobj 47 0 obj <> endobj 48 0 obj <> endobj 50 0 obj <>endobj 51 0 obj <>endobj 54 0 obj <> endobj 55 0 obj <> endobj 57 0 obj <>endobj 58 0 obj <>endobj 61 0 obj <> endobj 62 0 obj <> endobj 64 0 obj <>endobj 65 0 obj <>endobj 68 0 obj <> endobj 69 0 obj <> endobj 71 0 obj <>endobj 72 0 obj <>endobj 75 0 obj <> endobj 76 0 obj <> endobj 78 0 obj <>endobj 79 0 obj <>endobj 82 0 obj <> endobj 83 0 obj <> endobj 85 0 obj <>endobj 86 0 obj <>endobj 91 0 obj <> endobj 92 0 obj <> endobj 94 0 obj <>endobj 95 0 obj <>endobj 98 0 obj <> endobj 99 0 obj <> endobj 101 0 obj <>endobj 102 0 obj <>endobj 105 0 obj <> endobj 106 0 obj <> endobj 108 0 obj <>endobj 109 0 obj <>endobj 114 0 obj <> endobj 115 0 obj <> endobj 117 0 obj <>endobj 118 0 obj <>endobj 121 0 obj <> endobj 122 0 obj <> endobj 124 0 obj <>endobj 125 0 obj <>endobj 128 0 obj <> endobj 129 0 obj <> endobj 131 0 obj <>endobj 132 0 obj <>endobj 135 0 obj <> endobj 136 0 obj <> endobj 138 0 obj <>endobj 139 0 obj <>endobj 143 0 obj <> endobj 144 0 obj <> endobj 146 0 obj <>endobj 147 0 obj <>endobj 150 0 obj <> endobj 151 0 obj <> endobj 153 0 obj <>endobj 154 0 obj <>endobj 159 0 obj <> endobj 160 0 obj <> endobj 162 0 obj <>endobj 163 0 obj <>endobj 166 0 obj <> endobj 167 0 obj <> endobj 169 0 obj <>endobj 170 0 obj <>endobj 173 0 obj <> endobj 174 0 obj <> endobj 176 0 obj <>endobj 177 0 obj <>endobj 180 0 obj <> endobj 181 0 obj <> endobj 183 0 obj <>endobj 184 0 obj <>endobj 187 0 obj <> endobj 188 0 obj <> endobj 190 0 obj <>endobj 191 0 obj <>endobj 194 0 obj <> endobj 195 0 obj <> endobj 197 0 obj <>endobj 198 0 obj <>endobj 201 0 obj <> endobj 202 0 obj <> endobj 204 0 obj <>endobj 205 0 obj <>endobj 208 0 obj <> endobj 209 0 obj <> endobj 211 0 obj <>endobj 212 0 obj <>endobj 215 0 obj <> endobj 216 0 obj <> endobj 218 0 obj <>endobj 219 0 obj <>endobj 222 0 obj <> endobj 223 0 obj <> endobj 225 0 obj <>endobj 226 0 obj <>endobj 231 0 obj <> endobj 232 0 obj <> endobj 89 0 obj <> endobj 142 0 obj <> endobj 38 0 obj <> endobj 244 0 obj <> endobj 36 0 obj <> endobj 245 0 obj <> endobj 34 0 obj <> endobj 246 0 obj <> endobj 247 0 obj <>stream xœ]O1ƒ0ÛóŠü €¨ªJˆ…. ­ª¶‰ƒ2p‰Búû’:ø$ŸmOtýµ'¹x§^ˆÜXÒ³[‚0ZbeŵUqgyªIz&º›ôï_ 0¿Ë âYÕç¼*·r³— AÒÖEÛÓ2þ“öÀ`vg}i3ªý‡’¢©Äq“«%PÌMs“TÀ~ÏxçSН`_SDS¦ endstream endobj 25 0 obj <> endobj 248 0 obj <> endobj 16 0 obj <> endobj 249 0 obj <> endobj 14 0 obj <> endobj 250 0 obj <> endobj 12 0 obj <> endobj 251 0 obj <> endobj 229 0 obj <> endobj 157 0 obj <> endobj 252 0 obj <> endobj 112 0 obj <> endobj 253 0 obj <> endobj 90 0 obj <> endobj 233 0 obj <>stream xœ}U PSW¾—p¯Weƒµ &kMâŒ;…–¢@ɪ,†… yˆ‚øh€)¯ á!b!Ü“„W ¡­ E­KqË£»RºëB±" Ý­î®­Ö­³ë¹™Ãv÷íLwf§sæÎ½ÿœ{þûýßÿß% W‚$IF¾+.n§¯ŸóùÜZ’{Ñ…[Çz‡Å±—n<àæzîÅe³«¡í9Xà“V<’Tëªå¹êâ|Uz†Fê™â%õ ô–úmÚ$ ÉVæ«R9Ò] M†2[¡ÁA–4.7E¥ÔK=·fh4jÙÆ:ÎG‘]à“›Ÿ¾ÝË[ªSi2¤±Êe~¡2U–›£‘F)²•Ògè|žÝå¹Ùj­F™/Ý•›ªÌÏ!Â#'Wž_ ÑêÉ)©QÊ´ UV¶Ì— vÑÄ"ŽØCÄ{‰}D±ƒ¡Ä¯‰DNì$"ˆ]D±–XM¬ÁT®8l"þB®$‹È›.ë\ö¸üÌëâýÓõ W½ëߩר ª‡§7ÓI´•3ð9ظåv’ó¿ÅãŽÀQÙZ×:˜™ý»câs·NR¡´÷b²“Ósðò g݂ǯ/l@ë‘òBë7L?†káÏñõ²YPàÀî®o ÿÖw&“·½Š^@< ßAWLpw>%¡Çž#Áá/ˆèÚÛ”‡v¢2”†|¾C+à:Hô68%±L…Vo"´*æ1¤`Î~nûÓåâô ~‰Kóí 9?n¿¹Ö†É*ôíw…aKÅÜ /ÀÍ­Ÿt|õÅõ‡&Ÿ[‰Ñÿcœ|ô9\wÇÉ8?ÑlnfÆtð=ÿÂ7@j¢ø`Zù _÷Uü¶¢¯bX°1‰¶³o‰µñ¬ÁpÔˆ Ÿ(îÃ-Ýpõ¥{íMâøfUèeÌ`úáxoia˜ÿ…?vgìI WÌò`ç!€bºeŒBbº >O…Ñjô<H—ÇP_Ð1èl­¾¦‹âν}¬»¹SÌžcÏÔ¯ã5iù™5E€),}ûýFÐhn•à–ê¯pîä×s<ÎÊE ‚é(ôA‰lgV ÖXzMMÆzÉ4ü+L‡¢Û†ÒÚ* E~x¬ïÌ|Ý•±~?f‡ÏÅaö^Âì½»”¹¡”²‚¢ŒÒlQ¹VX¥cØ48_~—mLƒ@¸ž^Œ¦îÑ|Ç«O9Êð±­BleÉá€òTK›A#°‚¡š‘š¡¨†ÓˆDYª×3å9"ÖhlÝ MZÀàñ™R¸_L€“ÎѶ~ëéqø³ó×zoüˆ1Ò†

t0yAÕÀÀÖ`#Æ3IŽÁvò[n 6aÁ=YÒ‰õænýl²ñµƒ.ÃÙ£­×„Õ¦¬¦Tà ‚Bt› ½…;œ:üœZôX’ÅS¿\júÿ±Ìm{“ µâkp‚ ùa~Ê4aÉ’Z ×mrjxðŠã—‚º8€ºM£äů7èû\4Nµô¢“Þ9˜ÏƒcŠŸ¥ÇˆÖ§î½Ås˜œpZëÞqÂIìŒöŒÜʲâªOÛ@$Ø—©HnþØÍÓØTsFöýÄž ðâù5”óà)¬r]"£hä‡þ#X Û(™óoƸŠñþò>|Àã"[::"VV•Â,k8Rñ¦° Yz­ÈeÑ*D|'Ép†>1æ~¡‹¶Â[»FŠæeös+Å+\;Ü–_­ss#ˆÿtD¼½ endstream endobj 39 0 obj <> endobj 234 0 obj <>stream xœ-Ï]HSað÷¸Õ޶ìV„µ½7’‚ÌÙM,ú’µ¨¼±™Á8;ÛNs;¶· Ò³MÝdz/u; Î$² 7º¥›è¦0‚.ºê>¢ûóê!è´ÓÅËó>ð<ü…ômˆ¢(ƒÃ9|wÀöïÛMº(rºœÑR ·öÀ¨£þùv\ö“ÇŽÈ#G‘Ž¢øÉY?1æ|~÷0½xÀn?߇ÏÙlv<dÃãa§[ð³A· 6ãx˜g8V˜Â=ý‚0q¡¿?‹YÝÁˆ•û.÷öá'øñ6†£¬ñ!ßtY¬á¬ZqðÁ‰I c'ïaÃ!„.äõ!t ÝC÷[ç ½Ú|¥’î$i¥PÝ^¥>“:Ò­DM¥'¥ø2ÐR¹,å!?ÿÔ¢üÚ¿:·’^œ†Sb"!f Sš±h‹Ä»N¸UJÿ¢“ëä š/>ËÔb)W,Â-%A> endobj 235 0 obj <>stream xœ¥XyXg·Ÿ˜Œ ¨è|ÛÎPµ*ZѺëç µ–UÅ­. €(;$l’°ä ûö¨€[«Xj±*¦­_£¨U»iÕ¯ÚZk­¶·=ã}éí$é×öûÜ`žys–ß9çw~/ÂÞŽ"/ÿ ^mþs2÷¼€{ÁŽ{Q¨Æ2®ê©)D#í¼àºÔ™sU£`ËhB(Ä')½âdâÈ=·©aîn¯.Z´à·Ù³f-r[.Ž ‰só‘D„džHø‡·õña‘á™ÛÔ%IÂâ™3SRRNâîf‰ÎÃòË+>6!I.vóß.Ž#âŸ+ã<ã½^[%N\-IòNN ‘†ú…í _³{히ÀÈõ¢7Ælаdʲ©î+¦m›4Ãcæ¬WÓgÏÉœKˆ5ÄDb-1‰XG¼LL&Öˆ©ÄFb1ØL¼Ix[/bñ±Š˜I¼NÌ"V¯oÞć˜KÌ#üˆù„?±€ „Ä‹E°Ä0b8ñ1‚XBŒ$–NÄ(b41†p&‚ˆ±Ä8bAKxÜ {"™øF°APigo—h÷¡p…Ð`?Ûþ„Ã8©CùyP4WôõA6cXçp‡áÃ/Œ˜6âîÈ­Ž„ãfGpZïô٨ţÒGÝ1úÓ1ÓÆDyÏÙÑy‡óí±Ùc{ÆQã¼ÆEŒ+w†v¢ƒiýó?2þqû¹7¸*'® ÁÞÈ9êmÜN!|ÄÝ¡‡SÅ yž2îßç%Aqqm¨†ýž¬iCû÷'¢¶ì`>ÙŠíbÿøZ‚¢Xœ Ëè²g!«ä$¥!‹$5H} Ë\,¯ß›`ƒIÈ͇nú‡ îE«w„KS™#¨&Œñ&3öò[y‹Çp_¨õ ¦5­¼ƒ½(ƒ oòa_×£6*Ái¡¢¿>EZü¥!Ô(øÆi&áèÃæ ýŠD2#aਗ਼…l„|ýÅ•­¦%õlOݹ“èêêڛ؎Ácq= ¡0Zô•ÁÏö] XLàã4¤Ás¢Çºy‘[Ãýg³¼7•¾2 Œ&ÐóÙm‡ÆÌzÄ%fMÅc°ó·ÓýõÛïÁ™ÁÛðBÚËÿÓ÷?¾pùòÇÞÓýWx™ È\Qð¶ Îô ¹8î&]‡šâe¹YÊ<&_¡å+CÕ† Ón˜Á«±/ØáçÁ†Ý¸ÿu{2’g¤å¦° Ifrkò«Äˆâ³Oa'‰ÒPÒ>m:VËt‡¿ŸßŽ(ðG0²òg“u ¬arÅÃ'ãç±ö‚]aX×ñ†#Ù½¥Ô72L®Ò ?‡¯v 7Œæ¹h8<ÿ&i)•DÆ,š/ÊŒî\Bz|ùÉ™GmOt¨)*%%3ê5ÙD-E=ö™ñ!vâÆÓû'Å’‹V'/A‡Û0ˆþü^KÎü0þ³Ž¶Ôë˜=TÏ\ø#™‡’øØ»¸ú‰MèMVCOú/ÛtF“õÔËf#¹zxj4sBn @«…|ê`g­C ÉsÏuLÀu‡–¿>ÑJ‚?¬ŠlBȵ5¡ªƒÔùZN*ä6ñæ -QäwÉ-Øè &óZÓz³;d¦|mŠFyr™oÊje\¾ŒR“›Áèð®ãÁO· û!¾_Q—ߌ\ßB…åºK‡êεñÛB“Y¯_¦{£0ç(ªG:Tv„²f±ñ£ ×R¾4³áýià—øùièõ„Æô¦ÒÎÂã•h4úB­¦iQ3:ˆ:ŇãQ<Š[[°.Ï?eKªï´šzí_kîwœ/9ü>£‹ê)8Š(ƒÁ‚ìÞ”ÂÒ ÖçÍ/ÀäPiDêv”¨µ;;Ž}ðëApd­3Ä4ˆ`ºÃ!›â -å2ðÉ­˜´ì'‡fü1ò #ðt~,tˆ´B v;”ÀÞç{ØÙAœø¬ôB«ˆARøÒÔeÏã.þ¹Mû+ÌgšýÌßP8fÿ÷ „ T¼ñ•|‡¾o“ä4kÐýŠ(ž$,öãguìãó·`^…¢˜í@Ò[‚O|ðA÷‰÷Nwî ÚÄîÇiwÏݵ%‡Ž4³Íµ•袾;4'Ès‡;ûLmrÅŸ7þyõ+þÿš[n 2B¼âŒÎwLàk:iznl&܇sôÙŽgÐê+Ï[x8ƒ—ýÝð€Àfz ž{ê ~§·£Žøædžœw¢U(®1²nok:/a.è.ÖåT'Æ$æ(óÃd èĹ>TšÝÂŽÍÌÜŸ¨“WP˜j§=!î*ùí‰5[·îX3sˆË¿¹'€l¾_ÎrÓ-):±8%E,Ö¥´´èt- ^_°jÔ_q&mº¦ÝšõT¸M 94Q§ÎñóBÎ{PÁ'(BäÌÖ®À²ž…–/Ÿ³öЮR{<¤>ï¿Ä×SëóZâ’*Å(žÚ¸sÍ’y^G¾ÎeÔµêúØA写é¦/,?®eÎ<ÆK7‡+ÿ¾{yç‰üb6옴x²ARº«BQZu½CîyïÒõSaó«™"iaæ>«ˆ³0Y« Æ›ÀuPƒ€ëŸ%qÿ2J¡ˆb½ECoÞƒñýŠm6…Ÿg…`94êNFÁ¯³ÙÎâ>QtÒ`ø·ž‰“üD·Ÿ>±¯Þ€‘üMýÅï>ûÈÀ‹Åìô<”“ÍFF…gñìé6ƒ¿RN‚i?üüdÿñ,ŸfÖ_¡ƒBÏ~ësǺù/]jNéžžϧ”ò¡[ÆÙÓÚÒŠ TK5¦j3”ŠÜ|ƒ…¯£}EwQ“k}FuZZ†\‡5£IѬC,¼ä¢*R”(•‘*—¦WähU,Pþ˜ò“«rrPº«´^^SV^RTÊ€ð’Ú· íBRWY­¼¶®¦º¾9ÿk´y`H+Deȵ¦^Û¨UV䔲âÚ ûCõf„Ÿºó4’Àñõ§£­ÿvÁžd”2'šýÍWSš}Oúpên&Ûzø§ –èYZi˜@Vw ŽÎó© 0‘¬F¼É`ðD?r®ÉõòZ}y]U‰uÓö˜àà.³v ˜ .üWàŽÇc_ðˆo"?Àxðep¯_—ø#¸ƒû¥¯^½4»ã©~ØiÉàZ¤Ox<<ç¸/èZÔ—ªÊÉT1ÒQ›6奫“ Ð^*µRÞÔÛu¼°ˆé_9Gd]R*ë’™CZj :O_¤‡Šñ›—È|4°¬NÝ€FþàcH k´ï R@ÎøÒ¬ì—Í]r(¿´¡©¦­QYš[ÌÔœî>dDÔíë[ç.]»fãv'àõY9ùù<™™Caà ÙTÊoZJ?ø?«äD«,«ÊÏC°Qpå”ñ+à ýs·çFïuþs¦Ÿ©)ÔðŒÅ—•£ JŸÖ˜˜œ’3÷/8óí{NÅ_™s”ùèhÛ‡è}êú µpé¶•Q-ÙuæøêHÃ8z©°Q}={¶ÇINP²» Ò òPJAn&Ê âô¨Þœ7—ÃwàÏ_f¬3jÒ³”¹9 F­ÞšˆHU¢,Oh—òT‰¢öf+ÄRI*’Qé5µUe%åŒFÓuÌ€ÊQin™¢-¦QÞf¾î·V–·46×ó|oÙvFn_„‹½Â£ ¤s2Qo#¢:¯l·Æ¦§_³ŽØ°»n}ZÿMv*Ë# ™ˆrÕr)…—ö¢!~rÀ?‰œäZΫ–kI,+‡›F0Ãíeñ#‡GŽ4t$ˆÿúA€X endstream endobj 35 0 obj <> endobj 236 0 obj <>stream xœ•X xSÕ¶>!åä0UAŽ´Š9EAÊ €ÈP£ eh™JiKç9C‡´IÚ4M²’4M›¦£€‚@G&[ÊT@QÑ¢Ô§LŠâ½®ëÔÝ{ßÛ¡ òî{ß}·ß—4é9Ý{¯µþõÿÿ:Æ«#‘HúÍ_8/h’¿çËhñY‰8¼øœˆýWKwN_(…^û‡û4 ½£û y’‘J$Éé¦ù‰Ié)Ñ‘Q ¿±aãü&͘1m¼ßdÿ~sã#R¢ÃBü–‡*¢"âCôKœ_`bXt„"ÝoìëQ EÒk'ªÕê ¡ñ©S"gï§ŽVDù­ŽHHQE„û-LLPø½á÷è|}˜ŸŸ¤TD¤ø-O HI`æÕ¹ A‰ó“6¤¤*”*uhÚ¶eéaá+¶¯ŒŒŠ\»6.~ýó#fŒ=kLöØ9ãÞxy¢ÿ¤ÉSæyf3ƒYÉŒbV13™ÑL ³†YˬcÖ3AÌ<&˜™Ï¼Ìl`0™f!ãÏü3‰YÄ,f–0S™W˜eÌ«ÌræMf:£fú0Ï0}#g8FËôcü˜þÌÆ›y’Ì ažb†2Óhº/FÁ\”,•8%ï×çŒôE©ÂkW†×Ç}G÷ÝËŽdkd2ÙlÙ n—ÃÝë·¡ß¾þ|ÿ˜Ó¸|5P?ðƒA“åjöžé}÷‰MOt>0˜Ü5dèÀ!{ŸêûTåS8´lèñ¡Èo回žòôyÑäÝ 5øô qqµDLèxÍáP7…UCh¶’Èžû>Æl0ƒ‘KÚ eò&¶ öBÙV”úàÛlÃKî(§ú(øžbËvB½lÆR¡‡GóåGJ[Šš8+ëHs‘â.ið!ñ¬·xjÄ]’÷p8¾ŽÃ¥¢ ¯ñ?†|áù-s’²å–cì>CÅ6y4©Õmz¼d‘%Úfù¶ÅUÚ(`²ìæÙƒ'ŽºAr²[ëÌ<øèÒƒ@ºGTKöw“Š¢Û°©Ømµ‚Ó·N Yò7Ø ÈŠ #+|ȳ¸<£.Tà;ÍR2Ì.­€‰¤™èȵ­Å_E-øSv?º«ðÌñÁ™ÄP®¬€·À÷K¶´jÆ¢|‡à-¶ë®áí.É^V¬'¬rTò8}æ 2Ìœ=™¼B¦Ý˜‡“pÒÍ.œ.'ùd2Oøúó«pûd`ʬ×Áߨ¿'ºïKÎáXi÷PÉ òS–!' ‚‘ÁqÜ)úkúíö(e½Ph´ç;¡kA5­ˆµÀRk_YûfÙ,àˆ‰ &H1ãS„Åüë'Ýï\Šf'G AÖÕà«]øå5ºÝp\MOÁ­ü;ÁPF®9Ö¸Š,^¹.5:RhÎrEË·?¬ËÉÇê"Z½J\ûë÷ƒ•ô 2”ôU¤k…ÔJp@çÝ=~µ‘œOHÅ?‹?ñ®R°A-Wo©Û$ïY†æeÄn¨7oÚá¦ÐÈ’ô8ôÜ©}s{÷Cz7+–U@ô"˜ÍåÞÝ<Ðt„|‡K~‘|ƒc¤˜ƒçy¬`÷V:4g»¢RË;Økð™épupT(’=€XÏsc¹ópýñ½ë—yÖYd†õòeI·Ðdq´Kîߥ‰ò•â:Ìàáîg­TYm»¸vY58Óçé ³In¹Ð‹àØÇÜü¦â ”¯?–4ÿ„þ•Š~8‚‡ÓñéaMQ…¡Ek\aEÐÊÜ_Ôz©)E¹KîÒÛh}]`+¶ØŠ\§i6+Ö•é ÂJb­ÉÀm!Ϲ¡6¾>UhŒm5œÑí1ÏnS¸!<$°ôô&¹Ña²çÌ9–Õ`qÿ`ý06BŸM«¦—-ŽZ½ 0¯ì¤Ûd/=Øš4ËüÎÆÿTÿ1\o—'÷’ÀoÙ5Qvy¥Z²K ”ŠQâDÞQFQfçv§€F®bCA§ÉIK:}Æb§¡ÆP»|SYM $šÀìÈp@O߲нP¾WzyîE®¦wÍÝK¥Ýaâ<Þ´;â`hMY땳Cˆ¿fõ«xÒ'¯ÖP·4 €,EŽ&„Ì"ýfb“¾AW² 85›FÙÆ”ø·ž¡>¥›wÁNàv³íPT^r îË&Z„V«Oáê#dr馒HGÚ1à>dƒËíj ø«Õuáý‹”^žÆ™ž|…ãe'“ñÖàMÁù‰‹äª£ t`(\e͵æ9ŒNŠ;ý9üαÚ÷;U³Rˆ’E‘r3pzî­†O]—ÛõcÙ#ÃÿÆO¦Ð¤¦–¿ àÜm•ÿ–Ðâ:)žB=/àB—ÛC9¾µjšÔ­l:h!Kc4.™š¡xŸŒU\›­¥òS®€/‘Ed2YŸgÈ7B®¯ÒC«‡)­ÚìµûoàPŸȨ2µjÀ÷[VµEù†â(é¢¤Š¡Õ¿3Ôºîgzòˆ‰î>b¢Jx¬­mÁÇ¡‚ÒW´‡¾Ž®&+goÖçö ¾Ôýv]p÷aâsa<ñ MÙY¦£Û\…ûâGÕéã>/êÅ[Ðã;à½GüSgٹٓz]쬖4‰‹‚ÍCi®> ²åJ6” Q˜Œ¯‘dã"ÎÂ;¶}»õûÄ åÁÀ%³Y)œo7ØŒ®ê™š«2éLz_mLÆ–µŠ2Óh7[MÀsMÚÜÂ…ö|¡X{Ê\ø$t`ÿ¢Ú±”½›=€Ø|Œ‡’ü6s)g7»ôùfÐëåšMÛf7îŸÿÂñÕê3㛷ØPQ´±6Þ@EcÜ„2Ÿ¼vã |©þ=kÃ%aw9ÕPÝ. ®à…+’½â©8[BÜFɈ;rÒÁfGAÄö}P¿ï ìšY*?ïë³ÍFÈô¥-U)ÇKli#4·ÄABð:3 ›Ù?V˜Fk)½Šù¿W¸— Ô²-‡ƒqôl!@ÖlØ d-n8tØÝvXØ^¦ox$BdøUž |N‚:%SaÖ7î|ú)|‡^{êõªZZç"ºÙË'q¸G¦y G©Tœ1|ÝNë;ȯ¸AÆ‘©¯O"ãÉô»3qRËÇþ‹Bm‰ÓnpšöXŠò÷Z¬9O5I§_´Â ¤/ho›ÎsÖ“¼ý\õ§7ás(_eŸE9£Qù¹xÕ#¬cÄAVÝIx—ÇÍóp.)'o¯$d)Yq`–\Ã)*'·H3OVF|s‹BWâ* «'MIV Þx›ö¡¤ çwInx4(‘²óÑßÙ9%ì.8pa_uNZµÜ™k7;€+W…Ð&ƒk´3¡PE¹‰{ƒ Ì / 3eª(ÊÞ P+o¨îÕTêà3,»ái¬DÁ£©5<ŽgqÒwq¾4î™ ûãíqü¡E(žáqX銀Eº¥äxc­s;ÙÖ…ýPÒÖ…+º$‡q(Úâ¦;|$dA–;¿ £vÓj³¶'¿K™€;„SgœU6攕Ðuf§Ù\‘£ÐY`Üav ù;Àæ¡â`m„bÓÞõ[ %S€Ì+ n‰’¶C8Ÿ´Â˜š$MÞútX qåë?H8“|ÉÒÜ»ø<ú“@žò±?`jéì´·~ô‘=bÍSx€pЍù/eE.",ĆùÁGí{¡Nxäa=¨ý';fóÂÄ,¹ëÙÿ¥þ¥Å¢Œ{Ÿ{à6~è^ÊÇfæ… ›e±®ìfù ö(Ô´Ó×Fá iyŒ É?þ‡Õ@%Jĺé:ƒi K±N\Î+Ëëà wýº­áô±ìò ÕR…à°ÛËËoúØŠ<Š EkJ邯•Ž à&“‰*²bAóæ·ÔÂñõíúké§³kµj—¾FÜ˯˜b¦Íkx'X®u›iäÑdÒh¦ú˜si¯˜@õS¤Ã|Iuʼ‹òò‹ß]‰è5ý«1u½ž]|ûH°ÍýmâW|OÓcp›dG½LG¨Zîøƒw;Ùr®lãØM¹¸¾×ü_Æ~R¼ˆ;yœ€#Ý%v‡oššÿUT¦Ò@¡"£È3>ø}ï*ªÇ‹SÕ»åO²öÃø4™]©¤]¾GÙ²Z¨µS_J\ ¼!þò@*ð8-{÷ÔGdõзôL“KXB¼ ÷îrqúãJ2UF"ñµmø²8¯ãåªí9x¯±ü?´í·ÖüŃ»K@7«÷%ín¼kbGÊ3¿ÕJ# …-1q u¬AÃýË‘êës-GKTë›M¶X’…Ù²d«e¿<~¦Åd΃|ßlTÈÝl5X­En[ø·î÷û»P#n®–`ÏŽ/t/á•FPM.ô·M µ€Ì²íúBj6¹JÞV«µ¾àŠíšõŠõÇUø„«1‚R^߃½ˆêÅWToµx»ò;Ù…ßÞ–´¡.ÀRü/<Ë[r¬i¦­Æ7ÓG“>” Š’v M6j¾Àl4æ¦Åf) Ë=±î/Xxðë_,XHÔËë–®—‡®1ÃlXf[}xõõmšóð 4¾[º—{1Ÿ ]ý3t}s¹böóY@F½ä9B`Íî{bá½ÝsïwÑ7)žïñç I;Õ…F”P¿a+uñ±Ú­NjÈ+–í6Ë·W†j¬\14GFÂv½|I^˜*!&&BaħÓL§’/[QTÖd²çÓã?6Ŭ–™ûT§¯8=lo¢bX"Ç'ËO^|P6çÆèjn~%¿½4¥Z¡µêí#Å\ùŒoÖ숆­°4V` Zý±òžøA—„Nç,AVÚíºÂ¿®l“ÅbÊ“oL µdS+g¨AÐP®\[žMg_Sa ±óTadhÀŒúâ)ß„~Êá€ëçÎÁ%îË…Ÿ0a.0gç¼ÊpybÚÊm™Y™šèm°Š{™Z,r_Ÿ´È&Mü .À±J»­ØN-Y5×K-VÊeó:`~òÎŽú–ŠuáËÖm‰“/!ÏñçŸYÕ¨XgÉniþ–}ØRSê¤ñý·_áè¯$纓¥Ýiø'Þ}Ú záï2V¿BCC‰ÐÍ’ ÞuøÁð÷¾¬6ôÁ•Ÿ³;妴 ÿf›P4P>&¹#J¤¢?E¼š °Y“žjÔC&d–hJ”åqµ[€[¾dCF¼%TÑÿu€­¼ u‡ƒ®ºr]­f¯òà>n½ÐQi5Ùb¯ù5°šš:|ÒçSiIÏ$GÏ&s€D´“DàLòRMšÍÓûUlE ”ÚÁ¦-–]]èD-`û—Èu^,pبæJuI¥£¢·Q§R,ÄanÏhçáçO7Öï©ÙÕç8:ÀøCb1Dȳ 909´U| ´6c1•O›Íálmo¯ìîb‘rýÆœ•Ró<Ñt@R[M¹…žy»ƒ­·Zw ¤?™Ïÿ±—eìóß#ÆPz¢[4âLdÓ1Õ-¼?û#òZ mÓ ·fQž&ÃÌe—ÐRTѹÕU8ðþUœžÇ8ƒR0‚ÌÄ—To™=ö¨êêºÎtá%úF;vàˆËiÏŠ?Þç3éB†üèÌ`õ˜ KöFµÅLéì Ÿ»?lí<ûùÏözh‡ueHœSAãâÈË+'ádÔ…W©$Ò¡kþ'#H Ñ’§hbÂa„Å̺Nx»Kh(?ÊzSO–ßæ'öompç[ ýÃ#€ ˜Hƒïƒk»$nl“¢ ×ò¿Ù\Ìj#>uðxÊÞ çHEU÷\¾°¬àäjÓ«Sô)9&9ùú¾yð<ÊSV©wìqí,¶Ë=¤Ù%~ãq¡ÃqŽ”ŠvüžÇçu$“h€d<$ 3Q¨BAN4¤Ÿ º;¦zÃIø»p¾°Ã^ïºõ'ÊŽîivµ3^‡u°fÖ˜’uþox±µC—Xún-b>'Eìö§Ä²'DoÖjåé™ÛÇš¹ôdCBd#”¾Ýè(Ú#ô”Î’e{¬9ý‹€-lI3 };mÒ‰†_(ÏJðô“^¸Îë)B÷ðñ~ß‹#·Œ6Ñ[*:ÓÅÒj+!Õ¢¤Uz•¥Ü5¸¼´eoy™oç©Î“p›Cï)È1Q«áå9†Í‘鋎-õ)Ìõ> endobj 237 0 obj <>stream xœcd`ab`ddd÷ vô541U~H3þaú!ËÜüÓëÇzÖnæn–ÕßW }OüžÈÿ=N€…‘1¿´ªË9¿ ²(3=£DA#YSÁÐÒÒ\GÁÈÀÀRÁ17µ(391OÁ7±$#57±ÈÉQÎOÎL-©TаÉ())°Ò×///×KÌ-ÖË/J·ÓÔQ(Ï,ÉPJ-N-*KMQpËÏ+QðKÌMU€8NB¹–椕e&æ¥ Ë‹sR=»˜Y~tðýœ›¼àǺùŒ÷~|gþiö½\tö¤þIÝ“»'wLªšügï÷u“:»;»9ʺ++åÿL`¯ê®œß×Û=i†_éÂK§~WœÍö;i:ûf®ÍÜr\,æóy8—Ìâáb^”¢p* endstream endobj 17 0 obj <> endobj 238 0 obj <>stream xœX XS×¶>!ää¨BzêxÏ¡h«ujmÕZ+N­Xh«8^QA†H$! ó¼Â<„ a2 JQ¬#ŽT ÕÛBª¯Zkk'm«íó¾}ì¶·ï„AèWß½ïûà#gŸ½÷¿þýkm„³!ÄË|ýýçÌv|ôâÆ ¸ NÜß„™XÃYùˆÀE.ÎMèMèGwnhÓ(B(ÈcÓ–Éwia¡2¥ç´íÏ{ÎY°àÕžsgÏ^àé)U„mŽòô Vʤ‘ÁJþ!Âs­|{˜T©ñœ¶H¦TîZ8k–J¥š3S®]üü OU˜Ræ¹F#UÄIwx®”G)=ý‚#¥ž}§›Ù÷g™\s[¾8ÆJÀcÚ^ÐOÜ'ö_-þ¹ÝB¤àHÍ'+êùóÇðAÂóo’ÕPæX’YðrŸ$ê¡‚ýg‘Ó? ½|åÆÁ;U`•í̉‹gr|×$+Z 'ëÙÞÅýáP¤ýÖB­PÔeÒ\ÍMÑ gÑM²7¢’i/Æ9 ÃÁžÕŠÿ:£„œÞs™‘¨ÀÒ6›MæItÕ.¨ãv ¹¥<¦!8† òc#±_ÅtUdûÓ mL?¸&‰ñ÷Æ0 Xal5ÔBÙžÞå­È» í3—$ä;Xy1 a±˜ÔÄðë×B5ÛAnÂ'D9dfC‘Äš²ÊdÌs—›•¶3™**‡Ü€Nˆ:Ȫ:~s%¨Ÿ|Ý Mìy|'_™§k‡±íWRe¯ÿÚ`Ê«¡ dÁ†6<,?Õ_FhƒÒqœS ]q,gP¶þˆ Ð'䥲(Büéº[xòÖ)°4Òª­«°•´(6,¹&C9”õÙɈå¬ä(^‘…Ý6M·ò#Ÿ_I\tm¦’øìxU JˆÛ¡ „T |·íÝßq» MÉgJ°› ¢v¤ ‰¦‰ÚIÓî|èç¡v³Þ^o<5ô¯÷Mt¿ß´“h8ž†Gáy¢íƒ£hX[qÁÞFnw°›HÛÏÿîÉÛûRÎߊ‰ž¸‰Ž7Ä14òù«”’*ˆkÝ –zFÒ|€÷–ñC¬…•èþš° or¾,þ‹9ÌKmçöÚ¿úÂ[†ÃBÒ5icsÈŒêkZõL”6¦þé*l&ÑDü(?²!g,d+$(¢üC³u9`((†rª^S¥Ø¯‰Þ»½ãþa4¦,ŸybÅ—»QÌ!‚´- ÒµÉÙª4&=A½Å¨W–õ|{̆Äh¼u?¤°Yµ¾¨:keãåIˆ—¼ƒ'¼„]~˜‚<»÷§Ê~V'u£&» §Õw ÑAND'†¦D¥GñZN>ú2f&×)@ÔÚ>¼VhaëÅáqý`npÎrÑqYÀ쟟P¬,—¤¦ÓŒP¦âbS^á—¨ÐxŠ2<Ž&Ÿúe½¸ÅÚ/™µä6ÈÔ§D?É‚Ozù~€ïߎӡ og†š Wø³™KJ:wn3oÓg` õÍ ÿäiï„vÛ)î¼\¼6pþâåï|zç^ÏÅž kýûc=áî7wHäž}¬Çôç›CTûìЖëT'áøqôyn ݤ Pá}²Âû,î‡ÆõÇúë¾sÄA(‹ÞK:î8z ÖïÃ`½X=@ÈÕ?MúS2Ä@äÜÈm ;äŒn¯¼j'P’ᩉudaªíëF«í‚2.GÈɹ£tÙ@Y4éz2ßNõKÛ#ç]=ý´9§0¥V )|ÕWA2_õ·à-¾¼SBANuÚé œçPË_ÔWálPÂÈK-²:¾¾- ”ZòŠN£„üv¾úçžÆCv‘¢Šø÷uPÐÚë÷oY¹çøNv_ˆ.r]ô©mù))Û2ׇàY¹ŒaìÈÝfˆnàýõ}È+ÎmÏ=m¸h8m8™NQOÕºŽ þ ÎwoÞþA\ÿƒà.ÐyGÊøF&*)/¨1èòâlPU†J ­A[ÿý Çi­hbòêA-‚Vn³sB¯ÒŸ‘ÆVhm•A"»Š¬B^¢cƒRÒ„Äm1¥:™Q9‰:05³xül¯"ÐQ©…ªúF´A%}Ë ;ßϰ u~Û‰Vt ¹Éœ†ÎÊí5Á×|æaѳðJǽ÷E@Z¼OàòÑø-ü&rÅc‘ç7·>l´É!9> ’“YY¸4)Œ¿ž/ MDÏ?øåWÛád¿Zv5þ”Þ|þú­#g>8|è½… ×luà¹aE¯÷ Å<$U_KP&æ=žˆ&‘Fh•ñ œÈàIx¢øI.ó]ñ$2d­üd#Ó'ñ8T‰Ý­{9“C­y´Îw‹6139K“ª^!·ür9ÙwìÚ®Œ —6*ör‹zý®®§ôü9ñé 8Ì ¹ $D×»þš<½FñHiœåf¹ÀGnt‘ÙPLUé*U±iº„tñûÊ4m@êXME¼¥¦¨¢¼Ðñ=Žº?u©,|­ñC´ãø¹…ônUmdZFd3™PRXw鿎°Å¥`¦ªâMú˜çVbÅm!öT5Ô9–I²sÅvÁñn´Ÿ\:K#¿)h4vÂÎSñ8ìƒý~Á£‘r¾Æ!¾(Êp1ýºï ÓW÷ÏW.÷<§âi>xøë} çjÿ…g'ƒÜî:í0uzbb#}eC’:[›— rJQ•QQ} pß!æñÂÙâ'Eå¸Ù䓨ôqýh<ý„Úßߥ’ß6Ë.8y5v ?>K§¤¦g€žŠ¨3ƒ¾#÷•´° â¾H¨å N!ϸwõ`ûGG.ÀçrñºŠ]ñðE ^ ±%UZk+mÆŒò”"¦âÈÑæ3@ݼðÒŠÍï­òw ä‘‹ÏE¯Ð¯£%_r«¸Ïh³Î¬MJÏHOc"åÑZ=_¾SKŒ å*kì¹V¯ÒEÅ‚†ÒVhÍe……EL“­Ál‚R(N)O,O°Äí…Ý`3×VZ*k ŠrM*ã–• 7ÊH¬)Û‡w`†;kä.Ãì..Ý.# âRgƒÂ endstream endobj 15 0 obj <> endobj 239 0 obj <>stream xœW{8•éúþVËúÖ—k¾bš½–NCMTH”CäPT(çHŽ‘$¡"¼QǨE¤”J£sÍTN­Jr(†A'Õ¦ÙSÏ·æeïý.š®™ßoÿ±/\Ëw­õ>ÏóÞ÷óÜ÷³x”ŠÇã -\]õtåÿ~ÍMæq_áþÁG8KöF¶K€”øHIáôW¤ã¹¯Ô¡HÖªQ|/„2ÑaFEˆê¸î:ÞàSnÊSþà(~EBXB‚ÍgpÓa>6cËáñ,¹À!hý+cK¼db­¿Wuv¤*Κó`Ílèä‚uµ¦ˆÑ^¨ƒ'ã §ÖÝØËã’€$’Á\[Â+ä,ùœ ‰cF›`ÿ­«6ïöÔÌ SÎF¶$WÌ‚| S̆œÏiÙÒOGdSù2]rÄœ¶ÇAICuR½É‘½'£ú·×ÛA°†í‚’‚‚±pïòFêµM ˆ¯u‡eKiø ÖM(: ¥]…WŽ¿Íªfˆ¦„[x?Äû4H".:I Óo¼FÞ¥vð!Ø÷æ­óìÖÇGxвmoT_pi^­ñ[&öâYéx‚šÏxW?+È¼Ü ÚØ!4 mCQÁÛÂâ2’ã±þè…V08x1“@n7 Êà>'àŒX( Á\ÿ{H(à„ÃvO VšðH¢ˆ~Æ qÞ|(€8ì!D°ˆÆ_âEX‹F48áì†ã½4Ì'˜…}#œIáµÂå éDô fÃv]W貘‹A͈y÷ô| j6@ÍñwH^·RœåÈ•=S‹˜ÆNoüžhèíè¿éð•(2hçÐ=îãßèäfÞ§õ3ÈbÖÉ+Å>õ\‹„÷‰V<·¥{eD3„ÕæÅà¸7g5¨k˜Ðà6䔸9víÞ]š‘ÎÛQŠG!ûCó³í4JS§•¢3¨:ÿü{"óN¤±_Ë•‚ÏÍå X§ÓÁ9ŽdtÅÆDT±ÚKÌõ[µ…Õ·Ä)ÍküV'¬AšF®íoºª?Ü8½{c-Aûߣh¿ëâ‘(l®'VKò$E¥–$V︀õ8}àg, ÀȨ}tvH æ³!M‡4¡â×S½9å%š¹'*ÚÝ—¡1LuÉì0M„ÁÝÎFâeŠ|n:7“ýÿáb¹*ì#ªÐEc ~#ðåï`má'å1ø1DÓ;ˆ ʉÁWi·K®yˆÑ1†Y<éÇ¿T5æÜª»w‘¦³(!#.$,:6jw$b̯‚h<=ßx¹2:¤tt˜G:« 0á:‚„Äjò;ñ÷ÑG|/d'‘–Ú®j2;Óa~½í¼Ï“”¼˜¥`Z 㥼3€êùœ>„³ètF‡ÿmß;ŽyDq1_o )Hcp*(Ý­/;þ8¥i…»íÞh¤¹Ù·¥½aÔ²E7¿¯G7P]pÁx ÌG,À6ØSXÓbh óÀkO)ïW"Û–r½Ó€0Ž~Ô|ð˜¤"}ÇiQ³01kó·É9–Úb½eΆ&E’'zWÒ—ä&í=|øÌ7¨}x u~‘û{¦\õ.Ð ‚÷$îG“¶X(&zz‰—†}ëáëöÛõTÏ»Ó 6­’V„›Ì–¢ãûËÐaô]Z&Jº«a…œ·…îÜZ|È1 Í-t 6J"Åa¾È¥¢Èœ°â­î›½P$cöv%¨€êÛÆAŒ#Ñ|zçzt3oÑÁqÉŽª„jļh}Ô-¦:éOÀ¾l ûѾ¾G«/^ 75õ ÷_ÆÎl)õëM‹Œ-O^ÍBM]â?÷$yŸõt€×_W%;!"¸'Wƒÿ¿+i˜®K¡`¦î>gÝìo•Ím¨‡y‹yÏð4N¶{ ­ /WŸVA?=dé°D ¦ ¹ïdiiï„ [»FÔ ´ûI |0”™°úúýô¬Íqï ÞˆiáÞÝçÕuùn> ›Ë®ªZUl.Ÿó3u¼ }j|ÄÖ_JlLx²57íx”d{é&äÍØ®²ÕõÕËm3í0~¾ê§„»H4^ý cš6_‹){~¿)gÞQçÂøý¡Çöd‡Ÿ@—˜Æ[·_=¾¶isµHEfBªzÛÆƒëÄòX™ÛOÿiä_6 ýn_ÒŸFøÅ°‚ܳvŒŽÖcb°§¡œ0èÑxöpë-†íZ`Šð§>ÐÅÑDƒUd1u²/F<õ ý™DÓ!_kÚ.Zt&‹8_ý!!þÆ ›L$X@º}†h.y"9Vº£bM0’ù¼ïzÈù2/Âcsü ¬¼Ò=|u (²Ó*;Y O߈Lû§ý÷AEÏ£ŸØÈ9ý?B•?,Gþ¡Íÿc!ÉdAëâæH}l’*·N´/å†-l› Æ´nŠY²[¤ºÊݶ&âÍî*OX¬a g iØ@–÷ú¼+yxffß ‹úþвÙ³A84Cã™|j¸í%ÿìãUõ¿ DZ½FFåÂ(¬.8OCŒÿë3ùxŒþ%ýÞ…§€zùÜ|Ù×ì‰/q OÁãÉ_> jŽOn_ k`A ¯N6‡/³€>öÐ$‘lC â¡A:aŠ=‚‰¹_°'[8úÎñнcôB2e•£¿&ð.ÿ;¼#è÷ý.áó(üå„l_Ú,êë‹B8¨ÿõY…ÓÀY%¸JxÝÄDÊd»ØÐåŽ^XÕOkÏdŽp'LÇš×60RÚãž,‚NT—cσây`êoWÉñû3Ä“ cq{ª²YzTk>ü€’#x:hz\bék0³$,rMÃc}±¢/f\VnÚ$'G6iáss¸ÇlQNît„)‹ÍOHÚ›–œ úfyfeöcT®Yómbü¶ä¨¨lÃÌPÑÌ–y{ˆÌj&Ä&nI<°+'E|0µ*¾gæ9iÄïJNEÛ˜-’ļýY¹…¢ÁæôÐC¥Qº;¿èHnyyÊãôJÑÏöÅ;÷§å!ÍBI~Y~jήlñž›ŠŒ/‘ʪF-ȤX¬'þí%³gŒúè½ØdT×p¥Ü—0ù–Gß;{¨¼¤tOR±è0%3*' 1Ëœ¬´ÅºúTbõÏüíû;}U±;y®QÇûKdIiJÒaâxÿ-2T~x «xyp˜'`5Û€;¬èŸ²öÔ/w¸Qæê¸I|ÎNæÉ(@Y(“ÉÛ•“”°799M„þežº¥¡tͤœ]y…ûss³D##ÃuHy~ùZçE uïý٧Ƿúl rBV¾ú›ÌSÐbd²ß¼Ò¼æ›ÎˆzÒ wÏŸj©lʽ>2Ø×°îÈ÷\l{|}Æ-Ô…î¢ÛŵÙGÊ{{Èñ¥㎸¢åÈÙ¢q+"uÝâC¼QP·§á 锈n>ܳ±´“£QšG:ã,¬Úw-óûf¨«;CoVÊ´q5÷x¿—æàDö$¬&°ç¦µa»?×4Ì£Oïì8yâÈá.9|ùò­›è BãwXÓ®¦ ·ˆò·HÉLËLÏÝ™› ùñx×KÄ ü`fjàââ´RüICš!®Ç)ôó_qyì‰Ö¦³RÄܸjïèëä˜ NÉHG–)Œc›¨Ò¹kM½ì—X›œy°Aœ´òáœWÉ5ÄÓTž¿þý¥Õ›qçù3Ð]æ©Ñ}%æ~V>óŸþkoüÛTþ:IÚ3¦”s*÷Ò¢Rûæ ¥Š]ãDŠ †¥±Ò,%¥®<%eŠú°<ç endstream endobj 13 0 obj <> endobj 240 0 obj <>stream xœmV XMé^«Uk¯’í6‹\f¯mŽK’¹D»R¡‹J…¦›¶tÛ=]E “J?‘[¢¦"·qÉ ±Û•T.Ív‰Ñ0 æœc¾µý9ÏùwŒ3Ïœóìõ<{­½×÷ÿßû~ï÷~?MP4MK }|¬'ëoLjÃiq„ø%ƒðVÝ-Ý#dÊ SÃ#Lß„{`c?ìO14­JÎR¨âÓV®ˆL’›‡“[OŸng)Ÿ^b®TÌCe¢±†¾£-#΄Ë|ÓÚg¸¯ÏÒ„¥²v§?-l‘4ï¨}žï)ÃuZ‰TÌXß o4ôQ-%1ÁÏÃpób 6±‰‡â!oÌ“Wo—á(<“W¸jÀúþp¡¥ã†?6Æýœ|]©ŽÝÐ,þÔL_Ĉm á=¾]=qx°9 ÞSÀòúÅÔ•…½Ü+–ìtACñl<[àp¬,ƒ1oÊ ê»‚/.; ¼h¦ïja–«sü‰˜³‰—÷²ûŒ€¾óÁÀ*lþÚ`¡nî‡Z‰xÈpÿ‰êò¿#®S3Çr¬‹b®jÕ®¢4!¡<·íã¤â}Ôû4ðM+ýs7#æÂC^ƒï@Œ¢Â¼BÄkKûWÑ¿a3Qf^&É~ ìc¥ðˆ°j]JßídÀTEçǸ›äÏ:† :Td±yDF¿6ÓU„¼Ñ@ñAÊ€U>ˆ›æ×ùêá™§oÚ¯‰« [½ODíð"½*›…¥˜Å_<û L믞iP~neÞVîÏX«´°¡“gè±âslPµQâ,gƃ1ß9êÅ©+…õ…-aÝ„O ‰LFœ‡¢úÃÐGgÔ§¥F• úÄ4 ¸ ¦úøÕȈã!™G59MÑ—Â:œwđƤ¬ÿF–4{9 ¸ó {ôÉlÍ­D[ò6o*G[½½²bÑläÖ±éWp™/n«»Ôˆ*QGFñHN ß“¢ÒjX¦¡_“ŽžKúçw5¦Á”m¿Zx¼ªr]v¡ìº$kKÔ%I}ž£…`íè}»g0i*ƒ25Ô^¡Ÿþm÷x gI÷½xýÏw/ñç~p,| ¿ñ`¬vž3Óó –ˆ"‡6€ù­¦ˆh¤›:@ÑQrƒ_DЖM›7•m)Ï?…òÑ~T±i]“Ù*4/Ï-:êpø¶TÄMuvœ²bwTy¬½1%"eQÂîµQ™!HÅ9¾ð)H_6jAŽmQ˜Ì–ÍA—Ê·ìŠ3¯>ƒ¸î›7Ÿž\{*å@ ÎÕ>¹RRY[ë0Ù'-F8‹½ør0@.A.Q³f9WÖç£V­ðÇLÑW÷¯cÅ%hyl¢ šõ²þŸ¹«{{Æu÷çdÝ ÞÆ¦›ÝˆÇñs{¼: gRÚÄ·­ôå;pâ#.ÕYñaå‡&“ê›:~¬SMжl¡>ðĆkk¥å‹*NÛ"9—Eómg¹ì%K·êùxÃy½i>} ̵˜ ÉBP½r—kñ¼â„‚ä²µEñè×ÔÐøøÑ¹¨è“2©¨Beº‘¤)o3Py˜FY쇃ŒDÇî7`”D{,q¢ÑbdV)WtƒJÉÌ€;ùm¢k‡ž0³[0c¦}3 —‰a6=¡<$rL> Ð0ZÖ‹¾wŸÎÏO ëö~žÏú‹Ñ-$\v¤ýˆm—y%§ËÒZ|KüÑt²xu ×ñi^_?xïö³m ”z^ÿò(‘¾·ø¸QÑ{)ó~ÙÉ‘„»Â±ùÚ¥éÞ9+ô}6¹{µ›ˆŽf¶¬ nÉJôÄqYîäŸœÓ ¯rŠC`ª™\Õ{YÀwâc¿ÀóŠ'ÕðeÁ¥¡›Y”·= ;Ý#ïõÝŒ Ü×ÀŒfúÞMéfÀBü™‡]͸«Ç°•­¸Z«ŸÁu—Bqá—ìC¤P&¯^Ã`÷ë˜pez‚JÂÔU]ô‹.œˆ©ÙÛw±ö¸Š·ïê"£§?ÞZöÞ—ÐH ô[Ýžœ†Eà`„ívªÁ0óœ†]~Òãn$Å?Yÿ=Epá_0ª­™ûo8¤xoåÁ†UC0;N!€GÏy²§W4ͪÂF‡&ï²B“¾ðåºÄ—~tŠÙ]Ä) ›n~o†¹xöGãúñ+Qcc²šc%‡ÊË¿Y_$k—¤îÈÚƒ¸¹‹œ,„‰øÇ öZ~Á^÷ùsxiYöºbb?ÿ/|Ü?5½ö0püx5Þã­?ÉA®†Ìª FÇkz2<%½ü~$·«7sòR‹ÏVbî2P§›Æ¯b׬Yº S›¸Œ¼¼4!\Ò„Îï-ÛÉõìÅRoøA¥úÅQ»XÓLCÏ}¦¾…_ oÇ.’Oç$9{ðÐóg­êÎÖ–fôŒföoØ S¾NVñ²cáhÓÎÌŠßOÕwºâjãŸâíê&|TRµ2¯Òðïn扸“¯¸ÖTÓ†¸ï.Ĺ»ùúe Ùy ²×çqž7%ÿ¨˜âk¿ÄC1æ±[AÂ:¯ÖÉ×Ô=?~ñîN@»íáFõé6të¶oµ˜áì!Ó§\ã5úµ¤x4Ìá_i,ÄÖ,ÞÜ3ÃÈ ñœ{\éü‘ïN_;{¿p+ôC§¸8¥LôÚ e%e,Ý-јhûÈL íJM/˜šjw™ö¥¨ÿG—YÒ endstream endobj 230 0 obj <> endobj 241 0 obj <>stream xœe]HSaÇß×ÍesMëÜdÍC‰l`~âG‘èšÔlΨ(ȵÜlÛóØXYTF¨¯e 1sDéB1t‘]D5KÖ²fÆ8A F÷uÑóŽ£ÑD„ «çùÝüŸÿóÃH™ƒ0ÆŒÉj³UÕ¬­%´Ó9t§‚ôÒ_K.Ñ(ˆFù$“Wž8¿Néc¡û–Ið‡î—ÈF®ª®®¦ŒÛ[YYÇ5zù€Ûa÷qV»èâ½v1 Î&8ܼâ \¢è¯¯¨ƒåvoW¹è8h,ã‚nÑŵò]|àï䚟ȳ{yn½[ùú0 ^·È8«àä>„Êgvò®6„Ž£RdFÍèªFLö-¤DµÈfq >‡iŸ–Ih§%h‘tL³ÉžE9·ÅÞéôï›VÌÜf’ã_RËwO¸õrLb´ôIÁƒÜø„——0›b÷“PÃ($rnË„Ix LÔÐ0·R»z˜šçUÙ[½ øš€ëð”Ýi-ËXØFyVåy|zÜFÔ•&ƒ¬“u †ïó/bÑñâ3ÓÛYr•ôxüÁË]½"QŸ<ô ò¡ð[,›y£ÅZZM­ÿNà‰?*h,™êÿpñµëmk¤¨wï3Ê[eÝR`¦ã#O_“¡þ±Ar§o’ u¶]sÒü¦”êá8;þj†Œ’Ïýw©7ü¬uN§Áú¯¢£O4›fîi4Ò°&¡¿cP*' endstream endobj 158 0 obj <> endobj 242 0 obj <>stream xœcd`ab`dddsö Ž´±TH3þaú!ËÜý»ïGÌÏ&Önæn–•?Î }OüÅÿ=T€™‘1¯¸É9¿ ²(3=£DA#YSÁÐÒÒ\GÁÈÀÀRÁ17µ(391OÁ7±$#57±ÈÉQÎOÎL-©TаÉ())°Ò×///×KÌ-ÖË/J·ÓÔQ(Ï,ÉPJ-N-*KMQpËÏ+QðKÌMU»ML:çç”–¤)øæ§¤å1000祥30Ø2Ä0ÄýÂÀäœgLüÑÁ÷cê﾿‚ç3ù¡ÌüCïw©è„º õ³º9¦M2£·»·u¦üï÷¿lš4÷5uK646ÕuvwN¬•k\ò#ié¤%Œß /1ßñãŠh÷ñîEkVΟ³röξi=“»»§qÌhê®ÓÔŒ±é’û=…½+3ÏS©­©«½µ»•£~j×d¹‹»“§Æô6uwvgpüŽbïN鎺˜~ ÿT×´nŽSºgLkìi“ן˜³·eYÇôîÞîõߵػWtïéšÒx8jMðìïkº/toç@¸(y1ÔEß%D{Ö®8ûe”žþ‰Ý9¦7ö4˹öEonÜÕ9hÖ:Žï@7uïq]¶Ì§·¡›£¾±»®aj×ùç­«"'ôÕÝ•Îñhc^wTOÓÔà=Y‡«sdu»uÇsüö`ïöï.ÉÊ-¯Ê­ŽíhèjîînਛÚ=ýíÛ]·zäøŠÿ´_Èö[fû6®mÜr\,biõ<œÛæðð1/ŸS! endstream endobj 113 0 obj <> endobj 243 0 obj <>stream xœ¥Y TSW·¾1psUÛ« í½Øª¿sëX­³¢ˆÖ•y†H a 'a ó@dVDQgê€Õ8‹ÚZmkµ­ÃßgíjÏí;üë'IúÛ¾µÞz V7÷ܳÏÞûÛßþö…GØõ#x<¹ÜuëÖùæ¿Æs£yÜ{ý¸÷ù)(†3üábøÀÁ®þ=Æq87n,· %ø<^x”r¹P(vžà3ÑyÆüùs§8Ïœ>}¾óÒ0¿È ¯pgW/q _˜—_„:oúù‰c', ‹E >úH*•Nó ‹š&Œ X— ÃD±_¤³«Ð×/2œ ˆKÃ…;–‹v®ˆŒZ-^#Y-õŠñ^ëãêëçæ°)0hËÖÐ°Ïæ|¯ª5¯šd³ŠÄöRMðš‰÷y¬Àö‚`( ‡NýÙ#û©ÐP4ôù$híž¿„C䃦ÓËÜî<}rå‹7/»Îœá¶lÛsdNbâA Þ`×JëÉâ:lAˆ-Œ!åžØpW74TåC©IU‹~‰2Tƒý–U}ÇÓ“ðCô¹=Z%E¼ Þ`kð¢àjó¡M0ñZºàñ{|.†»O—€šIJBŒWì©Ù(4ñÑ{h Zû¡÷¡#´òíó"”"Ô¬ ú@¨ó‡cáÄo_Wù ­`³"÷<@5ƒª ³k(Ò§¼Éˆ¦‹Q$mf²!ìpì1@AþËçp88ç²óðŠ d*²Ãÿ”­n½m¶p±ôÅ‹'/ݸ¸zöL—5ËVø~}†é fg¬ÆáôçZèüò©f12è¤T²K1@Ül>$ÓÝëŽL’ƒää_ô |Eî×å`_*@•¿?Ç0ËP™ o÷]0¿‹‘ƒ´ÜržRÖÐ-‰&û®  G~ÇÀÙpö8 9±È®»•æ$? y±¥6!gKöaÎþ$1\O¿ºö$˜LÿÚä"@UÊj+Úæm^律mìWé‚dg5ôu,´1[n…â[ÑyÛóM|n)7¦'ÑâÔ„ätƯb'ˆÃ‰^.Ÿ.ÜÖU¨bDצ¾–U§}¥;¨ÐðÀÉ| ¥L²>­@();] ¢Æ’âÜÚ<æTà Ç™[`üñðÉІ¨Ög_döÔ¯œµ ™ªn¬ýá‡Ì ‰†Ñ kl1‘؉Ã&^s,ÃIr‡Þt–‘ƒ•ZHÕ¢Àekµdɯðpâý×÷:Úw-.`µrmìþÞ !+èñ)E.T`ðú·bŸÆ¢Ñh-rý9ÂZÊÊØˆüÄšž„[¢rÑôZσ“»zâ.áúÑp–µ°Ñ¬¯ÉÞÌK™…ó2Qo)}ƒä䇷o}w£³«)$ʤê F½ËG‚©m)è0ö&Td‚ÛM¼oº /öo=®i£µÑ`²¯4h;ò…Ûÿ|·Ïc·$ʆ!ÿTÆ"è‹DQä_9ùÆÇ>äœèìü‰ýüɹ‹‚ƒºV Þ¾ŸEN½q¿©%»¾•É Óƒr@Ýûö³R<ƒÝ„„ [­´‰n "l®[mÖ=Ç5À×&ž‘ñ¹Oq6êÈ‹‘ÖçªÉ±È4šì«mž`-€:³ÕãB\ÄàTöƒTßæ¥\"ŸóÀ›×1Øzò<Ⱥõ)r7:jŸA¦ÕÈΩêågÓJýAH“Ë6%ú+<Ò"© r¯µË‚Ì2P ²µyÚâ\PIaÊŠcIÆá“+râKÒØl5Æ!؉&9 ç$¥J1l’ë¤g"nºCÖ±#2G[”[J(ÜXó³2ŒÀ˜B¥.?[‡1ßG¿:jÔY dˆÉÃ%>ቑêÜ GuSd~, „±1"ŸÏ37;¾ø®Ží#ù[]0ô'Üò 6ÈuE<(™dyœ×J@}¼êÆãÓ ¿ÃwËŠ3@«Wk24ÊÌ š¤R@Õèõ5wÇ´t= þç8~Øðs‰Uš\N><Á½O+|Þ)¡Ø«”º¤†Äý.p—cRR¨M–24‚z¶["3À\W-Ña, dGéÂuáב¯cVB^D=¨yÕY…—¡»#ÐTÝÎ6Ršîò/–ê½MbˆEdRe‹§=xÂT÷xBSHI…OÕ6Üø“'£ahÈÓIhk-;x qG™?ñÚR8‚vß³àÓU¯?~bºv§óÔgî½mƒ¾á²ýæcá´n¢õ•à¤\^  ž2WÆÐ_'Àwᨶ§Fsâ8 lÔæu lsHŸSš+tÅÃˇσ›àÈîÜO©>9vÎÒá®E®È5Z„ZÑQƒºÂõ•5ð(ƒ¼Q=ˆ+Û΀ \· ÛŠN×~ „"÷‚Ý`p«Áª„mI»¢$sõ¦ô¡®~\:sÃëoÓðú·“w.iê™L‘AfTEuqãó|ñÏØ“­ ð%êoCãuV6o.ns.¸tú Üv…g2·žÆ/ø0à2­  Ê”aFJ4#½,P˜­«‘7(õ¬ëÎ÷ÊÚ¸j¶²°D[¬É‰0¨Š±ú©(7ÖH¶‰÷¦„û³Âò ‚@@M]ºl–QHy«”%E€àejÕ«½Ò]€œšõ›|ÿ½ó{,ƒ×ƒpf'ÐÛ=[;:Z[OŸnõtw÷ôÜÎjÐ ú)äy>+=ÇO\v¤µ¹ñÈ鬹Ê~·ÍÅ|ÄÒ%åÀ£Îaƒ/µéËåÝsÊé×@;õv–Ê @SÄä*NMÈJÉK,Ø 4 ºÓ“â€ò|òqócà<¸¥;QxÞXñ<UÑ›u»ÀR° ñ)®Á‘{;&d€h@Å“ñ1 : ¨Ûg°o›^â|{¶ëÞnàÝ’ÿÿxÓƒ›¯~áA%†‰»@׊«„B±X(¬×ÖVUÕ2È °ê`Ü:°†±ší°BäxŸì9däÏÜ„ûoò¹Mo&¥",™qoÙ˜‰Ç[²hŽ{~{do}òݸüô²LpEZ±QŸynYêí£+1»kÓŽdTd”fè{E*¢{Tj¥®¨>—i1%žÆíƒºýýÓFeKèaÖ÷¸GA@^tö²2EÖž‚€ƒàuòøñëPP2-2 ²ŒR«Xµ`ufþíU9ÃÜɾùá¾%îÝ#ÿb²Ö-ÙnÛÖPlï‹-àš$0»…¹4íì›lºòt«¶ÙO¢)èC{ø³ÅàZkžè–ì²)ÊéV3»î’÷ïà”L°1Sj(f¡ƒuûз$\/w¢mtç¬ÝFØ\?¶9߈>?x§;!iþås{áçt%€v3“vÞŒ:+¦Ý«’`UxDZàlÙ®4±¨CÐ7æ?µ¾€+ßioÑÅ»2(N  ïÅÓ­ÿÓ|8¥k0ñ ¹t>Žs—_Û{t›±ÉHz¡[É[S<Ów:eê/öÂmÉ…IåR„ðglJâä®^—~8¥-¥Ý~ïXe• -:¨èX y³» SšÝ œtXëå3sOCqæJKfzŸBâ,U¾¸ B‡@f¥¶ÜÂü°Ê¬yßvA.jÑÊÊz3¦üXT$‚ˆ¦òììü<¦þ`[ñI¬ ­\·xÕÆù>Ÿ•¶JX&7_£Õ:i4@ ²¨j©>"F˜à·àá h‡ý×SÈÿeÑKÔ?Ø;UâÉÀõ‹éº«pމwêó» ¬­žÑ%ÐéÉ£§Xu”äôD ¤Äeâº}E}{ÈÅqxª† ](ò?ýòþëíg>Ev[·Çx3…h" ti™ œ:þôýg\–Ï_·yùø®¦G›ýòÈÀ9ãÁ+à>¼Ê}AŸõÌR)½Ò¶mÏF“µLã dš0Ml hš2Íí9ÍEÍ9Í™¬p†ê.°{‹~,ž¤™àg&Þ….X„=yÑÊ®µÔù_!ä0wÑüU×v_1.1K·‚ÔÄga‡ÿøäå£%ëË™EôJ·ÖÏOu¿w¯ÃcÇV7Ï•,ºd·`ý¹«—Îw>þþœÛ†µë·,0ã ~m€9zÞ¿ ùMâÅ×/øÿ&ü›ànÑMáEqñÊ]™LòÐFꪀ“jŒÜ ýÿ·ûæÀ {޹ qp8†s ÛÈ¢fp¨Ù$²d1ì—}8² 8ƒ´ŒD9êï8ù/¿]N&ú¿fPÄ^"ãÐû½¤Âøùl5PSÑ¥q•YÕ³˜ì¦Ìš¬ƒÔ‹¿¿u‡,8šùëJ¢àúEÏÆ“{*wÛ•ðÜßáï8>ÝZâ/ ño56×442è¼Ý[ßá'ç:MÐÿ t3uêy®ÿjz}Ý,0ÛéC)-qÅÞ)©*ˆ¦B÷É Er]öù,`õŒúÁ@$cüˆ¯[ƒ 3á˜H I9žåò39ÙºBŒ¿êh}¤,Tå¹¼}6ž€×Ë€h#¨)Á»¼*¹y| .ù>AŽÕ”K½¥`×plòs¯þ4¸D]¸³zÓŽmS·­/ñdâeþ ™(8ÉR‹N¬¸{®å`c sÀïpX ®×Üj; j¡Z”ªCâ¥1 V”í¿ ïÈÌ¥Ð&ø-ûKuÖXWÕ–f„ËÂvlb$¨?]$:1W.â¡Á/ñóý-y•mÇzJkëÝûwyÍÜ6>·¾¤ bÜù‚x½$ã}1ˆbÃ×h ]|—F. Ä‘‰ï‡qc3opÖ7b­RoâÃç\2Ýxdo€,\’¢õ:™Îh@F“¡Í)øG¤rYá•”š”b©Ø2y©ñ÷ëðÝÿÈË&h¤ ó rñX¯×©²Ñ☜©Òd*V*K‹”ùÉ,lB«Q;Ú˜–®J1N‘•Š’ìl­6Ç‚ò?Ęí–`f_»¥I9Ê\äøØ2àWpÏ`ªlk¹wòÈñ†Üì( òSô"ñÜM³·0ÛæÅÍÄ2~Mñ”«SN.ÿÊmžÓrôù¬eÏ x°ÝoxT×⟯}¾óö'x4L•¨dùɺ:Î>‚ð!Xí"Ùã³d§·G¨*%5 º2'º¦ê› Ï1g•=·Ìø~jàFáƒJoòáqø/Z»Oc5Th *‘ÆEÉŒ½¤ÈUk•ÀI*—Å$d'”'±¿m³Yœâ@ªSL‰L¯ËÎÌÌf qE™áDN*ØÔšòj2Lê}LEb»¨&Î(ךßjèKJ+ôñy)™¬¤hñ‘¤ìßÎ;VâÉ9‡ª—J•©é驿>0À…wá"|4É]>< 4dÞR‹È’à?æ¼±ˆôÒ_! ñ™üšñâBÆZÂæòÀ‡Z:Uë·=N™›$=…Úøú,´»àßêáì_#jÎÍÕh´æg¡á®sñ ¬æ¯‘}æ,dø†/¿M xÁ¤7›LúÛ=,€¹ÀMás{þp óJäRU1%±Qʘ¤T}ù¯e*ÈÉNâ y¹QW^m•Ó'ºà~ 5‘y‚Ü0ŽDvÈ~<…\І_ÐHhí_ÁQÐ…AÁxŠüćc,wýÅíÛ×'¡±hœ+êÿI¯æ%M¿à˜'cŒ]ëÕæq*¥"… ]é#òI—gHÔ Œ’$[ôUL÷G3mþßmˆ3Ikôdð'º/aÿZ(°M6›ˆG‚Ÿ`NÿÚ´*99tf…ÆÀï-ogêz_ÈG‹$!϶C»'ûªšÞ¾~¦àÀ _¢¡¨ÿÂ…û4&•è«Ëê ªÜÔl¦ìرj<<èÚ=g¥»›O0k+îüÔãe!¶rûúÍçD,É:ÈV4¸,µÚü^UµOjˆˆ˃f=Û ‡ÁxþÐõœ‡¹s&÷*®–ûK®"{4díÎÕa•±ûöôÕºô‚Ô\f äêf›¿·PáíÉFÄÅfx¤ûª¥æ š%«Ù{N‡ò¸µ\]&+‹S$'+•Œ<><*kдì¸Ò„B©!DQ‚0ÚÃ_¥)WWV”›«Ó1%ÅuÆ ²RËd… úèÀj k Ç›µù ß2ÿ¿6qÎÂíNþ!h¥·ûh*<+þ5cÝl&¶5Ö¦áöºËz±þBPé™p2¤d(¢)4«›¤a|fž 'pËóà§$ŠÉ˜t dØÅ ú›ºÄÿpýï endstream endobj 5 0 obj << /Limits [ (Doc-Start) (page.9) ] /Names [ (Doc-Start) 11 0 R (Navigation1) 6 0 R (Navigation10) 85 0 R (Navigation11) 94 0 R (Navigation12) 101 0 R (Navigation13) 108 0 R (Navigation14) 117 0 R (Navigation15) 124 0 R (Navigation16) 131 0 R (Navigation17) 138 0 R (Navigation18) 146 0 R (Navigation19) 153 0 R (Navigation2) 21 0 R (Navigation20) 162 0 R (Navigation21) 169 0 R (Navigation22) 176 0 R (Navigation23) 183 0 R (Navigation24) 190 0 R (Navigation25) 197 0 R (Navigation26) 204 0 R (Navigation27) 211 0 R (Navigation28) 218 0 R (Navigation29) 225 0 R (Navigation3) 30 0 R (Navigation4) 43 0 R (Navigation5) 50 0 R (Navigation6) 57 0 R (Navigation7) 64 0 R (Navigation8) 71 0 R (Navigation9) 78 0 R (page.1) 7 0 R (page.10) 86 0 R (page.11) 95 0 R (page.12) 102 0 R (page.13) 109 0 R (page.14) 118 0 R (page.15) 125 0 R (page.16) 132 0 R (page.17) 139 0 R (page.18) 147 0 R (page.19) 154 0 R (page.2) 22 0 R (page.20) 163 0 R (page.21) 170 0 R (page.22) 177 0 R (page.23) 184 0 R (page.24) 191 0 R (page.25) 198 0 R (page.26) 205 0 R (page.27) 212 0 R (page.28) 219 0 R (page.29) 226 0 R (page.3) 31 0 R (page.4) 44 0 R (page.5) 51 0 R (page.6) 58 0 R (page.7) 65 0 R (page.8) 72 0 R (page.9) 79 0 R] >> endobj 254 0 obj <>stream dvips + GPL Ghostscript 9.20 2019-02-15T22:03:07+03:00 2019-02-15T22:03:07+03:00 LaTeX with Beamer class paexec – distributes tasks over network or CPUsAleksey Cheusov vle@gmx.net endstream endobj 2 0 obj <>endobj xref 0 255 0000000000 65535 f 0000050485 00000 n 0000102154 00000 n 0000050211 00000 n 0000044515 00000 n 0000099208 00000 n 0000051135 00000 n 0000051193 00000 n 0000000015 00000 n 0000000613 00000 n 0000051251 00000 n 0000051293 00000 n 0000061342 00000 n 0000087496 00000 n 0000060708 00000 n 0000082609 00000 n 0000060174 00000 n 0000077812 00000 n 0000051352 00000 n 0000051384 00000 n 0000044707 00000 n 0000051438 00000 n 0000051498 00000 n 0000000632 00000 n 0000001415 00000 n 0000059910 00000 n 0000077192 00000 n 0000051558 00000 n 0000051590 00000 n 0000044901 00000 n 0000051644 00000 n 0000051704 00000 n 0000001435 00000 n 0000002697 00000 n 0000059116 00000 n 0000071511 00000 n 0000058575 00000 n 0000066113 00000 n 0000058288 00000 n 0000065181 00000 n 0000051764 00000 n 0000051796 00000 n 0000045095 00000 n 0000051861 00000 n 0000051921 00000 n 0000002718 00000 n 0000004022 00000 n 0000051981 00000 n 0000052013 00000 n 0000045289 00000 n 0000052089 00000 n 0000052149 00000 n 0000004043 00000 n 0000005461 00000 n 0000052209 00000 n 0000052241 00000 n 0000045483 00000 n 0000052328 00000 n 0000052388 00000 n 0000005482 00000 n 0000006812 00000 n 0000052448 00000 n 0000052480 00000 n 0000045677 00000 n 0000052556 00000 n 0000052616 00000 n 0000006833 00000 n 0000008003 00000 n 0000052676 00000 n 0000052708 00000 n 0000045871 00000 n 0000052784 00000 n 0000052844 00000 n 0000008024 00000 n 0000009680 00000 n 0000052904 00000 n 0000052936 00000 n 0000046065 00000 n 0000053023 00000 n 0000053083 00000 n 0000009701 00000 n 0000011088 00000 n 0000053143 00000 n 0000053175 00000 n 0000046259 00000 n 0000053251 00000 n 0000053311 00000 n 0000011109 00000 n 0000013057 00000 n 0000057881 00000 n 0000062993 00000 n 0000053371 00000 n 0000053403 00000 n 0000046453 00000 n 0000053490 00000 n 0000053550 00000 n 0000013078 00000 n 0000014130 00000 n 0000053610 00000 n 0000053642 00000 n 0000046647 00000 n 0000053696 00000 n 0000053758 00000 n 0000014150 00000 n 0000016057 00000 n 0000053820 00000 n 0000053853 00000 n 0000046845 00000 n 0000053930 00000 n 0000053992 00000 n 0000016079 00000 n 0000017416 00000 n 0000062431 00000 n 0000092787 00000 n 0000054054 00000 n 0000054087 00000 n 0000047043 00000 n 0000054166 00000 n 0000054228 00000 n 0000017438 00000 n 0000018891 00000 n 0000054290 00000 n 0000054323 00000 n 0000047241 00000 n 0000054402 00000 n 0000054464 00000 n 0000018913 00000 n 0000020438 00000 n 0000054526 00000 n 0000054559 00000 n 0000047439 00000 n 0000054638 00000 n 0000054700 00000 n 0000020460 00000 n 0000021979 00000 n 0000054762 00000 n 0000054795 00000 n 0000047637 00000 n 0000054874 00000 n 0000054936 00000 n 0000022001 00000 n 0000025069 00000 n 0000058220 00000 n 0000054998 00000 n 0000055031 00000 n 0000047835 00000 n 0000055099 00000 n 0000055161 00000 n 0000025091 00000 n 0000026914 00000 n 0000055223 00000 n 0000055256 00000 n 0000048033 00000 n 0000055335 00000 n 0000055397 00000 n 0000026936 00000 n 0000028525 00000 n 0000062143 00000 n 0000091864 00000 n 0000055459 00000 n 0000055492 00000 n 0000048231 00000 n 0000055573 00000 n 0000055635 00000 n 0000028547 00000 n 0000030132 00000 n 0000055697 00000 n 0000055730 00000 n 0000048429 00000 n 0000055800 00000 n 0000055862 00000 n 0000030154 00000 n 0000031635 00000 n 0000055924 00000 n 0000055957 00000 n 0000048627 00000 n 0000056038 00000 n 0000056100 00000 n 0000031657 00000 n 0000033630 00000 n 0000056162 00000 n 0000056195 00000 n 0000048825 00000 n 0000056276 00000 n 0000056338 00000 n 0000033652 00000 n 0000035511 00000 n 0000056400 00000 n 0000056433 00000 n 0000049023 00000 n 0000056514 00000 n 0000056576 00000 n 0000035533 00000 n 0000037558 00000 n 0000056638 00000 n 0000056671 00000 n 0000049221 00000 n 0000056752 00000 n 0000056814 00000 n 0000037580 00000 n 0000039512 00000 n 0000056876 00000 n 0000056909 00000 n 0000049419 00000 n 0000056977 00000 n 0000057039 00000 n 0000039534 00000 n 0000041006 00000 n 0000057101 00000 n 0000057134 00000 n 0000049617 00000 n 0000057202 00000 n 0000057264 00000 n 0000041028 00000 n 0000042458 00000 n 0000057326 00000 n 0000057359 00000 n 0000049815 00000 n 0000057440 00000 n 0000057502 00000 n 0000042480 00000 n 0000044106 00000 n 0000057564 00000 n 0000057597 00000 n 0000050013 00000 n 0000057678 00000 n 0000057740 00000 n 0000044128 00000 n 0000044494 00000 n 0000061893 00000 n 0000090909 00000 n 0000057802 00000 n 0000057835 00000 n 0000063271 00000 n 0000065454 00000 n 0000066597 00000 n 0000071941 00000 n 0000077418 00000 n 0000078281 00000 n 0000083046 00000 n 0000087856 00000 n 0000091146 00000 n 0000092109 00000 n 0000093332 00000 n 0000058457 00000 n 0000059023 00000 n 0000059559 00000 n 0000059679 00000 n 0000060075 00000 n 0000060602 00000 n 0000061204 00000 n 0000061794 00000 n 0000062313 00000 n 0000062900 00000 n 0000100438 00000 n trailer << /Size 255 /Root 1 0 R /Info 2 0 R /ID [<48CF3EA99B8508068B7EDDE552F6E8FC><48CF3EA99B8508068B7EDDE552F6E8FC>] >> startxref 102439 %%EOF paexec-1.1.1/presentation/paexec.tex0000644000175000017500000005125413431606350017403 0ustar cheusovcheusov%%%begin-myprojects \documentclass[hyperref={colorlinks=true}]{beamer} \usepackage{fancyvrb,relsize} \usepackage{graphicx} \setbeamertemplate{navigation symbols}{} %\usetheme{Boadilla} %\usetheme{CambridgeUS} %\usetheme{Malmoe} %\usetheme{Singapore} %\usetheme{boxes} %\usecolortheme{crane} %\usecolortheme{dove} \usecolortheme{seagull} % very cool with \usetheme{default} %\usefonttheme{professionalfonts} %\useinnertheme{rectangles} \mode \title{paexec -- distributes tasks over network or CPUs} \author{Aleksey Cheusov \\ \texttt{vle@gmx.net}} \date{Minsk, Belarus, 2013} \begin{document} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \newenvironment{CodeSmall}[1]% {\Verbatim[label=\bf{#1},frame=single,% fontsize=\footnotesize,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{CodeSmallNoLabel}% {\Verbatim[frame=single,% fontsize=\footnotesize,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{Code}[1]% {\Verbatim[label=\bf{#1},frame=single,% fontsize=\small,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{CodeNoLabel}% {\Verbatim[frame=single,% fontsize=\small,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{CodeLarge}[1]% {\Verbatim[label=\bf{#1},frame=single,% fontsize=\large,% commandchars=\\\{\}]}% {\endVerbatim} \newenvironment{CodeLargeNoLabel}% {\Verbatim[frame=single,% fontsize=\large,% commandchars=\\\{\}]}% {\endVerbatim} %\newcommand{\prompt}[1]{\textcolor{blue}{#1}} %\newcommand{\prompt}[1]{\textbf{#1}\textnormal{}} \newcommand{\prompt}[1]{{\bf{#1}}} %\newcommand{\h}[1]{\textbf{#1}} %\newcommand{\h}[1]{\bf{#1}\textnormal{}} \newcommand{\h}[1]{{\bf{#1}}} \newcommand{\name}[1]{{\tt{#1}}} \newcommand{\URL}[1]{\textbf{#1}} \newcommand{\AutohellFile}[1]{\textcolor{red}{#1}} \newcommand{\MKCfile}[1]{\textcolor{green}{#1}} \newcommand{\ModuleName}[1]{\textbf{#1}\textnormal{}} \newcommand{\ProgName}[1]{\textbf{#1}\textnormal{}} \newcommand{\ProjectName}[1]{\textbf{#1}\textnormal{}} \newcommand{\PackageName}[1]{\textbf{#1}\textnormal{}} \newcommand{\MKC}[1]{\large\textsf{#1}\textnormal{}\normalsize} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% \begin{frame} %% \frametitle{qqq} %% \begin{code}{files in the directory} %% bla bla bla %% \end{code} %% \end{frame} %%%end-myprojects %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame} \titlepage \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}{} \frametitle{Problem} \begin{block}{} \begin{itemize} \item Huge amount of data to process \item Typical desktop machines have more than one CPU \item Unlimited resources are available on the Internet \item Heterogeneous environment (*BSD, Linux, Windows...) \end{itemize} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Solution} \begin{block}{} \begin{CodeLarge}{Usage} paexec [OPTIONS] \textbackslash -n 'machines or CPUs' \textbackslash -t 'transport program' \textbackslash -c 'calculator' < tasks \end{CodeLarge} \begin{CodeLarge}{example} ls -1 *.wav | \textbackslash paexec -x -c 'flac -s' -n +4 > /dev/null \end{CodeLarge} \begin{CodeLarge}{example} paexec \textbackslash -n 'host1 host2 host3' \textbackslash -t /usr/bin/ssh \textbackslash -c ~/bin/toupper < tasks \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} Our goal is to convert strings to upper case in parallel \begin{block}{} \begin{Code}{\~{}/bin/toupper} #!/usr/bin/awk -f \{ print " ", toupper(\$0) print "" # empty line -- end-of-task marker! fflush() # We must flush stdout! \} \end{Code} \end{block} \begin{block}{} \begin{Code}{\~{}/tmp/tasks} apple bananas orange \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} \name{\~{}/bin/toupper} script will be run only once on remote servers ``server1'' and ``server2''. It takes tasks from stdin (one task per line). Transport program is \name{ssh(1)}. \begin{block}{} \begin{CodeLarge}{paexec invocation} \prompt{\$} paexec \h{-t} ssh \h{-c} ~/bin/toupper \textbackslash \h{-n} 'server1 server2' < tasks > results \prompt{\$} cat results BANANAS ORANGE APPLE \prompt{\$} \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} Options \h{-l} and \h{-r} add the task number and server where this task is processed to stdout. \begin{block}{} \begin{CodeLarge}{paexec -lr invocation} \prompt{\$} paexec \h{-lr} -t ssh -c ~/bin/toupper \textbackslash -n 'server1 server2' < tasks > results \prompt{\$} cat results \h{server2 2} BANANAS \h{server2 3} ORANGE \h{server1 1} APPLE \prompt{\$} \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} The same as above but four instances of \name{\~{}/bin/toupper} are ran locally. \begin{block}{} \begin{CodeLarge}{paexec invocation} \prompt{\$} paexec \h{-n} +4 -c ~/bin/toupper < tasks > results \prompt{\$} cat results BANANAS ORANGE APPLE \prompt{\$} \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} The same as above but without \name{\~{}/bin/toupper}. In this example we run AWK program for each individual task. At the same time we still make only one ssh connection to each server regardless of a number of tasks given on input. \begin{block}{} \begin{CodeLarge}{paexec invocation} \prompt{\$} paexec \h{-x} -t ssh -n 'server1 server2' \textbackslash \h{-c} "awk 'BEGIN \{print toupper(ARGV[1])\}' " \textbackslash < tasks > results \prompt{\$} cat results ORANGE BANANAS APPLE \prompt{\$} \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} If we want to "shquate" less one can use option \h{-C} instead of \h{-c} and specify command after options. \begin{block}{} \begin{CodeLarge}{paexec invocation} \prompt{\$} paexec -x \h{-C} -t ssh -n 'server1 server2' \textbackslash awk 'BEGIN \{print toupper(ARGV[1])\}' \textbackslash < tasks > results \prompt{\$} cat results ORANGE BANANAS APPLE \prompt{\$} \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 1: toupper} With options \h{-z} or \h{-Z} we can easily run our tasks on unreliable hosts. If we cannot connect or lost connection to the server, paexec will redistribute failed tasks to another server. \begin{block}{} \begin{CodeLarge}{paexec invocation} \prompt{\$} paexec \h{-Z}240 -x -t ssh \textbackslash -n 'server1 badhostname server2' \textbackslash -c "awk 'BEGIN \{print toupper(ARGV[1])\}' " \textbackslash < tasks > results {\it ssh: Could not resolve hostname badhostname:} {\it No address associated with hostname} {\it badhostname 1 fatal} \prompt{\$} cat results ORANGE BANANAS APPLE \prompt{\$} \end{CodeLarge} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \linespread{0.5} \begin{frame}[fragile] \frametitle{Example 2: parallel banner(1)} \begin{block}{} \begin{CodeLarge}{what is banner(1)?} \prompt{\$} banner -f @ NetBSD @ @ @@@@@@ @@@@@ @@@@@@ @@ @ @@@@@@ @@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @@@@@ @ @@@@@@ @@@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ @@@@@@ @ @@@@@@ @@@@@ @@@@@@ \prompt{\$} \end{CodeLarge} \end{block} \end{frame} \linespread{1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 2: parallel banner(1)} \name{\~{}/bin/pbanner} is wrapper for \name{banner(1)} for reading tasks line by line. Magic line is used instead empty line as an end-of-task marker. \begin{block}{} \begin{Code}{\~{}/bin/pbanner} #!/usr/bin/env sh while read task; do banner -f M "\$task" | echo \h{"\$PAEXEC\_EOT"} # end-of-task marker done \end{Code} \begin{Code}{tasks} pae xec \end{Code} \begin{Code}{paexec invocation} \prompt{\$} paexec -l \h{-mt='SE@X-L0S0!&'} -c ~/bin/pbanner \textbackslash -n +2 < tasks > result \prompt{\$} \end{Code} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \linespread{0.5} \begin{frame}[fragile] \frametitle{Example 2: parallel banner(1)} \name{paexec(1)} reads calculator's output asynchronously. So, its output is sliced. \begin{block}{} \begin{CodeSmall}{Sliced result} \prompt{\$} cat result 2 2 2 M M MMMMMM MMMM 2 M M M M M 1 1 1 MMMMM MM MMMMMM 1 M M M M M 1 M M M M MMMMM 1 MMMMM MMMMMM M 2 MM MMMMM M 2 MM M M 2 M M M M M 2 M M MMMMMM MMMM 2 1 M M M M 1 M M M MMMMMM 1 \prompt{\$} \end{CodeSmall} \end{block} \end{frame} \linespread{1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \linespread{0.5} \begin{frame}[fragile] \frametitle{Example 2: parallel banner(1)} \name{paexec\_reorder(1)} normalizes \name{paexec(1)}'s output. \begin{block}{} \begin{CodeSmall}{Ordered result} \prompt{\$} paexec_reorder \h{-mt='SE@X-L0S0!&'} results MMMMM MM MMMMMM M M M M M M M M M MMMMM MMMMM MMMMMM M M M M M M M M MMMMMM M M MMMMMM MMMM M M M M M MM MMMMM M MM M M M M M M M M M MMMMMM MMMM \prompt{\$} \end{CodeSmall} \end{block} \end{frame} \linespread{1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \linespread{0.5} \begin{frame}[fragile] \frametitle{Example 2: parallel banner(1)} The same as above but using magic end-of-task marker provided by \name{paexec(1)}. \begin{block}{} \begin{CodeSmall}{Ordered result} \prompt{\$} paexec \h{-y} -lc ~/bin/pbanner -n+2 < tasks | paexec_reorder \h{-y} MMMMM MM MMMMMM M M M M M M M M M MMMMM MMMMM MMMMMM M M M M M M M M MMMMMM M M MMMMMM MMMM M M M M M MM MMMMM M MM M M M M M M M M M MMMMMM MMMM \prompt{\$} \end{CodeSmall} \end{block} \end{frame} \linespread{1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \linespread{0.5} \begin{frame}[fragile] \frametitle{Example 2: parallel banner(1)} For this trivial task wrapper like \name{\~{}/bin/pbanner} is not needed. We can easily run \name{banner(1)} directly. \begin{block}{} \begin{CodeSmall}{Sliced result} \prompt{\$} paexec -l \h{-x} -c banner -n+2 < tasks 2 2 2 M M MMMMMM MMMM 2 M M M M M 2 MM MMMMM M 2 MM M M 2 M M M M M 1 1 1 MMMMM MM MMMMMM 1 M M M M M 1 M M M M MMMMM 1 MMMMM MMMMMM M 2 M M MMMMMM MMMM 2 1 M M M M 1 M M M MMMMMM 1 \prompt{\$} \end{CodeSmall} \end{block} \end{frame} \linespread{1} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} \name{paexec(1)} is able to build tasks taking into account their ``dependencies''. Here ``devel/gmake'' and others are pkgsrc packages. Our goal in this example is to build pkgsrc package audio/abcde and all its build-time and compile-time dependencies. \begin{block}{} \begin{figure} \includegraphics[width=\textwidth, height=\textheight, keepaspectratio=true]{dep-graph.eps} \end{figure} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} \name{``paexec \h{-g}''} takes a dependency graph on input (in \name{tsort(1)} format). Tasks are separated by space (\name{paexec -md=}). \begin{block}{} \begin{CodeSmall}{\~{}/tmp/packages\_to\_build} audio/cd-discid audio/abcde textproc/gsed audio/abcde audio/cdparanoia audio/abcde audio/id3v2 audio/abcde audio/id3 audio/abcde misc/mkcue audio/abcde shells/bash audio/abcde devel/libtool-base audio/cdparanoia devel/gmake audio/cdparanoia devel/libtool-base audio/id3lib devel/gmake audio/id3v2 audio/id3lib audio/id3v2 devel/m4 devel/bison lang/f2c devel/libtool-base devel/gmake misc/mkcue devel/bison shells/bash \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} If option -g is applied, every task may succeed or fail. In case of failure all dependants fail recursively. For this to work we have to slightly adapt ``calculator''. \begin{block}{} \begin{CodeSmall}{\~{}/bin/pkg\_builder} #!/usr/bin/awk -f \{ print "build " \$0 \h{print "success"} # build succeeded! (paexec -ms=) print "" # end-of-task marker fflush() # we must flush stdout \} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} \begin{block}{} \begin{CodeSmall}{paexec -g invocation (no failures)} \prompt{\$} paexec \h{-g} -l -c ~/bin/pkg_builder -n 'server2 server1' \textbackslash -t ssh < ~/tmp/packages_to_build | paexec_reorder > result \prompt{\$} cat result build textproc/gsed \h{success} build devel/gmake success build misc/mkcue success build devel/m4 success build devel/bison success ... build audio/id3v2 success build audio/abcde success \prompt{\$} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} Let's suppose that ``devel/gmake'' fails to build. \begin{block}{} \begin{CodeSmall}{\~{}/bin/pkg\_builder} #!/usr/bin/awk -f \{ print "build " \$0 if (\$0 == "devel/gmake") \h{print "failure"} # Oh no... else print "success" # build succeeded! print "" # end-of-task marker fflush() # we must flush stdout \} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} Package ``devel/gmake'' and all dependants are marked as failed. Even if failures happen, the build continues. \begin{block}{} \begin{CodeSmall}{paexec -g invocation (with failures)} \prompt{\$} paexec -gl -c ~/bin/pkg_builder -n 'server2 server1' \textbackslash -t ssh < ~/tmp/packages_to_build | paexec_reorder > result \prompt{\$} cat result build audio/cd-discid success build audio/id3 success build devel/gmake \h{failure} \h{devel/gmake audio/cdparanoia audio/abcde audio/id3v2 misc/mkcue} build devel/m4 success build textproc/gsed success ... \prompt{\$} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} paexec is resistant not only to network failures but also to \h{unexpected} calculator \h{exits or crashes}. \begin{block}{} \begin{CodeSmall}{\~{}/bin/pkg\_builder} #!/usr/bin/awk -f \{ "hostname -s" | getline hostname print "build " \$0 " on " hostname if (hostname == "server1" && \$0 == "textproc/gsed") \h{exit 139} # Damn it, I'm dying... # Take a note that exit status doesn't matter. else print "success" # Yes! :-) print "" # end-of-task marker fflush() # we must flush stdout \} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 3: dependency graph of tasks} ``textproc/gsed'' failed on ``server1'' but then succeeded on ``server2''. Every 300 seconds we try to reconnect to ``server1''. Keywords ``success'', ``failure'' and ``fatal'' may be changed with a help of -ms=, -mf= and -mF= options respectively. \begin{block}{} \begin{CodeSmall}{paexec -Z300 invocation (with failure)} \prompt{\$} paexec -gl -Z300 -t ssh -c ~/bin/pkg_builder \textbackslash -n 'server2 server1' < ~/tmp/packages_to_build \textbackslash | paexec_reorder > result \prompt{\$} cat result build audio/cd-discid on server2 success \h{build textproc/gsed on server1} \h{fatal} \h{build textproc/gsed on server2} \h{success} build audio/id3 on server2 success ... \prompt{\$} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 4: Converting .wav files to .flac or .ogg} In trivial cases we don't need relatively complex ``calculator''. Running a trivial command may be enough. Below we run three .wav to .flac/.ogg convertors in parallel. If \h{-x} is applied, task is passed to calculator as an argument. \begin{block}{} \begin{CodeSmall}{paexec -x invocation} \prompt{\$} ls -1 *.wav | paexec \h{-x} -c 'flac -s' -n+3 >/dev/null \prompt{\$} \end{CodeSmall} \end{block} \begin{block}{} \begin{CodeSmall}{paexec -x invocation} \prompt{\$} ls -1 *.wav | paexec -ixC -n+3 oggenc -Q | grep . 01-Crying_Wolf.wav 02-Autumn.wav 03-Time_Heals.wav 04-Alice_(Letting_Go).wav 05-This_Side_Of_The_Looking_Glass.wav ... \prompt{\$} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: paexec -W} If different tasks take different amount of time to process, than it makes sense to process ``heavier'' ones earlier in order to minimize total calculation time. For this to work one can weigh each tasks. Note that this mode enables ``graph'' mode automatically. \begin{block}{} \begin{CodeSmall}{\~{}/bin/calc} #!/bin/sh # \$1 -- task given on input if test \$1 = huge; then sleep 6 else sleep 1 fi echo "task \$1 done" \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: paexec -W} This is how we run unweighted tasks. The whole process takes 8 seconds. \begin{block}{} \begin{CodeSmall}{paexec invocation} \prompt{\$} printf 'small1\textbackslash{nsmall2}\textbackslash{nsmall3}\textbackslash{nsmall4}\textbackslash{nsmall5}\textbackslash{nhuge}\textbackslash{n}' | time -p paexec -c \~{}/bin/calc -n +2 -xg | grep -v success task small2 done task small1 done task small3 done task small4 done task small5 done task huge done real 8.04 user 0.03 sys 0.03 \prompt{\$} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{Example 5: paexec -W} If we say paexec that the task ``huge'' is performed 6 times longer than others, it starts``huge'' first and then others. In total we spend 6 seconds for all tasks. \begin{block}{} \begin{CodeSmall}{paexec -W1 invocation} \prompt{\$} printf 'small1\textbackslash{nsmall2}\textbackslash{nsmall3}\textbackslash{nsmall4}\textbackslash{nweight: huge 6}\textbackslash{n}' | time -p paexec -c \~{}/bin/calc -n +2 -x \h{-W1} | grep -v success task small1 done task small2 done task small3 done task small4 done task small5 done task huge done real 6.02 user 0.03 sys 0.02 \prompt{\$} \end{CodeSmall} \end{block} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \begin{frame}[fragile] \frametitle{} For details see the manual page. \begin{center} \huge The End \end{center} \end{frame} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \end{document} paexec-1.1.1/presentation/dep-graph.dot0000644000175000017500000000262513431606350017771 0ustar cheusovcheusovdigraph FSA { node [ shape=box fontsize=14 fontface="Arial"]; "audio/cd-discid" -> "audio/abcde" [ fontsize = 14]; "textproc/gsed" -> "audio/abcde" [ fontsize = 14]; "audio/cdparanoia" -> "audio/abcde" [ fontsize = 14]; "audio/id3v2" -> "audio/abcde" [ fontsize = 14]; "audio/id3" -> "audio/abcde" [ fontsize = 14]; "misc/mkcue" -> "audio/abcde" [ fontsize = 14]; "shells/bash" -> "audio/abcde" [ fontsize = 14]; "devel/libtool-base" -> "audio/cdparanoia" [ fontsize = 14]; "devel/gmake" -> "audio/cdparanoia" [ fontsize = 14]; "devel/libtool-base" -> "audio/id3lib" [ fontsize = 14]; "devel/gmake" -> "audio/id3v2" [ fontsize = 14]; "audio/id3lib" -> "audio/id3v2" [ fontsize = 14]; "devel/m4" -> "devel/bison" [ fontsize = 14]; "lang/f2c" -> "devel/libtool-base" [ fontsize = 14]; "devel/gmake" -> "misc/mkcue" [ fontsize = 14]; "devel/bison" -> "shells/bash" [ fontsize = 14]; node [ shape = box ]; "devel/m4" [ ]; "shells/bash" [ ]; "audio/id3lib" [ ]; "misc/mkcue" [ ]; "audio/id3" [ ]; "lang/f2c" [ ]; "devel/gmake" [ ]; "textproc/gsed" [ ]; "audio/id3v2" [ ]; "audio/abcde" [ ]; "devel/bison" [ ]; "audio/cdparanoia" [ ]; "devel/libtool-base" [ ]; "audio/cd-discid" [ ]; } paexec-1.1.1/presentation/Makefile0000644000175000017500000000120413431606350017042 0ustar cheusovcheusov################################################## FILES = paexec.pdf FILESDIR = ${DOCDIR} .PHONE : all all : paexec.pdf .PHONY : pdf dvi pdf : paexec.pdf ps : paexec.ps dvi : paexec.dvi .SUFFIXES: .ps .eps .pdf .dvi .tex .dot paexec.ps paexec.dvi: dep-graph.eps .ps.pdf: ps2pdf "$<" "$@" .dot.eps: dot -Tps ${.IMPSRC} > ${.TARGET} .dvi.ps: dvips $< .tex.dvi: latex "${.IMPSRC}" && latex "${.IMPSRC}" GARBAGE = *.dvi *.aux *.vrb *.toc *.snm *.log *.nav *.out *.eps *.ps _mkc_* CLEANFILES += ${GARBAGE} *.pdf .PHONY: _clean_garbage _clean_garbage: rm -f ${GARBAGE} _prepdist: all _clean_garbage .include paexec-1.1.1/examples/0000755000175000017500000000000013431606350014510 5ustar cheusovcheusovpaexec-1.1.1/examples/Makefile.inc0000644000175000017500000000003313431606350016714 0ustar cheusovcheusov.include "../Makefile.inc" paexec-1.1.1/examples/dirtest/0000755000175000017500000000000013431606350016166 5ustar cheusovcheusovpaexec-1.1.1/examples/dirtest/tasks0000644000175000017500000000062213431606350017236 0ustar cheusovcheusov/nonexistant;/nonexistant/subdir /nonexistant/subdir;/nonexistant/subdir/subsubdir examples examples/divide examples/all_substr examples/cc_wrapper examples/make_package examples/toupper examples/cc_wrapper2 examples/wav2flac paexec tests;tests/transp_closed_stdin tests;tests/fakeflac tests;tests/fakeflac tests;tests/scripts /etc;/etc/dir with spaces /etc/dir with spaces;/etc/dir with spaces/subdir paexec-1.1.1/examples/dirtest/run_dirtest0000755000175000017500000000022413431606350020454 0ustar cheusovcheusov#!/usr/bin/env sh # # paexec -gx: exit status of command passed # to -c is treated as a status of task # paexec -gx -l -c 'test -d' -md=';' -n +3 paexec-1.1.1/examples/dirtest/Makefile0000644000175000017500000000021413431606350017623 0ustar cheusovcheusovSCRIPTS = run_dirtest SCRIPTSDIR = ${EGDIR}/${.CURDIR:T} FILES = tasks FILESDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.1.1/examples/all_substr/0000755000175000017500000000000013431606350016662 5ustar cheusovcheusovpaexec-1.1.1/examples/all_substr/run_all_substr0000755000175000017500000000072513431606350021652 0ustar cheusovcheusov#!/usr/bin/env sh # Obtains all substrings in parallel using 3 subprocesses. # Subprocesses are run on the same host where paexec is run. # Output lines are prepanded with task number (-l) # and process pid (-p). # In the end of task, an empty line is added (-e) # Output is sliced. paexec -lpe -c "`pwd`/cmd" -n +3 < paexec-1.1.1/examples/toupper/0000755000175000017500000000000013431606350016206 5ustar cheusovcheusovpaexec-1.1.1/examples/toupper/run_toupper0000755000175000017500000000060413431606350020516 0ustar cheusovcheusov#!/usr/bin/env sh # Converts all strings to upper case in parallel. # Subprocesses are run on the same host where paexec is run. # Input may contains empty lines. input (){ cat <<'EOF' My English is awesome. Who is absent? My name is Aleksey. I was born in USSR. London is a capital of Great Britain. Who is on duty today? :-) EOF } input | paexec -c "`pwd`/cmd" -n +2 | cut -b 2- paexec-1.1.1/examples/toupper/Makefile0000644000175000017500000000017413431606350017650 0ustar cheusovcheusovINSCRIPTS = cmd_toupper SCRIPTS = ${INSCRIPTS} run_toupper SCRIPTSDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.1.1/examples/toupper/cmd_toupper.in0000755000175000017500000000044713431606350021067 0ustar cheusovcheusov#!@awk@ -f BEGIN { EOT = ENVIRON ["PAEXEC_EOT"] } { # Prepand every line with a space in order # to avoid empty lines on output printf " " # Single-line output print toupper($0) # End of task marker, empty line by default print EOT # In the end, stdout must be flushed fflush() } paexec-1.1.1/examples/make_package/0000755000175000017500000000000013431606350017100 5ustar cheusovcheusovpaexec-1.1.1/examples/make_package/run_cycle_make_package0000755000175000017500000000017113431606350023460 0ustar cheusovcheusov#!/usr/bin/env sh # Attempt to build packages with cyclic dependencies paexec -g -le -c "`pwd`/cmd" -n +3 < tasks_cycle paexec-1.1.1/examples/make_package/cmd_make_package.in0000755000175000017500000000035413431606350022650 0ustar cheusovcheusov#!@awk@ -f { # Read package names one-by-one # Suppose we built the package... print $0 # ...succesfully print "success" # End of task marker, empty line by default print "" # In the end, stdout must be flushed fflush() } paexec-1.1.1/examples/make_package/tasks0000644000175000017500000000043013431606350020145 0ustar cheusovcheusovtextproc/dictem devel/autoconf wip/libmaa devel/gmake wip/libmaa wip/libmaa wip/dict-server wip/libmaa wip/dict-client devel/m4 wip/dict-server devel/byacc wip/dict-server devel/byacc wip/dict-client devel/flex wip/dict-server devel/flex wip/dict-client devel/glib2 devel/libjudy paexec-1.1.1/examples/make_package/tasks_cycle0000644000175000017500000000033113431606350021324 0ustar cheusovcheusovdevel/gettext-lib devel/gmake devel/gmake lang/gcc pkgtools/pkg_install-info lang/gcc devel/libtool-base devel/gettext-lib sysutils/checkperms devel/gettext-lib lang/gcc converters/libiconv lang/gcc devel/gettext-lib paexec-1.1.1/examples/make_package/tasks20000644000175000017500000000016413431606350020233 0ustar cheusovcheusovdevel/flex wip/dict-server devel/flex wip/dict-client wip/dict-server wip/pkg_online wip/dict-client wip/pkg_online paexec-1.1.1/examples/make_package/Makefile0000644000175000017500000000036113431606350020540 0ustar cheusovcheusovINSCRIPTS = cmd_make_package cmd_xxx_failed_make_package SCRIPTS = ${INSCRIPTS} run_make_package run_cycle_make_package FILES != echo tasks* FILESDIR = ${EGDIR}/${.CURDIR:T} SCRIPTSDIR ?= ${FILESDIR} .include paexec-1.1.1/examples/make_package/cmd_xxx_failed_make_package.in0000755000175000017500000000026413431606350025063 0ustar cheusovcheusov#!@awk@ -f BEGIN { regexp = ARGV [1] ARGV [1] = "-" } { print $0 if ($1 ~ regexp) print "failure" else print "success" print "" # end of task marker fflush() } paexec-1.1.1/examples/make_package/run_make_package0000755000175000017500000000034613431606350022305 0ustar cheusovcheusov#!/usr/bin/env sh # Build packages taking a dependency graph on input # and sort the sliced output using sort(1) -- first task # before the second one and so on. paexec -g -le -c "`pwd`/cmd" -n +3 < tasks | paexec_reorder -g -Ms paexec-1.1.1/examples/cc_wrapper/0000755000175000017500000000000013431606350016635 5ustar cheusovcheusovpaexec-1.1.1/examples/cc_wrapper/func3.c0000644000175000017500000000000713431606350020014 0ustar cheusovcheusovint c; paexec-1.1.1/examples/cc_wrapper/run_cc_wrapper0000755000175000017500000000041413431606350021573 0ustar cheusovcheusov#!/usr/bin/env sh # here we compile .c sources in parallel on two hosts: localhost and chen # a la distcc paexec -c "env CC=gcc CFLAGS=-O2 `pwd`/cmd" \ -n 'host1 host2' \ -t '/usr/bin/ssh -x' < $log1 2> $log2; then echo "done: $fn" else echo "failed: $fn" fi echo '' # end of job done paexec-1.1.1/examples/cc_wrapper/Makefile0000644000175000017500000000023313431606350020273 0ustar cheusovcheusovSCRIPTS = cmd_cc_wrapper run_cc_wrapper SCRIPTSDIR ?= ${FILESDIR} FILES != echo *.c FILESDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.1.1/examples/divide/0000755000175000017500000000000013431606350015754 5ustar cheusovcheusovpaexec-1.1.1/examples/divide/run_divide20000755000175000017500000000036013431606350020113 0ustar cheusovcheusov#!/usr/bin/env sh # The same as "run" but with non-standard "success", # "failure" and "eot" strings. paexec -ms='Ura!' -mf='Zhopa!' -mt='Konec!' \ -s -l -c cmd_divide2 -n +3 < paexec-1.1.1/examples/Makefile0000644000175000017500000000003013431606350016141 0ustar cheusovcheusov.include paexec-1.1.1/examples/cc_wrapper2/0000755000175000017500000000000013431606350016717 5ustar cheusovcheusovpaexec-1.1.1/examples/cc_wrapper2/func3.c0000644000175000017500000000000713431606350020076 0ustar cheusovcheusovint c; paexec-1.1.1/examples/cc_wrapper2/func2.c0000644000175000017500000000000713431606350020075 0ustar cheusovcheusovint b; paexec-1.1.1/examples/cc_wrapper2/func1.c0000644000175000017500000000000713431606350020074 0ustar cheusovcheusovint a; paexec-1.1.1/examples/cc_wrapper2/Makefile0000644000175000017500000000021513431606350020355 0ustar cheusovcheusovSCRIPTS = run_cc_wrapper2 SCRIPTSDIR ?= ${FILESDIR} FILES != echo *.c FILESDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.1.1/examples/cc_wrapper2/run_cc_wrapper20000755000175000017500000000026013431606350021736 0ustar cheusovcheusov#!/usr/bin/env sh # here we compile .c sources in parallel using 4 parallel processes : ${CC:=cc} : ${CFLAGS:=-O0} ls -1 $PWD/*.c | paexec -c "env $CC $CFLAGS -c " -n +4 -x paexec-1.1.1/examples/wav2flac/0000755000175000017500000000000013431606350016215 5ustar cheusovcheusovpaexec-1.1.1/examples/wav2flac/run_wav2flac0000755000175000017500000000046313431606350020537 0ustar cheusovcheusov#!/usr/bin/env sh # Here we convert .wav files to .flac # Usage: ./run /wav/directory a_number_of_parallel_processes # Ex: ./run $HOME/wavs 7 set -e test $# -eq 2 dir="$1" # directory with .wav files num="$2" # a number of flac(1) processes ls -1 "$dir"/*.wav | paexec -x -c 'flac --silent' -n +"$num" paexec-1.1.1/examples/wav2flac/Makefile0000644000175000017500000000010513431606350017651 0ustar cheusovcheusovSCRIPTS = run SCRIPTSDIR ?= ${FILESDIR} .include paexec-1.1.1/README0000644000175000017500000000230213431606350013547 0ustar cheusovcheusov====================================================================== paexec: Small program that processes a list of tasks in parallel on different CPUs, computers in a network or whatever. Full documentation is available in paexec.1 and paexec.pod. paexec.pdf presentation is also available in presentation/ subdirectory. author: Aleksey Cheusov project's home page: http://sourceforge.net/projects/paexec/ http://freecode.com/projects/paexec/ source code: http://github.com/cheusov/paexec licence: MIT license ====================================================================== INSTALLATION See INSTALL file ====================================================================== PACKAGES 1) pkgsrc (NetBSD, DragonFlyBSD, Linux, Solaris...) See parallel/paexec (http://pkgsrc.se/parallel/paexec) 2) FreeBSD See devel/paexec (http://www.freshports.org/devel/paexec) 3) See https://freecode.com/projects/paexec for latest information paexec-1.1.1/tests/0000755000175000017500000000000013431606350014034 5ustar cheusovcheusovpaexec-1.1.1/tests/Makefile.inc0000644000175000017500000000003313431606350016240 0ustar cheusovcheusov.include "../Makefile.inc" paexec-1.1.1/tests/scripts/0000755000175000017500000000000013431606350015523 5ustar cheusovcheusovpaexec-1.1.1/tests/scripts/paexec_notransport0000755000175000017500000000022213431606350021363 0ustar cheusovcheusov#!/usr/bin/env sh shift # skip node unset PAEXEC_EOT # unset variables used in regression tests unset ZZZZ unset YYYY unset CCCC # eval "$@" paexec-1.1.1/tests/scripts/big_result_cmd.in0000755000175000017500000000035413431606350021042 0ustar cheusovcheusov#!@awk@ -f BEGIN { eot = ENVIRON ["PAEXEC_EOT"] } { for (i=0; i < 10000; ++i){ # works fine for empty input too print toupper($0) } print eot # end of task marker fflush() # end of task MUST BE FLUSHED!!! } paexec-1.1.1/tests/scripts/transport_broken_rnd.in0000755000175000017500000000130613431606350022315 0ustar cheusovcheusov#!@awk@ -f function sleep (secs){ if (!nosleep && 0 != system("sleep " secs)){ exit 10 } } function my_rnd (){ if (rand() < threshold) return -1 # return unusual value for exiting with error else return rand() } BEGIN { threshold = ARGV [1] + 0.0 fake_cmd = ARGV [2] nosleep = ARGV [1] ~ /ns/ nopostfail = ARGV [1] ~ /nopostfail/ ARGV [1] = "-" ARGV [2] = "" srand() # FreeBSD's /usr/bin/awk generates very bad first random value. # This is why we run rand() twice. rand() } { rnd = my_rnd() if (rnd < 0.0) { sleep(0.1) exit 1 } sleep(rnd) print " " $0 rnd = my_rnd() if (!nopostfail && rnd < 0.0) { sleep(0.1) exit 1 } print "success" print "" fflush() } paexec-1.1.1/tests/scripts/transport_broken_echo.in0000755000175000017500000000104513431606350022450 0ustar cheusovcheusov#!@awk@ -f BEGIN { if (ARGC != 3){ print "usage: transport_broken_echo id ''" > "/dev/stderr" exit 77 } id = ARGV [1] ARGV [1] = "-" ARGV [2] = "" # emulate totally broken NODE==4 if (id == 4){ system("sleep 1") exit 3 } } { print "I'll output " $1 if ($1 == id && id >= 1){ # emulate broken TASK==NODE where NODE >= 1 exit 1 } print $1 # echoing input print "success" # This is a keyword! Not a random word ;-) print "" # end of task marker fflush() # end of task MUST BE FLUSHED!!! } paexec-1.1.1/tests/scripts/transport_broken_echo20000755000175000017500000000073513431606350022132 0ustar cheusovcheusov#!/usr/bin/env sh # # usage: transport # fn=$1 shift id=$1 shift if test "$id" -eq 1 && ! test -f "$fn"; then # fails if there is not file and = 1 touch "$fn" exit 12 fi if test "$id" -eq 2; then # fails = 2 with 3 secs timeout read task sleep 3 echo task exit 11 fi # succeeds in all other cases while read task; do echo "output $task" echo success echo '' done paexec-1.1.1/tests/scripts/transport_broken_toupper.in0000755000175000017500000000072213431606350023231 0ustar cheusovcheusov#!@awk@ -f BEGIN { if (ARGC != 3){ print "usage: transport_broken_toupper id ''" > "/dev/stderr" exit 77 } id = ARGV [1] ARGV [1] = "-" ARGV [2] = "" # emulate totally broken NODE==4 if (id == 4){ system("sleep 1") exit 3 } } { if ($1 == id && id >= 1){ # emulate broken TASK==NODE where NODE >= 1 exit 1 } print toupper($1) # uppering input print "" # end of task marker fflush() # end of task MUST BE FLUSHED!!! } paexec-1.1.1/tests/scripts/Makefile0000644000175000017500000000025013431606350017160 0ustar cheusovcheusovINSCRIPTS = big_result_cmd transport_broken_rnd \ transport_broken_echo transport_broken_toupper SCRIPTS = paexec_notransport ${INSCRIPTS} .include paexec-1.1.1/tests/test.sh0000755000175000017500000017543613431606350015372 0ustar cheusovcheusov#!/usr/bin/env sh export LC_ALL=C #EXEPREFIX='valgrind -q' #EXEPREFIX='env EF_PROTECT_BELOW=1 ef' export PATH=`pwd`/fakeflac:$PATH DIFF_PROG=${DIFF_PROG-diff -U10} OBJDIR=${OBJDIR-..} SRCDIR=${SRCDIR-..} runtest (){ $EXEPREFIX paexec "$@" 2>&1 } runtest_resort (){ $EXEPREFIX paexec "$@" 2>&1 | resort } runpaargs (){ $EXEPREFIX paargs "$@" 2>&1 } cut_version (){ awk '$1 == "paexec" || $1 == "paargs" {$2 = "x.y.x"} {print}' } cut_help (){ awk '/^OPTIONS/ {exit 0} {print}' } cut_full_path_closed_stdin (){ sed 's|^\(.*\) [^ ]*\(transport_closed_stdin.*\)$|\1 \2|' } spc2semicolon (){ tr ' ' ';' } resort (){ awk '{print $1, NR, $0}' | sort -k1,1n -k2,2n | awk '{sub(/^[^ ]+ [^ ]+ /, ""); print $0}' } gln (){ awk -v task=$1 ' $2 == task { ln = NR; tn = $1} $1 == tn && $2 == "success" {print ln; exit} $1 == tn && $2 == "failure" {print "f"; exit} $2 == "failure" {tf [$1] = 1} $1 in tf { for (i=3; i <= NF; ++i) {fail [$i] = 1} } END { if (task in fail) {print "rf"} } ' $OBJDIR/_test.tmp } filter_succeded_tasks (){ awk ' $3 == "success" { print $2, hash [$1, $2] next } $3 != "fatal" { hash [$1, $2] = $3 }' } test_tasks1 (){ cat< $tmpex cmp (){ # $1 - progress message # $2 - expected text printf ' %s... ' "$1" 1>&2 cat > "$tmpfn2" printf '%s' "$2" > "$tmpfn1" if $DIFF_PROG "$tmpfn1" "$tmpfn2" > "$tmpfn3"; then echo ok else echo FAILED awk '{print " " $0}' "$tmpfn3" rm -f $tmpex fi } do_test (){ runpaargs -V | cut_version | cmp 'paargs -V' 'paargs x.y.x written by Aleksey Cheusov ' runpaargs -h 2>&1 | cut_help | cmp 'paargs -h' 'paargs -- wrapper for paexec usage: paargs [OPTIONS] ' runpaargs -t ssh -P localhost < /dev/null 2>&1 | cmp 'paargs missing free arguments' \ 'paargs: missing arguments. Run paargs -h for details ' printf 'AAA\nBBB\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\nZ Y X\n' | runpaargs -P +3 -I '{}' echo xxx '{}' yyy | paexec_reorder -lgy -Ms | cmp 'paargs -P #1.1' \ '1 xxx AAA yyy 1 success 2 xxx BBB yyy 2 success 3 xxx TRTRTR'"'"'BRBRBR yyy 3 success 4 xxx CCC yyy 4 success 5 xxx DDD yyy 5 success 6 xxx EEE yyy 6 success 7 xxx FFF yyy 7 success 8 xxx "Y;X yyy 8 success 9 xxx GGG yyy 9 success 10 xxx Z Y X yyy 10 success ' # -J printf 'aaa\nbbb\nz y x\ntrtrtrbrbrbr\nccc\nddd\neee\nfff\ny;x\nggg\n' | runpaargs -P+2 -I '$$' -c 'awk "BEGIN {print toupper(\"$$\")}"' | paexec_reorder -lgy -Ms | cmp 'paargs -P #1.2' \ '1 AAA 1 success 2 BBB 2 success 3 Z Y X 3 success 4 TRTRTRBRBRBR 4 success 5 CCC 5 success 6 DDD 6 success 7 EEE 7 success 8 FFF 8 success 9 Y;X 9 success 10 GGG 10 success ' printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runpaargs -P +3 -I '{}' -c 'echo "{} is equal to {}"' | paexec_reorder -lgy -Ms | cmp 'paargs -J #1.3' \ '1 AAA is equal to AAA 1 success 2 BBB is equal to BBB 2 success 3 Z Y X is equal to Z Y X 3 success 4 TRTRTR'"'"'BRBRBR is equal to TRTRTR'"'"'BRBRBR 4 success 5 CCC is equal to CCC 5 success 6 DDD is equal to DDD 6 success 7 EEE is equal to EEE 7 success 8 FFF is equal to FFF 8 success 9 "Y;X is equal to "Y;X 9 success 10 GGG is equal to GGG 10 success ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runpaargs -I '{}' -c "echo '{} is equal to {}'" -P +3 | paexec_reorder -lgy -Ms | cmp 'paargs -J #1.4' \ '1 $1 is equal to $1 1 success 2 $1 is equal to $1 2 success 3 $1 is equal to $1 3 success 4 $1 is equal to $1 4 success 5 $1 is equal to $1 5 success 6 $1 is equal to $1 6 success 7 $1 is equal to $1 7 success 8 $1 is equal to $1 8 success 9 $1 is equal to $1 9 success 10 $1 is equal to $1 10 success ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runpaargs -P+3 -I '{}' echo '{}' is equal to '{}' | paexec_reorder -lgy -Ms | cmp 'paargs -J #1.5' \ '1 AAA is equal to AAA 1 success 2 BBB is equal to BBB 2 success 3 Z Y X is equal to Z Y X 3 success 4 TRTRTR'"'"'BRBRBR is equal to TRTRTR'"'"'BRBRBR 4 success 5 CCC is equal to CCC 5 success 6 DDD is equal to DDD 6 success 7 EEE is equal to EEE 7 success 8 FFF is equal to FFF 8 success 9 "Y;X is equal to "Y;X 9 success 10 GGG is equal to GGG 10 success ' printf 'aaa\nbbb\nz y x\ntrtrtr'\''brbrbr\nccc\nddd\neee\nfff\n"y;x\nggg\n' | runpaargs -P+3 awk 'BEGIN {print toupper(ARGV [1])}' | paexec_reorder -lgy -Ms | cmp 'paargs #1.1' \ '1 AAA 1 success 2 BBB 2 success 3 Z Y X 3 success 4 TRTRTR'"'"'BRBRBR 4 success 5 CCC 5 success 6 DDD 6 success 7 EEE 7 success 8 FFF 8 success 9 "Y;X 9 success 10 GGG 10 success ' # -x + -t export PAEXEC_ENV=' ZZZZ, , ,YYYY,CCCC LALALA ' export ZZZZ=zz1234zz export YYYY=yy1234yy export CCCC=cc1234cc printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runpaargs -t paexec_notransport \ -P '1 2 3 4 5 6 7 8 9' \ awk 'BEGIN {print ENVIRON["ZZZZ"], ENVIRON["YYYY"], ENVIRON["CCCC"], ENVIRON["LALALA"], toupper(ARGV[1])}' | paexec_reorder -lgy -Ms | grep -v success | resort | cmp 'paargs -t #1 (PAEXEC_ENV)' \ '1 zz1234zz yy1234yy cc1234cc A 2 zz1234zz yy1234yy cc1234cc BB 3 zz1234zz yy1234yy cc1234cc CCC 4 zz1234zz yy1234yy cc1234cc DDDD 5 zz1234zz yy1234yy cc1234cc EEEEE 6 zz1234zz yy1234yy cc1234cc FFFFFF ' unset ZZZZ YYYY CCCC PAEXEC_ENV # runpaargs -t ssh -P localhost -c echo file1 file2 < /dev/null 2>&1 | cmp 'paargs bad files' \ 'paargs: extra arguments. Run paargs -h for details ' ############################################################ runtest -V | cut_version | cmp 'paexec -V' 'paexec x.y.x written by Aleksey Cheusov ' runtest -h 2>&1 | cut_help | cmp 'paexec -h' 'paexec -- parallel executor that distributes tasks over CPUs or machines in a network. usage: paexec [OPTIONS] paexec -C [OPTIONS] cmd [args...] ' # bad -md= arg runtest -cfake -n+3 -md=aa 2>&1 | cmp 'paexec -md= #1' 'paexec: bad argument for -md=. At most one character is allowed ' # bad -ms=/-mf/-mF arg runtest -ms='lalala"trtrtr' 2>&1 | cmp 'paexec -ms= bad #1.1' 'paexec: symbols '\'' and " are not allowed in -m argument ' runtest -ms="lalala'trtrtr" 2>&1 | cmp 'paexec -ms= bad #1.2' 'paexec: symbols '\'' and " are not allowed in -m argument ' runtest -ms='lalala"trtrtr' 2>&1 | cmp 'paexec -mf= bad #1.1' 'paexec: symbols '\'' and " are not allowed in -m argument ' runtest -ms="lalala'trtrtr" 2>&1 | cmp 'paexec -mf= bad #1.2' 'paexec: symbols '\'' and " are not allowed in -m argument ' runtest -ms='lalala"trtrtr' 2>&1 | cmp 'paexec -mF= bad #1.1' 'paexec: symbols '\'' and " are not allowed in -m argument ' runtest -ms="lalala'trtrtr" 2>&1 | cmp 'paexec -mF= bad #1.2' 'paexec: symbols '\'' and " are not allowed in -m argument ' # bad use runtest -l -t dummy -c dummy -n ',bad arg' < /dev/null 2>&1 | cmp 'paexec bad -n #1' \ 'paexec: invalid argument for option -n ' runtest -t ssh -n +32 < /dev/null 2>&1 | cmp 'paexec bad -c' \ 'paexec: -c option is mandatory! ' runtest -t ssh -n localhost -x -c echo file1 file2 < /dev/null 2>&1 | cmp 'paexec bad files' \ 'paexec: extra arguments. Run paexec -h for details ' runtest -t ssh -n localhost -Cx < /dev/null 2>&1 | cmp 'paexec bad -C' \ 'paexec: missing arguments. Run paexec -h for details ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runtest -J '{}' -c 'echo "xxx{}yyy"' -n +3 | sort | cmp 'paexec -J #1.1' \ 'xxx"Y;Xyyy xxxAAAyyy xxxBBByyy xxxCCCyyy xxxDDDyyy xxxEEEyyy xxxFFFyyy xxxGGGyyy xxxTRTRTR'"'"'BRBRBRyyy xxxZ Y Xyyy ' # -J printf 'aaa\nbbb\nz y x\ntrtrtrbrbrbr\nccc\nddd\neee\nfff\ny;x\nggg\n' | runtest -n+2 -J '$$' -c 'awk "BEGIN {print toupper(\"$$\")}"' | sort | cmp 'paexec -J #1.2' \ 'AAA BBB CCC DDD EEE FFF GGG TRTRTRBRBRBR Y;X Z Y X ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runtest -J '{}' -c 'echo "{} is equal to {}"' -n +3 | sort | cmp 'paexec -J #1.3' \ '"Y;X is equal to "Y;X AAA is equal to AAA BBB is equal to BBB CCC is equal to CCC DDD is equal to DDD EEE is equal to EEE FFF is equal to FFF GGG is equal to GGG TRTRTR'"'"'BRBRBR is equal to TRTRTR'"'"'BRBRBR Z Y X is equal to Z Y X ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runtest -J '{}' -c "echo '{} is equal to {}'" -n +3 | sort | cmp 'paexec -J #1.4' \ '$1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 $1 is equal to $1 ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runtest -n +3 -J '{}' -C echo '{}' 'is equal to' '{}' | sort | cmp 'paexec -J #1.5' \ '"Y;X is equal to "Y;X AAA is equal to AAA BBB is equal to BBB CCC is equal to CCC DDD is equal to DDD EEE is equal to EEE FFF is equal to FFF GGG is equal to GGG TRTRTR'"'"'BRBRBR is equal to TRTRTR'"'"'BRBRBR Z Y X is equal to Z Y X ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runtest -n +3 -J '{}' -C echo '{}' is not equal to ' {}' | sort | cmp 'paexec -J #1.6' \ '"Y;X is not equal to $1 AAA is not equal to $1 BBB is not equal to $1 CCC is not equal to $1 DDD is not equal to $1 EEE is not equal to $1 FFF is not equal to $1 GGG is not equal to $1 TRTRTR'"'"'BRBRBR is not equal to $1 Z Y X is not equal to $1 ' # -J printf 'AAA\nBBB\nZ Y X\nTRTRTR'\''BRBRBR\nCCC\nDDD\nEEE\nFFF\n"Y;X\nGGG\n' | runtest -n +3 -J '{}' -C echo '{}/' is not equal to '{}' | sort | cmp 'paexec -J #1.7' \ '$1/ is not equal to "Y;X $1/ is not equal to AAA $1/ is not equal to BBB $1/ is not equal to CCC $1/ is not equal to DDD $1/ is not equal to EEE $1/ is not equal to FFF $1/ is not equal to GGG $1/ is not equal to TRTRTR'"'"'BRBRBR $1/ is not equal to Z Y X ' # x printf 'aaa\nbbb\nz y x\ntrtrtr'\''brbrbr\nccc\nddd\neee\nfff\n"y;x\nggg\n' | runtest -x -c "awk 'BEGIN {print toupper(ARGV [1])}'" -n +3 | sort | cmp 'paexec -x #1.1' \ '"Y;X AAA BBB CCC DDD EEE FFF GGG TRTRTR'"'"'BRBRBR Z Y X ' # x export PAEXEC_NODES=+3 printf 'aaa\nbbb\nz y x\ntrtrtr'\''brbrbr\nccc\nddd\neee\nfff\n"y;x\nggg\n' | runtest -x -c "awk 'BEGIN {print toupper(ARGV [1])}'" | sort | cmp 'paexec -x #1.1.1 (PAEXEC_NODES)' \ '"Y;X AAA BBB CCC DDD EEE FFF GGG TRTRTR'"'"'BRBRBR Z Y X ' export PAEXEC_NODES printf 'aaa\nbbb\nz y x\ntrtrtr'\''brbrbr\nccc\nddd\neee\nfff\n"y;x\nggg\n' | runtest -xCn+3 -- awk 'BEGIN {print toupper(ARGV [1])}' | sort | cmp 'paexec -x #1.2' \ '"Y;X AAA BBB CCC DDD EEE FFF GGG TRTRTR'"'"'BRBRBR Z Y X ' printf 'aaa\nbbb\nz y x\ntrtrtr'\''brbrbr\nccc\nddd\neee\nfff\n"y;x\nggg\n' | runtest -el -x -c 'awk "BEGIN {print toupper(ARGV[1])}"' -n +4 | paexec_reorder -x -Ms | cmp 'paexec -x #2' \ 'AAA BBB Z Y X TRTRTR'"'"'BRBRBR CCC DDD EEE FFF "Y;X GGG ' # x rm -f fakeflac/*.flac ls -1 fakeflac/*.wav | runtest -x -c 'flac --silent' -n +3 -p | sed 's/[0-9][0-9]*/NNN/' | cmp 'paexec -x (flac) #2.1' \ 'NNN NNN NNN NNN NNN '; ls -1 fakeflac/*.flac 2>/dev/null | sed 's,.*/,,' | sort | cmp 'paexec -x (flac) #2.2' \ 'fake1.flac fake2.flac fake3.flac fake4.flac fake5.flac ' rm -f fakeflac/*.flac; # x run_wav2flac ./fakeflac 3 | cmp 'paexec -x (flac) #3.1' \ ' ' # -X rm -f fakeflac/*.flac ls -1 fakeflac/*.wav | runtest -X -c 'flac --silent' -n +3 -p | cmp 'paexec -X (flac) #3.1.1' \ '' ls -1 fakeflac/*.flac | sort | cmp 'paexec -X (flac) #3.1.2' \ 'fakeflac/fake1.flac fakeflac/fake2.flac fakeflac/fake3.flac fakeflac/fake4.flac fakeflac/fake5.flac ' # -X rm -f fakeflac/*.flac ls -1 fakeflac/*.wav | runtest -Xg -c 'flac --silent' -n +3 | cmp 'paexec -X (flac) #3.1.3' \ 'success success success success success ' ls -1 fakeflac/*.flac | sort | cmp 'paexec -X (flac) #3.1.4' \ 'fakeflac/fake1.flac fakeflac/fake2.flac fakeflac/fake3.flac fakeflac/fake4.flac fakeflac/fake5.flac ' # x ls -1 fakeflac/*.flac 2>/dev/null | sed 's,.*/,,' | sort | cmp 'paexec -x (flac) #3.2' \ 'fake1.flac fake2.flac fake3.flac fake4.flac fake5.flac ' rm -f fakeflac/*.flac; # x ( cd ..; run_dirtest < examples/dirtest/tasks ) | paexec_reorder -l -Mm | cmp 'paexec -x (dirtest) #4' \ '1 failure 1 /nonexistant;/nonexistant/subdir;/nonexistant/subdir/subsubdir 4 success 5 success 6 success 7 success 8 success 9 success 10 success 11 success 12 success 13 success 14 success 15 success 16 success 17 success 18 failure 18 /etc/dir with spaces;/etc/dir with spaces/subdir ' find . -type f -name '*.wav' -print0 | runtest -n+6 -0x -C echo | sort | sed 's|^[.]/||' | cmp 'paexec -0' \ 'fakeflac/fake1.wav fakeflac/fake2.wav fakeflac/fake3.wav fakeflac/fake4.wav fakeflac/fake5.wav ' # toupper printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest_resort -l -t paexec_notransport -c cmd_toupper \ -n '1 2 3 4 5 6 7 8 9' | cmp 'paexec toupper #1' \ '1 A 2 BB 3 CCC 4 DDDD 5 EEEEE 6 FFFFFF ' export PAEXEC_TRANSPORT=paexec_notransport printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest_resort -l -c cmd_toupper \ -n '1 2 3 4 5 6 7 8 9' | cmp 'paexec toupper #1.0.1 (PAEXEC_TRANSPORT)' \ '1 A 2 BB 3 CCC 4 DDDD 5 EEEEE 6 FFFFFF ' unset PAEXEC_TRANSPORT # toupper printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | ( export PAEXEC_EOT=foobarbaz; runtest_resort -l -t paexec_notransport -c cmd_toupper \ -n '1 2 3 4 5 6 7 8 9'; ) | cmp 'paexec toupper #1.1 (PAEXEC_EOT)' \ '1 A 2 BB 3 CCC 4 DDDD 5 EEEEE 6 FFFFFF ' # toupper printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest_resort -l -t ' ' -c cmd_toupper \ -n '1 2 3 4 5 6 7 8 9' | cmp 'paexec toupper #2' \ '1 A 2 BB 3 CCC 4 DDDD 5 EEEEE 6 FFFFFF ' printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest_resort -l -c cmd_toupper \ -n '1 2 3 4 5 6 7 8 9' | cmp 'paexec toupper #3' \ '1 A 2 BB 3 CCC 4 DDDD 5 EEEEE 6 FFFFFF ' printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest_resort -l -p -t paexec_notransport \ -c cmd_toupper -n '+2' | awk '$1 ~ /^[0-9]/ {$2 = "pid"; print; next} {print}' | cmp 'paexec toupper #4' \ '1 pid A 2 pid BB 3 pid CCC 4 pid DDDD 5 pid EEEEE 6 pid FFFFFF ' export PAEXEC_NODES=+2 printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -p -t paexec_notransport \ -c cmd_toupper | resort | awk '$1 ~ /^[0-9]/ {$2 = "pid"; print; next} {print}' | cmp 'paexec toupper #4.0.1 (PAEXEC_NODES)' \ '1 pid A 2 pid BB 3 pid CCC 4 pid DDDD 5 pid EEEEE 6 pid FFFFFF ' unset PAEXEC_NODES printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -p -t '' \ -c cmd_toupper -n '+2' | resort | awk '$1 ~ /^[0-9]/ {$2 = "pid"; print; next} {print}' | cmp 'paexec toupper #5' \ '1 pid A 2 pid BB 3 pid CCC 4 pid DDDD 5 pid EEEEE 6 pid FFFFFF ' printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -p \ -c cmd_toupper -n '+2' | resort | awk '$1 ~ /^[0-9]/ {$2 = "pid"; print; next} {print}' | cmp 'paexec toupper #6' \ '1 pid A 2 pid BB 3 pid CCC 4 pid DDDD 5 pid EEEEE 6 pid FFFFFF ' printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -p \ -c cmd_toupper -n '+2' | resort | awk '$1 ~ /^[0-9]/ {$2 = "pid"; print; next} {print}' | cmp 'paexec toupper #6' \ '1 pid A 2 pid BB 3 pid CCC 4 pid DDDD 5 pid EEEEE 6 pid FFFFFF ' # all_substr printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -c cmd_all_substr \ -n '1 2 3 4 5 6 7 8 9' | resort | cmp 'paexec all_substr #1.1' \ '1 substr[1,1]=a 2 substr[1,1]=b 2 substr[1,2]=bb 2 substr[2,1]=b 3 substr[1,1]=c 3 substr[1,2]=cc 3 substr[1,3]=ccc 3 substr[2,1]=c 3 substr[2,2]=cc 3 substr[3,1]=c 4 substr[1,1]=d 4 substr[1,2]=dd 4 substr[1,3]=ddd 4 substr[1,4]=dddd 4 substr[2,1]=d 4 substr[2,2]=dd 4 substr[2,3]=ddd 4 substr[3,1]=d 4 substr[3,2]=dd 4 substr[4,1]=d 5 substr[1,1]=e 5 substr[1,2]=ee 5 substr[1,3]=eee 5 substr[1,4]=eeee 5 substr[1,5]=eeeee 5 substr[2,1]=e 5 substr[2,2]=ee 5 substr[2,3]=eee 5 substr[2,4]=eeee 5 substr[3,1]=e 5 substr[3,2]=ee 5 substr[3,3]=eee 5 substr[4,1]=e 5 substr[4,2]=ee 5 substr[5,1]=e 6 substr[1,1]=f 6 substr[1,2]=ff 6 substr[1,3]=fff 6 substr[1,4]=ffff 6 substr[1,5]=fffff 6 substr[1,6]=ffffff 6 substr[2,1]=f 6 substr[2,2]=ff 6 substr[2,3]=fff 6 substr[2,4]=ffff 6 substr[2,5]=fffff 6 substr[3,1]=f 6 substr[3,2]=ff 6 substr[3,3]=fff 6 substr[3,4]=ffff 6 substr[4,1]=f 6 substr[4,2]=ff 6 substr[4,3]=fff 6 substr[5,1]=f 6 substr[5,2]=ff 6 substr[6,1]=f ' # all_substr printf '1\n2\n3\n4\n5\n6\n7\n8\n9\n' > "$tmpfn4" printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -c cmd_all_substr \ -n ":$tmpfn4" | resort | cmp 'paexec all_substr #1.2' \ '1 substr[1,1]=a 2 substr[1,1]=b 2 substr[1,2]=bb 2 substr[2,1]=b 3 substr[1,1]=c 3 substr[1,2]=cc 3 substr[1,3]=ccc 3 substr[2,1]=c 3 substr[2,2]=cc 3 substr[3,1]=c 4 substr[1,1]=d 4 substr[1,2]=dd 4 substr[1,3]=ddd 4 substr[1,4]=dddd 4 substr[2,1]=d 4 substr[2,2]=dd 4 substr[2,3]=ddd 4 substr[3,1]=d 4 substr[3,2]=dd 4 substr[4,1]=d 5 substr[1,1]=e 5 substr[1,2]=ee 5 substr[1,3]=eee 5 substr[1,4]=eeee 5 substr[1,5]=eeeee 5 substr[2,1]=e 5 substr[2,2]=ee 5 substr[2,3]=eee 5 substr[2,4]=eeee 5 substr[3,1]=e 5 substr[3,2]=ee 5 substr[3,3]=eee 5 substr[4,1]=e 5 substr[4,2]=ee 5 substr[5,1]=e 6 substr[1,1]=f 6 substr[1,2]=ff 6 substr[1,3]=fff 6 substr[1,4]=ffff 6 substr[1,5]=fffff 6 substr[1,6]=ffffff 6 substr[2,1]=f 6 substr[2,2]=ff 6 substr[2,3]=fff 6 substr[2,4]=ffff 6 substr[2,5]=fffff 6 substr[3,1]=f 6 substr[3,2]=ff 6 substr[3,3]=fff 6 substr[3,4]=ffff 6 substr[4,1]=f 6 substr[4,2]=ff 6 substr[4,3]=fff 6 substr[5,1]=f 6 substr[5,2]=ff 6 substr[6,1]=f ' # all_substr printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -l -c cmd_all_substr -n '+9' | resort | cmp 'paexec all_substr #2' \ '1 substr[1,1]=a 2 substr[1,1]=b 2 substr[1,2]=bb 2 substr[2,1]=b 3 substr[1,1]=c 3 substr[1,2]=cc 3 substr[1,3]=ccc 3 substr[2,1]=c 3 substr[2,2]=cc 3 substr[3,1]=c 4 substr[1,1]=d 4 substr[1,2]=dd 4 substr[1,3]=ddd 4 substr[1,4]=dddd 4 substr[2,1]=d 4 substr[2,2]=dd 4 substr[2,3]=ddd 4 substr[3,1]=d 4 substr[3,2]=dd 4 substr[4,1]=d 5 substr[1,1]=e 5 substr[1,2]=ee 5 substr[1,3]=eee 5 substr[1,4]=eeee 5 substr[1,5]=eeeee 5 substr[2,1]=e 5 substr[2,2]=ee 5 substr[2,3]=eee 5 substr[2,4]=eeee 5 substr[3,1]=e 5 substr[3,2]=ee 5 substr[3,3]=eee 5 substr[4,1]=e 5 substr[4,2]=ee 5 substr[5,1]=e 6 substr[1,1]=f 6 substr[1,2]=ff 6 substr[1,3]=fff 6 substr[1,4]=ffff 6 substr[1,5]=fffff 6 substr[1,6]=ffffff 6 substr[2,1]=f 6 substr[2,2]=ff 6 substr[2,3]=fff 6 substr[2,4]=ffff 6 substr[2,5]=fffff 6 substr[3,1]=f 6 substr[3,2]=ff 6 substr[3,3]=fff 6 substr[3,4]=ffff 6 substr[4,1]=f 6 substr[4,2]=ff 6 substr[4,3]=fff 6 substr[5,1]=f 6 substr[5,2]=ff 6 substr[6,1]=f ' # no input runtest -c cmd_all_substr -n +3 < /dev/null | cmp 'paexec all_substr #3' '' # bad command + no input runtest -l -c /path/to/bad/prog -n +3 < /dev/null 2>/dev/null 1>&2| cmp 'paexec bad_command' '' # bi-i-i-i-i-i-ig result for i in 0 1 2 3 4 5 6 7 8 9; do awk ' BEGIN { for (i=0; i < 10; ++i) { print "1234567890-=qwertyuiop[]asdfghjkl;zxcvbnm,./zaqwsxcderfvbgtyhnmjuik,.lo"; } }' | runtest -c big_result_cmd -n '+9' | uniq -c | head -n 100 | awk '{$1 = $1; print $0}' | cmp 'paexec big_result_cmd' \ '100000 1234567890-=QWERTYUIOP[]ASDFGHJKL;ZXCVBNM,./ZAQWSXCDERFVBGTYHNMJUIK,.LO ' if test -f $tmpex; then : else break fi done # tests for partially ordered set of tasks (-s option) test_tasks3 | runtest -e -s -l -c cmd_divide -n +10 | cmp 'paexec 1/X #1' \ '1 1/1=1 1 success 1 2 1/2=0.5 2 success 2 3 1/3=0.333333 3 success 3 4 1/4=0.25 4 success 4 5 1/5=0.2 5 success 5 6 Cannot calculate 1/0 6 failure 6 0 7 8 9 10 11 12 6 ' test_tasks3 | spc2semicolon | runtest -eslmd=";" -c cmd_divide -n +10 | cmp 'paexec 1/X -md=";" #1.1' \ '1 1/1=1 1 success 1 2 1/2=0.5 2 success 2 3 1/3=0.333333 3 success 3 4 1/4=0.25 4 success 4 5 1/5=0.2 5 success 5 6 Cannot calculate 1/0 6 failure 6 0;7;8;9;10;11;12 6 ' test_tasks3 | runtest -ms='Ura!' -mf='Zhopa!' -mt='Konec!' \ -e -s -l -c cmd_divide2 -n +10 | cmp 'paexec 1/X nonstandard #1' \ '1 1/1=1 1 Ura! 1 Konec! 2 1/2=0.5 2 Ura! 2 Konec! 3 1/3=0.333333 3 Ura! 3 Konec! 4 1/4=0.25 4 Ura! 4 Konec! 5 1/5=0.2 5 Ura! 5 Konec! 6 Cannot calculate 1/0 6 Zhopa! 6 0 7 8 9 10 11 12 6 Konec! ' test_tasks3 | ( export PAEXEC_EOT='Konec!'; runtest -ms='Ura!' -mf='Zhopa!' \ -e -s -l -c cmd_divide2 -n +10; ) | cmp 'paexec 1/X nonstandard #1.1' \ '1 1/1=1 1 Ura! 1 Konec! 2 1/2=0.5 2 Ura! 2 Konec! 3 1/3=0.333333 3 Ura! 3 Konec! 4 1/4=0.25 4 Ura! 4 Konec! 5 1/5=0.2 5 Ura! 5 Konec! 6 Cannot calculate 1/0 6 Zhopa! 6 0 7 8 9 10 11 12 6 Konec! ' test_tasks3 | ( export PAEXEC_EOT='Konec!'; runtest -ms='Ura!' -mf='Zhopa!' \ -esly -c cmd_divide2 -n +10; ) | cmp 'paexec 1/X nonstandard -y #1.1' \ '1 1/1=1 1 Ura! 1 HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5 2 1/2=0.5 2 Ura! 2 HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5 3 1/3=0.333333 3 Ura! 3 HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5 4 1/4=0.25 4 Ura! 4 HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5 5 1/5=0.2 5 Ura! 5 HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5 6 Cannot calculate 1/0 6 Zhopa! 6 0 7 8 9 10 11 12 6 HG>&OSO@#;L8N;!&.U4ZC_9X:0AF,2Y>SRXAD_7U&QZ5S>N^?Y,I=W?@5 ' test_tasks3 | ( export PAEXEC_EOT='Konec!'; runtest -ms='Ura!' -mf='Zhopa!' \ -esly -c cmd_divide2 -n +10; ) | paexec_reorder -y | cmp 'paexec 1/X nonstandard -y #1.2' \ '1/1=1 Ura! 1/2=0.5 Ura! 1/3=0.333333 Ura! 1/4=0.25 Ura! 1/5=0.2 Ura! Cannot calculate 1/0 Zhopa! 0 7 8 9 10 11 12 ' test_tasks3 | ( export PAEXEC_EOT='Konec!'; export PAEXEC_TRANSPORT=lalala; runtest -ms='Ura!' -mf='Zhopa!' \ -esly -c cmd_divide2 -n +10; ) | paexec_reorder -y | cmp 'paexec 1/X nonstandard -y #1.2.1 (PAEXEC_TRANSPORT)' \ '1/1=1 Ura! 1/2=0.5 Ura! 1/3=0.333333 Ura! 1/4=0.25 Ura! 1/5=0.2 Ura! Cannot calculate 1/0 Zhopa! 0 7 8 9 10 11 12 ' # -s and no input runtest -s -l -c cmd_divide -n +10 < /dev/null | cmp 'paexec 1/X #2' '' runtest -ms='Ura!' -mf='Zhopa!' -mt='Konec!' \ -s -l -c cmd_divide -n +10 < /dev/null | cmp 'paexec 1/X nonstandard #2' '' ( export PAEXEC_EOT='Konec!'; runtest -ms='Ura!' -mf='Zhopa!' \ -s -l -c cmd_divide -n +10 < /dev/null; ) | cmp 'paexec 1/X nonstandard #2.1' '' # paexec_reorder + failure test_tasks4 | runtest -se -l -c cmd_divide -n +1 | paexec_reorder -gl | cmp 'paexec 1/X #3' \ '1 1/1=1 1 success 2 1/2=0.5 2 success 3 1/3=0.333333 3 success 4 1/4=0.25 4 success 5 1/5=0.2 5 success 6 Cannot calculate 1/0 6 failure 6 0 7 8 9 10 1/10=0.1 10 success 11 1/11=0.0909091 11 success 12 1/12=0.0833333 12 success ' test_tasks4 | runtest -ms='Ura!' -mf='Zhopa!' -mt='Konec!' \ -se -l -c cmd_divide2 -n +1 | paexec_reorder -gl -ms='Ura!' -mf='Zhopa!' -mt='Konec!' | cmp 'paexec 1/X nonstandard #3' \ '1 1/1=1 1 Ura! 2 1/2=0.5 2 Ura! 3 1/3=0.333333 3 Ura! 4 1/4=0.25 4 Ura! 5 1/5=0.2 5 Ura! 6 Cannot calculate 1/0 6 Zhopa! 6 0 7 8 9 10 1/10=0.1 10 Ura! 11 1/11=0.0909091 11 Ura! 12 1/12=0.0833333 12 Ura! ' test_tasks4 | ( export PAEXEC_EOT='Konec!'; runtest -ms='Ura!' -mf='Zhopa!' \ -se -l -c cmd_divide2 -n +1 | paexec_reorder -gl -ms='Ura!' -mf='Zhopa!'; ) | cmp 'paexec 1/X nonstandard #3.1' \ '1 1/1=1 1 Ura! 2 1/2=0.5 2 Ura! 3 1/3=0.333333 3 Ura! 4 1/4=0.25 4 Ura! 5 1/5=0.2 5 Ura! 6 Cannot calculate 1/0 6 Zhopa! 6 0 7 8 9 10 1/10=0.1 10 Ura! 11 1/11=0.0909091 11 Ura! 12 1/12=0.0833333 12 Ura! ' # paexec_reorder + failure ( cd ../examples/divide; ./run_divide; ) | sed 's/^[^ ]* //' | sort | cmp 'paexec 1/X #4' \ '0 7 8 9 1/10=0.1 1/11=0.0909091 1/12=0.0833333 1/1=1 1/2=0.5 1/3=0.333333 1/4=0.25 1/5=0.2 Cannot calculate 1/0 failure success success success success success success success success ' ( cd ../examples/divide; ./run_divide2; ) | sed 's/^[^ ]* //' | sort | cmp 'paexec 1/X #4 nonstandard' \ '0 7 8 9 1/10=0.1 1/11=0.0909091 1/12=0.0833333 1/1=1 1/2=0.5 1/3=0.333333 1/4=0.25 1/5=0.2 Cannot calculate 1/0 Ura! Ura! Ura! Ura! Ura! Ura! Ura! Ura! Zhopa! ' # -s all failed runtest -s -l -c 'cmd_xxx_failed_make_package .' -n +10 < /dev/null | cmp 'paexec all fails #1.1' '' runtest -n +10 -sCl cmd_xxx_failed_make_package . < /dev/null | cmp 'paexec all fails #1.2' '' # -s all failed runtest -s -l -c 'cmd_xxx_failed_make_package .' -n +5 < /dev/null | cmp 'paexec all fails #2' '' # -s all failed runtest -s -l -c 'cmd_xxx_failed_make_package .' -n +1 < /dev/null | cmp 'paexec all fails #3' '' # -s: all succeeded runtest -l -s -c cmd_make_package -n +2 \ > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/libmaa`" -lt "`gln wip/dict-server`" && echo ok6 test "`gln wip/libmaa`" -lt "`gln wip/dict-client`" && echo ok7 test "`gln devel/m4`" -lt "`gln wip/dict-server`" && echo ok8 test "`gln devel/byacc`" -lt "`gln wip/dict-client`" && echo ok9 test "`gln devel/byacc`" -lt "`gln wip/dict-server`" && echo ok10 test "`gln devel/flex`" -lt "`gln wip/dict-client`" && echo ok11 test "`gln devel/flex`" -lt "`gln wip/dict-server`" && echo ok12 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 22 && echo ok100 } | cmp 'paexec packages #1' \ 'ok1 ok2 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok11 ok12 ok100 ' # -s: byacc fails runtest -l -s -c 'cmd_xxx_failed_make_package byacc' \ -n +3 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/libmaa`" -gt 0 && echo ok6 test "`gln devel/m4`" -gt 0 && echo ok7 test "`gln devel/flex`" -gt 0 && echo ok8 test "`gln devel/byacc`" = f && echo ok9 test "`gln wip/dict-server`" = "rf" && echo ok10 test "`gln wip/dict-client`" = "rf" && echo ok11 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 19 && echo ok100 } | cmp 'paexec packages #2' \ 'ok1 ok2 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok11 ok100 ' # -s: flex fails runtest -l -s -c 'cmd_xxx_failed_make_package flex' \ -n +5 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/libmaa`" -gt 0 && echo ok6 test "`gln devel/m4`" -gt 0 && echo ok7 test "`gln devel/byacc`" -gt 0 && echo ok8 test "`gln devel/flex`" = f && echo ok9 test "`gln wip/dict-server`" = "rf" && echo ok10 test "`gln wip/dict-client`" = "rf" && echo ok11 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 19 && echo ok100 } | cmp 'paexec packages #3' \ 'ok1 ok2 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok11 ok100 ' # -s: libmaa fails runtest -l -s -c 'cmd_xxx_failed_make_package libmaa' \ -n +6 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -gt 0 && echo ok4 test "`gln devel/gmake`" -gt 0 && echo ok5 test "`gln devel/flex`" -gt 0 && echo ok66 test "`gln devel/m4`" -gt 0 && echo ok7 test "`gln devel/byacc`" -gt 0 && echo ok8 test "`gln wip/libmaa`" = f && echo ok9 test "`gln wip/dict-server`" = "rf" && echo ok10 test "`gln wip/dict-client`" = "rf" && echo ok11 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 19 && echo ok100 } | cmp 'paexec packages #4' \ 'ok1 ok2 ok3 ok4 ok5 ok66 ok7 ok8 ok9 ok10 ok11 ok100 ' # -s: m4 fails runtest -l -s -c 'cmd_xxx_failed_make_package m4' \ -n +4 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln devel/flex`" -lt "`gln wip/dict-client`" && echo ok6 test "`gln devel/byacc`" -lt "`gln wip/dict-client`" && echo ok7 test "`gln wip/libmaa`" -lt "`gln wip/dict-client`" && echo ok8 test "`gln devel/m4`" = f && echo ok9 test "`gln wip/dict-server`" = "rf" && echo ok10 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 21 && echo ok100 } | cmp 'paexec packages #5' \ 'ok1 ok2 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok100 ' # -s: libjudy fails runtest -l -s -c 'cmd_xxx_failed_make_package libjudy' \ -n +2 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/libmaa`" -lt "`gln wip/dict-server`" && echo ok6 test "`gln wip/libmaa`" -lt "`gln wip/dict-client`" && echo ok7 test "`gln devel/m4`" -lt "`gln wip/dict-server`" && echo ok8 test "`gln devel/byacc`" -lt "`gln wip/dict-client`" && echo ok9 test "`gln devel/byacc`" -lt "`gln wip/dict-server`" && echo ok10 test "`gln devel/flex`" -lt "`gln wip/dict-client`" && echo ok11 test "`gln devel/flex`" -lt "`gln wip/dict-server`" && echo ok12 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 23 && echo ok100 } | cmp 'paexec packages #6' \ 'ok1 ok2 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok11 ok12 ok100 ' # -s: dictem fails runtest -l -s -c 'cmd_xxx_failed_make_package dictem' \ -n +3 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/libmaa`" -lt "`gln wip/dict-server`" && echo ok6 test "`gln wip/libmaa`" -lt "`gln wip/dict-client`" && echo ok7 test "`gln devel/m4`" -lt "`gln wip/dict-server`" && echo ok8 test "`gln devel/byacc`" -lt "`gln wip/dict-client`" && echo ok9 test "`gln devel/byacc`" -lt "`gln wip/dict-server`" && echo ok10 test "`gln devel/flex`" -lt "`gln wip/dict-client`" && echo ok11 test "`gln devel/flex`" -lt "`gln wip/dict-server`" && echo ok12 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 23 && echo ok100 } | cmp 'paexec packages #7' \ 'ok1 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok11 ok12 ok100 ' # -s: glib2 fails runtest -l -s -c 'cmd_xxx_failed_make_package glib2' \ -n +6 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/libmaa`" -lt "`gln wip/dict-server`" && echo ok6 test "`gln wip/libmaa`" -lt "`gln wip/dict-client`" && echo ok7 test "`gln devel/m4`" -lt "`gln wip/dict-server`" && echo ok8 test "`gln devel/byacc`" -lt "`gln wip/dict-client`" && echo ok9 test "`gln devel/byacc`" -lt "`gln wip/dict-server`" && echo ok10 test "`gln devel/flex`" -lt "`gln wip/dict-client`" && echo ok11 test "`gln devel/flex`" -lt "`gln wip/dict-server`" && echo ok12 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 23 && echo ok100 } | cmp 'paexec packages #8' \ 'ok2 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok10 ok11 ok12 ok100 ' # -s: gmake fails runtest -l -s -c 'cmd_xxx_failed_make_package gmake' -n +5 \ > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -gt 0 && echo ok4 test "`gln devel/gmake`" = f && echo ok5 test "`gln devel/m4`" -gt 0 && echo ok8 test "`gln devel/byacc`" -gt 0 && echo ok9 test "`gln devel/flex`" -gt 0 && echo ok10 test "`gln wip/libmaa`" = "rf" && echo ok11 test "`gln wip/dict-server`" = "rf" && echo ok12 test "`gln wip/dict-client`" = "rf" && echo ok13 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 17 && echo ok100 } | cmp 'paexec packages #9' \ 'ok1 ok2 ok3 ok4 ok5 ok8 ok9 ok10 ok11 ok12 ok13 ok100 ' # -s: autoconf fails runtest -l -s -c 'cmd_xxx_failed_make_package autoconf' \ -n +4 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/gmake`" -gt 0 && echo ok4 test "`gln devel/autoconf`" = f && echo ok5 test "`gln devel/m4`" -gt 0 && echo ok8 test "`gln devel/byacc`" -gt 0 && echo ok9 test "`gln devel/flex`" -gt 0 && echo ok10 test "`gln wip/libmaa`" = "rf" && echo ok11 test "`gln wip/dict-server`" = "rf" && echo ok12 test "`gln wip/dict-client`" = "rf" && echo ok13 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 17 && echo ok100 } | cmp 'paexec packages #9' \ 'ok1 ok2 ok3 ok4 ok5 ok8 ok9 ok10 ok11 ok12 ok13 ok100 ' # -s: dict-server fails runtest -l -s -c 'cmd_xxx_failed_make_package dict-server' \ -n +4 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln wip/dict-server`" = f && echo ok6 test "`gln wip/libmaa`" -lt "`gln wip/dict-client`" && echo ok7 test "`gln devel/m4`" -gt 0 && echo ok8 test "`gln devel/byacc`" -lt "`gln wip/dict-client`" && echo ok9 test "`gln devel/flex`" -lt "`gln wip/dict-client`" && echo ok11 test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 23 && echo ok100 } | cmp 'paexec packages #10' \ 'ok1 ok2 ok3 ok4 ok5 ok6 ok7 ok8 ok9 ok11 ok100 ' # -s: flex and byacc fail runtest -n +4 -Cls cmd_xxx_failed_make_package 'flex|byacc' \ > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" -lt "`gln wip/libmaa`" && echo ok4 test "`gln devel/gmake`" -lt "`gln wip/libmaa`" && echo ok5 test "`gln devel/m4`" -gt 0 && echo ok8 test "`gln devel/byacc`" = f && echo ok9 test "`gln devel/flex`" = f && echo ok10 test "`gln wip/dict-server`" = "rf" && echo ok11 test "`gln wip/dict-client`" = "rf" && echo ok12 awk 'NF > 2 && $2 == "devel/flex" && /wip\/dict-server/ && /wip\/dict-client/ {print "ok20"}' $OBJDIR/_test.tmp awk 'NF > 2 && $2 == "devel/byacc" && /wip\/dict-server/ && /wip\/dict-client/ {print "ok21"}' $OBJDIR/_test.tmp test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 20 && echo ok100 } | cmp 'paexec packages #11' \ 'ok1 ok2 ok3 ok4 ok5 ok8 ok9 ok10 ok11 ok12 ok20 ok21 ok100 ' # -s: gmake and autoconf fail runtest -l -s \ -c 'cmd_xxx_failed_make_package "gmake|autoconf"' \ -n +4 > $OBJDIR/_test.tmp < ../examples/make_package/tasks { test "`gln devel/glib2`" -gt 0 && echo ok1 test "`gln textproc/dictem`" -gt 0 && echo ok2 test "`gln devel/libjudy`" -gt 0 && echo ok3 test "`gln devel/autoconf`" = f && echo ok4 test "`gln devel/gmake`" = f && echo ok5 test "`gln devel/m4`" -gt 0 && echo ok8 test "`gln devel/byacc`" -gt 0 && echo ok9 test "`gln devel/flex`" -gt 0 && echo ok10 test "`gln wip/libmaa`" = "rf" && echo ok11 test "`gln wip/dict-server`" = "rf" && echo ok12 test "`gln wip/dict-client`" = "rf" && echo ok13 awk 'NF > 2 && $2 == "devel/autoconf" && /wip\/libmaa/ && /wip\/dict-server/ && /wip\/dict-client/ {print "ok20"}' $OBJDIR/_test.tmp awk 'NF > 2 && $2 == "devel/gmake" && /wip\/libmaa/ && /wip\/dict-server/ && /wip\/dict-client/ {print "ok21"}' $OBJDIR/_test.tmp test "`awk 'END {print NR}' $OBJDIR/_test.tmp`" -eq 18 && echo ok100 } | cmp 'paexec packages #12' \ 'ok1 ok2 ok3 ok4 ok5 ok8 ok9 ok10 ok11 ok12 ok13 ok20 ok21 ok100 ' # diamond-like dependancy and failure runtest -l -s -C -n +5 cmd_xxx_failed_make_package flex \ > $OBJDIR/_test.tmp < ../examples/make_package/tasks2 { test "`gln devel/flex`" = f && echo ok1 awk 'NF > 2 && $2 == "devel/flex" && /wip\/dict-client/ && /wip\/dict-server/ && /wip\/pkg_online/ {print "ok2"}' $OBJDIR/_test.tmp if grep 'wip/pkg_online.*wip/pkg_online' $OBJDIR/_test.tmp > /dev/null then echo 'needs to be fixed!!!' else echo ok fi } | cmp 'paexec packages #13' \ 'ok1 ok2 ok ' # cycle detection1 runtest -l -s \ -c cmd_make_package \ -n +5 < ../examples/make_package/tasks_cycle | cmp 'paexec cyclic deps #1' \ 'Cyclic dependancy detected: devel/gettext-lib -> devel/gmake devel/gmake -> lang/gcc lang/gcc -> devel/gettext-lib ' # cycle detection2 printf 'task-2 task-1 task-1 task0 task0 task10 task10 task20 task20 task30 task30 task10 ' | runtest -l -s \ -c cmd_make_package \ -n +5 | cmp 'paexec cyclic deps #2' \ 'Cyclic dependancy detected: task10 -> task20 task20 -> task30 task30 -> task10 ' # cycle detection2 printf 'task0 task10 task10 task20 task20 task30 task50 task50 task30 task40 ' | runtest -l -s \ -c cmd_make_package \ -n +5 | cmp 'paexec cyclic deps #3' \ 'Cyclic dependancy detected: task50 -> task50 ' # cycle detection2 printf 'task0 task100 task0 task200 task0 task100 task10 task100 task20 task100 task50 task100 task100 task110 task200 task300 task300 task0 ' | runtest -l -s \ -c cmd_make_package \ -n +5 | cmp 'paexec cyclic deps #4' \ 'Cyclic dependancy detected: task0 -> task200 task200 -> task300 task300 -> task0 ' # transport failure printf '%s' '-1 0 0 1 1 2 2 3 3 4 4 5 ' | runtest -s -E \ -t transport_broken_echo -c ':' \ -n '1 2 3 4 5 6' | cmp 'paexec broken transport #1' \ "I'll output -1 -1 success I'll output 0 0 success I'll output 1 Node 1 exited unexpectedly " # resistance/-z without -s printf 'bilberry gooseberry apple pear plum cherry ' | runtest_resort -el -z \ -t transport_broken_toupper \ -c : -n '4 5 6 7' | cmp 'paexec broken transport #2' \ '1 fatal 1 1 BILBERRY 1 2 GOOSEBERRY 2 3 APPLE 3 4 PEAR 4 5 PLUM 5 6 CHERRY 6 ' # -Z + -w without -s printf '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n' | runtest_resort -Z1 -w \ -t transport_broken_rnd \ -m F= -c: -n '0.5ns-nopostfail 0.5ns-nopostfail 0.5ns-nopostfail' | cmp 'paexec broken transport #3' \ 'success success success success success success success success success success success success success success success success 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ' # resistance to transport failure printf '%s' '-1 0 0 1 ' | runtest -z -g -E \ -t transport_broken_echo -c ':' \ -n '1' | cmp 'paexec broken transport #4' \ "I'll output -1 -1 success I'll output 0 0 success I'll output 1 fatal all nodes failed " # resistance to transport failure printf '%s' '-1 0 0 1 1 2 2 3 3 4 4 5 5 6 ' | runtest -z -r -g -E \ -t transport_broken_echo -c ':' \ -n '1 2 3 4 5 6 7' | cmp 'paexec broken transport #5' \ "1 I'll output -1 1 -1 1 success 1 1 I'll output 0 1 0 1 success 1 1 I'll output 1 1 fatal 1 2 I'll output 1 2 1 2 success 2 2 I'll output 2 2 fatal 2 3 I'll output 2 3 2 3 success 3 3 I'll output 3 3 fatal 3 4 fatal 4 5 I'll output 3 5 3 5 success 5 5 I'll output 4 5 4 5 success 5 5 I'll output 5 5 fatal 5 6 I'll output 5 6 5 6 success 6 6 I'll output 6 6 fatal 6 7 I'll output 6 7 6 7 success 7 " # resistance to transport failure2 (write(2) errors) printf '0 1 1 2 2 3 3 4 4 5 5 6 ' | runtest -g -z -lre -t transp_closed_stdin -c : \ -n '0 1 2 3 4 5 6 7 8' | cmp 'paexec broken transport #6' \ "0 1 I'll output 0 0 1 0 0 1 success 0 1 0 2 fatal 0 2 1 2 I'll output 1 1 2 1 1 2 success 1 2 1 3 fatal 1 3 2 3 I'll output 2 2 3 2 2 3 success 2 3 2 4 fatal 2 4 3 4 I'll output 3 3 4 3 3 4 success 3 4 3 5 fatal 3 5 4 5 I'll output 4 4 5 4 4 5 success 4 5 4 6 fatal 4 6 5 6 I'll output 5 5 6 5 5 6 success 5 6 5 7 fatal 5 7 6 7 I'll output 6 6 7 6 6 7 success 6 7 " # resistance to transport failure awk ' BEGIN { for (i=1; i < 300; ++i){ print i } }' | runtest -z -r -g -E \ -t transport_broken_echo -c ':' \ -n '4' | cmp 'paexec broken transport #7' \ '4 fatal 4 all nodes failed ' # resistance to transport failure export PAEXEC_TRANSPORT=transport_broken_echo awk ' BEGIN { for (i=1; i < 300; ++i){ print i } }' | runtest -z -r -g -E -c ':' -n '4' | cmp 'paexec broken transport #7.0.1 (PAEXEC_TRANSPORT)' \ '4 fatal 4 all nodes failed ' unset PAEXEC_TRANSPORT # resistance to transport failure echo mama | runtest -z -r -g -i -E \ -t transport_broken_echo -c ':' \ -n '4' | cmp 'paexec broken transport #8' \ '4 mama 4 fatal 4 all nodes failed ' # resistance to transport failure cat > $OBJDIR/_test.in < $OBJDIR/_tasks.tmp <&1 | grep '^sum_weight' | cmp 'paexec -W0 #2.1' \ 'sum_weight [pcc]=4 sum_weight [gcc]=10 sum_weight [tcl]=8 sum_weight [glibc]=9 sum_weight [python]=7 sum_weight [dictd]=3 sum_weight [mplayer]=11 sum_weight [pike]=6 sum_weight [ruby]=5 sum_weight [gnome]=12 sum_weight [kde]=13 sum_weight [runawk]=2 sum_weight [mk-configure]=1 sum_weight [qt4]=14 ' test_tasks1 | sed 's/^weight:/W:/' | runtest -W0 -e -d -mw=W: -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W0 -mw=W: #2.2' \ 'sum_weight [pcc]=4 sum_weight [gcc]=10 sum_weight [tcl]=8 sum_weight [glibc]=9 sum_weight [python]=7 sum_weight [dictd]=3 sum_weight [mplayer]=11 sum_weight [pike]=6 sum_weight [ruby]=5 sum_weight [gnome]=12 sum_weight [kde]=13 sum_weight [runawk]=2 sum_weight [mk-configure]=1 sum_weight [qt4]=14 ' # tests for max_weight calculation (-W0 option) test_tasks2 | runtest -edW0 -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W0 #3' \ 'sum_weight [pipestatus]=1 sum_weight [pkg_status]=1 sum_weight [pkg_summary-utils]=2 sum_weight [dict]=15 sum_weight [pkg_online-client]=1 sum_weight [netcat]=1 sum_weight [dictd]=20 sum_weight [pkg_online-server]=1 sum_weight [judyhash]=12 sum_weight [runawk]=2 sum_weight [libmaa]=5 sum_weight [paexec]=4 ' test_tasks2 | spc2semicolon | runtest -edW0 -md=';' -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W0 -md=";" #3.1' \ 'sum_weight [pipestatus]=1 sum_weight [pkg_status]=1 sum_weight [pkg_summary-utils]=2 sum_weight [dict]=15 sum_weight [pkg_online-client]=1 sum_weight [netcat]=1 sum_weight [dictd]=20 sum_weight [pkg_online-server]=1 sum_weight [judyhash]=12 sum_weight [runawk]=2 sum_weight [libmaa]=5 sum_weight [paexec]=4 ' # tests for sum_weight calculation (-W0 option) test_tasks2 | runtest -eW0 -c cmd_make_package -n +1 2>&1 | cmp 'paexec -W0 #4' \ 'judyhash success libmaa success dictd success dict success paexec success runawk success pipestatus success pkg_summary-utils success pkg_status success netcat success pkg_online-client success pkg_online-server success ' test_tasks2 | spc2semicolon | runtest -eW0 -md=';' -c cmd_make_package -n +1 2>&1 | cmp 'paexec -W0 -md=";" #4.1' \ 'judyhash success libmaa success dictd success dict success paexec success runawk success pipestatus success pkg_summary-utils success pkg_status success netcat success pkg_online-client success pkg_online-server success ' # tests for weighted nodes of graph (-W1 option) test_tasks1 | runtest -W1 -e -c cmd_make_package -n +1 | cmp 'paexec -W1 #1' \ 'qt4 success kde success gnome success mplayer success gcc success glibc success tcl success python success pike success ruby success pcc success dictd success runawk success mk-configure success ' # tests for sum_weight calculation (-W1 option) test_tasks1 | runtest -W1 -e -d -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W1 #2' \ 'sum_weight [pcc]=4 sum_weight [gcc]=10 sum_weight [tcl]=8 sum_weight [glibc]=9 sum_weight [python]=7 sum_weight [dictd]=3 sum_weight [mplayer]=11 sum_weight [pike]=6 sum_weight [ruby]=5 sum_weight [gnome]=12 sum_weight [kde]=13 sum_weight [runawk]=2 sum_weight [mk-configure]=1 sum_weight [qt4]=14 ' # tests for sum_weight calculation (-W1 option) test_tasks2 | runtest -edW1 -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W1 #3' \ 'sum_weight [pipestatus]=6 sum_weight [pkg_status]=1 sum_weight [pkg_summary-utils]=5 sum_weight [dict]=16 sum_weight [pkg_online-client]=1 sum_weight [netcat]=2 sum_weight [dictd]=21 sum_weight [pkg_online-server]=1 sum_weight [judyhash]=12 sum_weight [runawk]=7 sum_weight [libmaa]=49 sum_weight [paexec]=9 ' # tests for sum_weight calculation (-W1 option) test_tasks2 | runtest -eW1 -c cmd_make_package -n +1 2>&1 | cmp 'paexec -W1 #4' \ 'libmaa success dictd success dict success judyhash success paexec success runawk success pipestatus success pkg_summary-utils success netcat success pkg_status success pkg_online-client success pkg_online-server success ' # tests for sum_weight calculation (-W1 option) printf 'task1 task2\ntask1 task2\nweight: task1 7\nweight: task2 9\n' | runtest -edW1 -c cmd_make_package -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W1 #5' \ 'sum_weight [task1]=16 sum_weight [task2]=9 ' # tests for weighted nodes of graph (-W2 option) test_tasks1 | runtest -W2 -e -c cmd_make_package -n +1 | cmp 'paexec -W2 #1' \ 'qt4 success kde success gnome success mplayer success gcc success glibc success tcl success python success pike success ruby success pcc success dictd success runawk success mk-configure success ' # tests for max_weight calculation (-W2 option) test_tasks1 | runtest -W2 -e -d -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W2 #2' \ 'sum_weight [pcc]=4 sum_weight [gcc]=10 sum_weight [tcl]=8 sum_weight [glibc]=9 sum_weight [python]=7 sum_weight [dictd]=3 sum_weight [mplayer]=11 sum_weight [pike]=6 sum_weight [ruby]=5 sum_weight [gnome]=12 sum_weight [kde]=13 sum_weight [runawk]=2 sum_weight [mk-configure]=1 sum_weight [qt4]=14 ' # tests for max_weight calculation (-W2 option) test_tasks2 | runtest -edW2 -c cmd_make_package \ -n +1 2>&1 | grep '^sum_weight' | cmp 'paexec -W2 #3' \ 'sum_weight [pipestatus]=2 sum_weight [pkg_status]=1 sum_weight [pkg_summary-utils]=2 sum_weight [dict]=15 sum_weight [pkg_online-client]=1 sum_weight [netcat]=1 sum_weight [dictd]=20 sum_weight [pkg_online-server]=1 sum_weight [judyhash]=12 sum_weight [runawk]=2 sum_weight [libmaa]=20 sum_weight [paexec]=4 ' # tests for sum_weight calculation (-W2 option) test_tasks2 | runtest -eW2 -c cmd_make_package -n +1 2>&1 | cmp 'paexec -W2 #4' \ 'libmaa success dictd success dict success judyhash success paexec success pipestatus success runawk success pkg_summary-utils success pkg_status success netcat success pkg_online-client success pkg_online-server success ' # tests for sum_weight calculation (-W0 option) test_tasks2 | runtest -lgX -n+1 -C \ awk 'BEGIN { if (ARGV[1] == "libmaa") { print "libmaa is broken"; exit 1} { print ARGV[1] " is fine"} }' | cmp 'paexec -X #1' \ '9 success 11 failure 11 libmaa dict pkg_online-client dictd pkg_online-server paexec pkg_summary-utils pkg_status 10 success 1 success 6 success ' # the first line on input is empty printf '\n\n' | runtest -xc echo -n +2 -l | sort | cmp 'paexec # empty line1' \ '1 2 ' # empty lines anywhere printf 'aaa\n\nbbb\n' | runtest -xc echo -n +2 -l | sort | cmp 'paexec # empty line2' \ '1 aaa 2 3 bbb ' # -g + the first line on input is empty printf '\n\n' | runtest -gxc 'echo task' -n +2 -l | paexec_reorder -gl | cmp 'paexec # empty line1' \ '1 task 1 success ' # -g + empty lines anywhere printf 'aaa\n\nbbb\n' | runtest -gxc 'echo task' -n +2 -l | paexec_reorder -gl | cmp 'paexec # -g + empty line2' \ '1 task aaa 1 success 2 task 2 success 3 task bbb 3 success ' # -g + empty task printf ' ccc\nbbb \naaa bbb\nccc ddd\n' | runtest -gxc 'printf '"'"'task "%s"\n'"'" -n +2 -l | cmp 'paexec # -g + empty task1' \ '4 task "aaa" 4 success 3 task "bbb" 3 success 1 task "" 1 success 2 task "ccc" 2 success 5 task "ddd" 5 success ' # -x + -t export PAEXEC_ENV=' ZZZZ, , ,YYYY,CCCC LALALA ' export ZZZZ=zz1234zz export YYYY=yy1234yy export CCCC=cc1234cc printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -xlC -t paexec_notransport \ -n '1 2 3 4 5 6 7 8 9' \ awk 'BEGIN {print ENVIRON["ZZZZ"], ENVIRON["YYYY"], ENVIRON["CCCC"], ENVIRON["LALALA"], toupper(ARGV[1])}' | resort | cmp 'paexec -g + -t #1 (PAEXEC_ENV)' \ '1 zz1234zz yy1234yy cc1234cc A 2 zz1234zz yy1234yy cc1234cc BB 3 zz1234zz yy1234yy cc1234cc CCC 4 zz1234zz yy1234yy cc1234cc DDDD 5 zz1234zz yy1234yy cc1234cc EEEEE 6 zz1234zz yy1234yy cc1234cc FFFFFF ' unset ZZZZ YYYY CCCC PAEXEC_ENV # -t + shquote(3) printf 'a\nbb\nccc\ndddd\neeeee\nffffff\n' | runtest -t paexec_notransport \ -n '1 2 3 4 5 6 7 8 9' \ -C sh -c 'while read f; do echo $f; echo; done' | sort | cmp 'paexec -t + shquote(3) #1' \ 'a bb ccc dddd eeeee ffffff ' # -t + shquote(3) printf 'a\nbb\n' | runtest -x -t /bad/transport -n +1 -c echo | sort | cmp 'paexec -n +1 -t /bad/transport' \ 'a bb ' # tests for paexec_reorder paexec_reorder_input1 | paexec_reorder | cmp 'paexec_reorder' \ 'TABLE1 TABLE2 TABLE3 TABLE4 GREEN1 GREEN2 GREEN3 GREEN4 APPLE1 APPLE2 APPLE3 APPLE4 ' paexec_reorder_input1 | nonstandard_msgs | paexec_reorder -m t='Konec!' | cmp 'paexec_reorder nonstandard' \ 'TABLE1 TABLE2 TABLE3 TABLE4 GREEN1 GREEN2 GREEN3 GREEN4 APPLE1 APPLE2 APPLE3 APPLE4 ' # tests for paexec_reorder -l paexec_reorder_input2 | paexec_reorder -l | cmp 'paexec_reorder -l' \ '2 fatal 1 2 fatal 2 2 fatal 3 2 fatal 4 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN4 ' paexec_reorder_input2 | nonstandard_msgs | paexec_reorder -l \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -l nonstandard' \ '2 PolnayaZhopa! 1 2 PolnayaZhopa! 2 2 PolnayaZhopa! 3 2 PolnayaZhopa! 4 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN4 ' # tests for paexec_reorder -g paexec_reorder_input3 | paexec_reorder -gS | cmp 'paexec_reorder -gS' \ 'TABLE1 TABLE2 TABLE3 TABLE4 success APPLE1 APPLE2 APPLE3 APPLE4 success GREEN1 GREEN2 GREEN3 GREEN??? failure 4 5 ' paexec_reorder_input3 | nonstandard_msgs | paexec_reorder -gS \ -mt='Konec!' -mf='Zhopa!' -mF='PolnayaZhopa!' -ms='Ura!' | cmp 'paexec_reorder -gS nonstandard' \ 'TABLE1 TABLE2 TABLE3 TABLE4 Ura! APPLE1 APPLE2 APPLE3 APPLE4 Ura! GREEN1 GREEN2 GREEN3 GREEN??? Zhopa! 4 5 ' # tests for paexec_reorder -glS paexec_reorder_input4 | paexec_reorder -glS | cmp 'paexec_reorder -glS' \ '2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 success 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 success 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 failure 3 4 5 ' paexec_reorder_input4 | nonstandard_msgs | paexec_reorder -glS \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -glS nonstandard' \ '2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 Ura! 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 Ura! 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 Zhopa! 3 4 5 ' # tests for paexec_reorder -gl paexec_reorder_input5 | paexec_reorder -gl | cmp 'paexec_reorder -gl' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 success 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 success 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 failure 3 4 5 ' paexec_reorder_input5 | nonstandard_msgs | paexec_reorder -gl \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gl nonstandard' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 Ura! 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 Ura! 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 Zhopa! 3 4 5 ' # tests for paexec_reorder -Ms paexec_reorder_input1 | paexec_reorder -Ms | cmp 'paexec_reorder -Ms' \ 'APPLE1 APPLE2 APPLE3 APPLE4 TABLE1 TABLE2 TABLE3 TABLE4 GREEN1 GREEN2 GREEN3 GREEN4 ' paexec_reorder_input1 | nonstandard_msgs | paexec_reorder -Ms \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -Ms nonstandard' \ 'APPLE1 APPLE2 APPLE3 APPLE4 TABLE1 TABLE2 TABLE3 TABLE4 GREEN1 GREEN2 GREEN3 GREEN4 ' # tests for paexec_reorder -l -Ms paexec_reorder_input2 | paexec_reorder -l -Ms | cmp 'paexec_reorder -l -Ms' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 2 fatal 1 2 fatal 2 2 fatal 3 2 fatal 4 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN4 ' paexec_reorder_input2 | nonstandard_msgs | paexec_reorder -l -Ms \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -l -Ms nonstandard ' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 2 PolnayaZhopa! 1 2 PolnayaZhopa! 2 2 PolnayaZhopa! 3 2 PolnayaZhopa! 4 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN4 ' # tests for paexec_reorder -gS -Ms paexec_reorder_input3 | paexec_reorder -gS -Ms | cmp 'paexec_reorder -gS -Ms' \ 'APPLE1 APPLE2 APPLE3 APPLE4 success TABLE1 TABLE2 TABLE3 TABLE4 success GREEN1 GREEN2 GREEN3 GREEN??? failure 4 5 ' paexec_reorder_input3 | nonstandard_msgs | paexec_reorder -gS -Ms \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gS -Ms nonstandard' \ 'APPLE1 APPLE2 APPLE3 APPLE4 Ura! TABLE1 TABLE2 TABLE3 TABLE4 Ura! GREEN1 GREEN2 GREEN3 GREEN??? Zhopa! 4 5 ' # tests for paexec_reorder -gl -Ms paexec_reorder_input4 | paexec_reorder -gl -Ms | cmp 'paexec_reorder -gl -Ms' \ '1 blablabla 1 fatal 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 success 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 success 3 foo 3 bar 3 fatal 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 failure 3 4 5 ' paexec_reorder_input4 | nonstandard_msgs | paexec_reorder -gl -Ms \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gl -Ms nonstandard' \ '1 blablabla 1 PolnayaZhopa! 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 Ura! 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 Ura! 3 foo 3 bar 3 PolnayaZhopa! 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 Zhopa! 3 4 5 ' # tests for paexec_reorder -gl -Ms paexec_reorder_input5 | paexec_reorder -gl -Ms | cmp 'paexec_reorder -gl -Ms' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 success 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 success 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 failure 3 4 5 ' paexec_reorder_input5 | nonstandard_msgs | paexec_reorder -gl -Ms \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gl -Ms nonstandard' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 Ura! 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 Ura! 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 Zhopa! 3 4 5 ' # tests for paexec_reorder -Mf paexec_reorder_input1 | paexec_reorder -Mf | cmp 'paexec_reorder -Mf' \ 'TABLE1 TABLE2 TABLE3 TABLE4 GREEN1 GREEN2 GREEN3 GREEN4 APPLE1 APPLE2 APPLE3 APPLE4 ' paexec_reorder_input1 | nonstandard_msgs | paexec_reorder -Mf \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -Mf nonstandard ' \ 'TABLE1 TABLE2 TABLE3 TABLE4 GREEN1 GREEN2 GREEN3 GREEN4 APPLE1 APPLE2 APPLE3 APPLE4 ' # tests for paexec_reorder -l -Mf paexec_reorder_input2 | paexec_reorder -l -Mf | cmp 'paexec_reorder -l -Mf' \ '2 fatal 1 2 fatal 2 2 fatal 3 2 fatal 4 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN4 ' paexec_reorder_input2 | nonstandard_msgs | paexec_reorder -l -Mf \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -l -Mf nonstandard' \ '2 PolnayaZhopa! 1 2 PolnayaZhopa! 2 2 PolnayaZhopa! 3 2 PolnayaZhopa! 4 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN4 ' # tests for paexec_reorder -gS -Mf paexec_reorder_input3 | paexec_reorder -gS -Mf | cmp 'paexec_reorder -gS -Mf' \ 'TABLE1 TABLE2 TABLE3 TABLE4 success APPLE1 APPLE2 APPLE3 APPLE4 success GREEN1 GREEN2 GREEN3 GREEN??? failure 4 5 ' paexec_reorder_input3 | nonstandard_msgs | paexec_reorder -gS -Mf \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gS -Mf nonstandard' \ 'TABLE1 TABLE2 TABLE3 TABLE4 Ura! APPLE1 APPLE2 APPLE3 APPLE4 Ura! GREEN1 GREEN2 GREEN3 GREEN??? Zhopa! 4 5 ' # tests for paexec_reorder -gl -Mf paexec_reorder_input4 | paexec_reorder -gl -Mf | cmp 'paexec_reorder -gl -Mf' \ '2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 success 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 success 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 failure 3 4 5 ' paexec_reorder_input4 | nonstandard_msgs | paexec_reorder -gl -Mf \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gl -Mf nonstandard' \ '2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 Ura! 1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 Ura! 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 Zhopa! 3 4 5 ' # tests for paexec_reorder -gl -Mf paexec_reorder_input5 | paexec_reorder -gl -Mf | cmp 'paexec_reorder -gl -Mf' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 success 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 success 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 failure 3 4 5 ' paexec_reorder_input5 | nonstandard_msgs | paexec_reorder -gl -Mf \ -m t='Konec!' -m f='Zhopa!' -mF='PolnayaZhopa!' -m s='Ura!' | cmp 'paexec_reorder -gl -Mf nonstandard' \ '1 APPLE1 1 APPLE2 1 APPLE3 1 APPLE4 1 Ura! 2 TABLE1 2 TABLE2 2 TABLE3 2 TABLE4 2 Ura! 3 GREEN1 3 GREEN2 3 GREEN3 3 GREEN??? 3 Zhopa! 3 4 5 ' # test -f $tmpex return $? } for PAEXEC_BUFSIZE in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1000 10000; do printf "PAEXEC_BUFSIZE=%d:\n" $PAEXEC_BUFSIZE export PAEXEC_BUFSIZE do_test || exit done paexec-1.1.1/tests/Makefile0000644000175000017500000000267613431606350015507 0ustar cheusovcheusovMKC_CHECK_CUSTOM += sleep_fract MKC_CUSTOM_FN.sleep_fract = ../checks/sleep_fract CLEANFILES += _test.in _tasks.tmp _test.tmp all: @echo 'running tests...'; \ set -e; \ cd ${.CURDIR}; \ export OBJDIR=${.OBJDIR}; \ export PATH=${.CURDIR}/broken_echo:$$PATH; \ export PATH=${.CURDIR}/scripts:$$PATH; \ export PATH=${.CURDIR}/../paexec:$$PATH; \ export PATH=${.CURDIR}/../examples/all_substr:$$PATH; \ export PATH=${.CURDIR}/../examples/cc_wrapper:$$PATH; \ export PATH=${.CURDIR}/../examples/cc_wrapper2:$$PATH; \ export PATH=${.CURDIR}/../examples/dirtest:$$PATH; \ export PATH=${.CURDIR}/../examples/divide:$$PATH; \ export PATH=${.CURDIR}/../examples/make_package:$$PATH; \ export PATH=${.CURDIR}/../examples/toupper:$$PATH; \ export PATH=${.CURDIR}/../examples/wav2flac:$$PATH; \ export PATH=${OBJDIR_paexec}:$$PATH; \ export PATH=${OBJDIR_paargs}:$$PATH; \ export PATH=${OBJDIR_scripts}:$$PATH; \ export PATH=${OBJDIR_transp_closed_stdin}:$$PATH; \ export PATH=${OBJDIR_all_substr}:$$PATH; \ export PATH=${OBJDIR_cc_wrapper}:$$PATH; \ export PATH=${OBJDIR_cc_wrapper2}:$$PATH; \ export PATH=${OBJDIR_dirtest}:$$PATH; \ export PATH=${OBJDIR_divide}:$$PATH; \ export PATH=${OBJDIR_make_package}:$$PATH; \ export PATH=${OBJDIR_toupper}:$$PATH; \ export PATH=${OBJDIR_wav2flac}:$$PATH; \ export SLEEP_FRACT=${CUSTOM.sleep_fract:S/0//}; \ if ./test.sh; \ then echo 'SUCCEEDED'; \ else echo 'FAILED'; false; \ fi .include paexec-1.1.1/tests/transp_closed_stdin/0000755000175000017500000000000013431606350020075 5ustar cheusovcheusovpaexec-1.1.1/tests/transp_closed_stdin/Makefile0000644000175000017500000000010713431606350021533 0ustar cheusovcheusovPROG = transp_closed_stdin WARNS = 4 .include paexec-1.1.1/tests/transp_closed_stdin/transp_closed_stdin.c0000644000175000017500000000067313431606350024310 0ustar cheusovcheusov#include #include #include #include static const char *id; int main (int argc, char **argv) { char task [1000]; --argc, ++argv; id = argv [0]; while (fgets (task, sizeof (task), stdin)){ task [strlen (task)-1] = 0; printf ("I'll output %s\n%s\nsuccess\n\n", task, task); fflush (stdout); if (!strcmp (task, id)){ fclose (stdin); sleep (2); exit (1); } } return 0; } paexec-1.1.1/tests/fakeflac/0000755000175000017500000000000013431606350015570 5ustar cheusovcheusovpaexec-1.1.1/tests/fakeflac/fake1.wav0000644000175000017500000000002213431606350017270 0ustar cheusovcheusovThis is fake wav1 paexec-1.1.1/tests/fakeflac/fake3.wav0000644000175000017500000000002213431606350017272 0ustar cheusovcheusovThis is fake wav3 paexec-1.1.1/tests/fakeflac/flac0000755000175000017500000000044013431606350016421 0ustar cheusovcheusov#!/usr/bin/env sh set -e while test $# -ne 0; do case "$1" in --silent) ;; -o) dst_fn=$2 shift;; *) break;; esac shift done test $# -eq 1 src_fn="$1" : ${dst_fn:=${src_fn%%.wav}.flac} cat "$src_fn" > "$dst_fn" echo "converted to flac" >> "$dst_fn" paexec-1.1.1/tests/fakeflac/fake2.wav0000644000175000017500000000002213431606350017271 0ustar cheusovcheusovThis is fake wav2 paexec-1.1.1/tests/fakeflac/fake5.wav0000644000175000017500000000002213431606350017274 0ustar cheusovcheusovThis is fake wav5 paexec-1.1.1/tests/fakeflac/fake4.wav0000644000175000017500000000002213431606350017273 0ustar cheusovcheusovThis is fake wav4 paexec-1.1.1/paargs/0000755000175000017500000000000013431606354014153 5ustar cheusovcheusovpaexec-1.1.1/paargs/paargs.pod0000644000175000017500000000357313431606350016140 0ustar cheusovcheusov=head1 NAME paargs - wrapper for paexec similar to xargs =head1 SYNOPSIS B I<[OPTIONS]> =head1 DESCRIPTION B is a simple wrapper over B that simplifies use of B's capalities. The use of B is actually very similar to B. B runs B with the following options enabled by default: =over 4 =item * I<-C> -- for specifying I as free arguments, =item * I<-x> -- for being B-like, =item * I<-l> -- 0-based task number is included to the output of B, this allows to reorder the sliced output, =item * I<-e> -- for the same purposes as I<-l>, =item * I<-g> -- this flag allows analysis of I's exit status, =item * I<-md=> -- disables task delimiter for I<-g> mode enabled by default, as a result the whole line given on input is considered as a task. =back =head1 OPTIONS =over 4 =item B<-h> Display this help. =item B<-V> Display version. =item B<-P> I Same as I<-n> in B. =item B<-t> I Passed directly to B. =item B<-c> I Command with its arguments. By default, free arguments are used for setting command and its arguments. =item B<-I> I Execute command for each task, replacing one or more occurrences of I with the entire task. =item B<-X> Passed directly to B. =item B<-f> Flushes stdout after recieving an end-of-task line. =item B<-0> Passed directly to B. =item B<-Z> I Passed directly to B. =item B<-z> Passed directly to B. =item B<-m> I Passed directly to B. =back =head1 BUGS/FEEDBACK Please send any comments, questions, bug reports etc. to me by e-mail or (even better) register them at sourceforge project home. Feature requests are also welcomed. =head1 HOME L =head1 SEE ALSO L paexec-1.1.1/paargs/paargs.10000644000175000017500000001425113431606354015515 0ustar cheusovcheusov.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .if !\nF .nr F 0 .if \nF>0 \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} .\} .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "paargs 1" .TH paargs 1 "2019-02-15" "" "" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" paargs \- wrapper for paexec similar to xargs .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBpaargs\fR \fI[\s-1OPTIONS\s0]\fR .SH "DESCRIPTION" .IX Header "DESCRIPTION" \&\fBpaargs\fR is a simple wrapper over \fBpaexec\fR that simplifies use of \fBpaexec\fR's capalities. The use of \fBpaargs\fR is actually very similar to \fBxargs\fR. \fBpaargs\fR runs \fBpaexec\fR with the following options enabled by default: .IP "\(bu" 4 \&\fI\-C\fR \*(-- for specifying \fIcommand\fR as free arguments, .IP "\(bu" 4 \&\fI\-x\fR \*(-- for being \fBxargs\fR\-like, .IP "\(bu" 4 \&\fI\-l\fR \*(-- 0\-based task number is included to the output of \fBpaargs\fR, this allows to reorder the sliced output, .IP "\(bu" 4 \&\fI\-e\fR \*(-- for the same purposes as \fI\-l\fR, .IP "\(bu" 4 \&\fI\-g\fR \*(-- this flag allows analysis of \fIcommand\fR's exit status, .IP "\(bu" 4 \&\fI\-md=\fR \*(-- disables task delimiter for \fI\-g\fR mode enabled by default, as a result the whole line given on input is considered as a task. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-h\fR" 4 .IX Item "-h" Display this help. .IP "\fB\-V\fR" 4 .IX Item "-V" Display version. .IP "\fB\-P\fR \fInodes\fR" 4 .IX Item "-P nodes" Same as \fI\-n\fR in \fBpaexec\fR. .IP "\fB\-t\fR \fItransport\fR" 4 .IX Item "-t transport" Passed directly to \fBpaexec\fR. .IP "\fB\-c\fR \fIcommand\fR" 4 .IX Item "-c command" Command with its arguments. By default, free arguments are used for setting command and its arguments. .IP "\fB\-I\fR \fIreplstr\fR" 4 .IX Item "-I replstr" Execute command for each task, replacing one or more occurrences of \fIreplstr\fR with the entire task. .IP "\fB\-X\fR" 4 .IX Item "-X" Passed directly to \fBpaexec\fR. .IP "\fB\-f\fR" 4 .IX Item "-f" Flushes stdout after recieving an end-of-task line. .IP "\fB\-0\fR" 4 .IX Item "-0" Passed directly to \fBpaexec\fR. .IP "\fB\-Z\fR \fItimeout\fR" 4 .IX Item "-Z timeout" Passed directly to \fBpaexec\fR. .IP "\fB\-z\fR" 4 .IX Item "-z" Passed directly to \fBpaexec\fR. .IP "\fB\-m\fR \fIarg\fR" 4 .IX Item "-m arg" Passed directly to \fBpaexec\fR. .SH "BUGS/FEEDBACK" .IX Header "BUGS/FEEDBACK" Please send any comments, questions, bug reports etc. to me by e\-mail or (even better) register them at sourceforge project home. Feature requests are also welcomed. .SH "HOME" .IX Header "HOME" .SH "SEE ALSO \fIpaexec\fP\|(1)" .IX Header "SEE ALSO paexec" paexec-1.1.1/paargs/paargs.in0000755000175000017500000000530713431606350015764 0ustar cheusovcheusov#!/bin/sh usage (){ cat 1>&2 <<'EOF' paargs -- wrapper for paexec usage: paargs [OPTIONS] OPTIONS: -h display this help -V display version -P <+num> number of subprocesses to run list of nodes separated by space character <:filename> filename containing a list of nodes, one node per line -t set a transport program -c command with its arguments. By default, free arguments are used for setting command and its arguments -I execute command for each task, replacing one or more occurrences of replstr with the entire task -X ignore calculator's stdout -f flushes stdout after recieving an end-of-task signal -0 change paexec to expect NUL characters as separators instead of newline -Z passed directly to paexec -z passed directly to paexec -m s= set an alternative for 'success' message f= set an alternative for 'failure' message F= set an alternative for 'fatal' message t= set an alternative for EOT marker d= set the delimiter for -g mode, no delimiter by default w= set an alternative for 'weight:' marker -P is a mandatory option EOF } command='paexec -Cxleg -md=' version='@version@' shquote (){ __cmd=`printf '%s\n' "$1" | sed "s|'|'\\\\\''|g"` printf "%s\n" "'$__cmd'" } while getopts 0c:fI:hm:P:t:VXzZ: f; do case "$f" in '?') exit 1;; h) usage exit 0;; V) echo "paargs $version written by Aleksey Cheusov" exit 0;; P) addon=$(shquote "$OPTARG") command="$command -n$addon";; t) addon=$(shquote "$OPTARG") command="$command -t$addon";; X) command="$command -X";; f) command="$command -E";; m) addon=$(shquote "$OPTARG") command="$command -m$addon";; I) addon=$(shquote "$OPTARG") command="$command -J$addon";; 0) command="$command -0";; Z) addon=$(shquote "$OPTARG") command="$command -w -Z$addon";; z) command="$command -wz";; c) command_specified=1 addon=$(shquote "$OPTARG") command="$command -c$addon";; esac done shift `expr $OPTIND - 1` if test -n "$command_specified"; then if test $# -ne 0; then echo 'paargs: extra arguments. Run paargs -h for details' 1>&2 exit 1 fi else if test $# -eq 0; then echo 'paargs: missing arguments. Run paargs -h for details' 1>&2 exit 1 fi fi for fa in "$@"; do addon=$(shquote "$fa") command="$command $addon" done #echo $command 1>&2 eval "$command" paexec-1.1.1/paargs/Makefile0000644000175000017500000000021213431606350015602 0ustar cheusovcheusovINSCRIPTS = paargs SCRIPTS = ${INSCRIPTS} MAN = paargs.1 CLEANFILES = paargs.1 .PHONY: _prepdist _prepdist: ${MAN} .include paexec-1.1.1/Makefile0000644000175000017500000000151613431606350014335 0ustar cheusovcheusovBIRTHDATE = 2008-01-25 PROJECTNAME = paexec ##### SUBPRJ = paexec:tests paargs presentation doc SUBPRJ_DFLT?= paexec paargs examples = divide all_substr cc_wrapper cc_wrapper2 \ make_package toupper dirtest .for d in ${examples} SUBPRJ += examples/${d}:tests examples/${d}:examples .endfor tests = transp_closed_stdin scripts .for d in ${tests} SUBPRJ += tests/${d}:tests .endfor ##### MKC_REQD = 0.27.0 ##### test: all-tests @: clean: clean-tests clean-presentation cleandir: cleandir-tests cleandir-presentation # new recursive target for making a distribution tarball TARGETS += _prepdist DIST_TARGETS= prepdist .PHONY: prepdist prepdist: all-presentation _prepdist rm ${MKC_CACHEDIR}/_mkc* ${MAKE} -Cpresentation ${MAKEFILES} _clean_garbage ##### .include "Makefile.inc" .include