paexec-1.0.1004075500017500000000000000000001237304662300122365ustar cheusovwheelpaexec-1.0.1/Makefile010064400017500000000000000015001237304661200137440ustar cheusovwheelBIRTHDATE = 2008-01-25 PROJECTNAME = paexec ##### SUBPRJ = paexec:tests presentation doc SUBPRJ_DFLT?= paexec 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 paexec-1.0.1/Makefile.inc010064400017500000000000000010351237304661200145170ustar cheusovwheel# 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}} # VERSION= 1.0.1 paexec-1.0.1/README010064400017500000000000000023021237304661200131650ustar cheusovwheel====================================================================== 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.0.1/checks004075500017500000000000000000001237304661200134745ustar cheusovwheelpaexec-1.0.1/checks/awk_fflush010075500017500000000000000001401237304661200156220ustar cheusovwheel#!/usr/bin/env sh if echo | "$AWK" '{fflush()}' 2>/dev/null 1>&2; then echo 1 else echo 0 fi paexec-1.0.1/checks/sleep_fract010075500017500000000000000001121237304661200157570ustar cheusovwheel#!/usr/bin/env sh if sleep 0.1 2>/dev/null; then echo 1 else echo 0 fi paexec-1.0.1/doc004075500017500000000000000000001237304661200130015ustar cheusovwheelpaexec-1.0.1/doc/INSTALL010064400017500000000000000056601237304661200141150ustar cheusovwheel====================================================================== 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.0.1/doc/LICENSE010064400017500000000000000020661237304661200140660ustar cheusovwheelCopyright (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.0.1/doc/Makefile010064400017500000000000000001261237304661200145140ustar cheusovwheelFILES = LICENSE NEWS ../README TODO FILESDIR = ${DOCDIR} .include paexec-1.0.1/doc/NEWS010064400017500000000000000401301237304661200135520ustar cheusovwheel====================================================================== Version 1.0.1, by Aleksey Cheusov, Thu, 14 Aug 2014 01:44:39 +0300 Unbuffered (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.0.1/doc/TODO010064400017500000000000000006641237304661200135530ustar cheusovwheelpaexec: - 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 -I like in xargs (in combination with -x) - 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.0.1/examples004075500017500000000000000000001237304661200140525ustar cheusovwheelpaexec-1.0.1/examples/Makefile010064400017500000000000000000301237304661200155570ustar cheusovwheel.include paexec-1.0.1/examples/Makefile.inc010064400017500000000000000000331237304661200163320ustar cheusovwheel.include "../Makefile.inc" paexec-1.0.1/examples/all_substr004075500017500000000000000000001237304661200162245ustar cheusovwheelpaexec-1.0.1/examples/all_substr/Makefile010064400017500000000000000002021237304661200177320ustar cheusovwheelINSCRIPTS = cmd_all_substr SCRIPTS = ${INSCRIPTS} run_all_substr SCRIPTSDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.0.1/examples/all_substr/cmd_all_substr.in010075500017500000000000000005631237304661200216340ustar cheusovwheel#!@awk@ -f { # Read tasks line-by-line # Our task is to print all not empty # substrings of the input string len=length($0) for (i=1; i <= len; ++i){ for (j=i; j <= len; ++j){ sz = j-i+1 printf "substr[%d,%d]=%s\n", i, sz, substr($0, i, sz) } } # End of task marker, empty line by default print "" # In the end, stdout must be flushed fflush() } paexec-1.0.1/examples/all_substr/run_all_substr010075500017500000000000000007251237304661200212700ustar cheusovwheel#!/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.0.1/examples/cc_wrapper/cmd_cc_wrapper010075500017500000000000000004621237304661200211530ustar cheusovwheel#!/usr/bin/env sh set -e while read fn; do # we obtain .c files from stdin log1=${fn%%.c}.log1 log2=${fn%%.c}.log2 obj=${fn%%.c}.o if ${CC} ${CPPFLAGS} ${CFLAGS} -c -o $obj ${fn} > $log1 2> $log2; then echo "done: $fn" else echo "failed: $fn" fi echo '' # end of job done paexec-1.0.1/examples/cc_wrapper/func1.c010064400017500000000000000000071237304661200174300ustar cheusovwheelint a; paexec-1.0.1/examples/cc_wrapper/func2.c010064400017500000000000000000071237304661200174310ustar cheusovwheelint b; paexec-1.0.1/examples/cc_wrapper/func3.c010064400017500000000000000000071237304661200174320ustar cheusovwheelint c; paexec-1.0.1/examples/cc_wrapper/run_cc_wrapper010075500017500000000000000004141237304661200212110ustar cheusovwheel#!/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' < paexec-1.0.1/examples/cc_wrapper2/func1.c010064400017500000000000000000071237304661200175120ustar cheusovwheelint a; paexec-1.0.1/examples/cc_wrapper2/func2.c010064400017500000000000000000071237304661200175130ustar cheusovwheelint b; paexec-1.0.1/examples/cc_wrapper2/func3.c010064400017500000000000000000071237304661200175140ustar cheusovwheelint c; paexec-1.0.1/examples/cc_wrapper2/run_cc_wrapper2010075500017500000000000000002601237304661200213540ustar cheusovwheel#!/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.0.1/examples/dirtest004075500017500000000000000000001237304661200155305ustar cheusovwheelpaexec-1.0.1/examples/dirtest/Makefile010064400017500000000000000002141237304661200172410ustar cheusovwheelSCRIPTS = run_dirtest SCRIPTSDIR = ${EGDIR}/${.CURDIR:T} FILES = tasks FILESDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.0.1/examples/dirtest/run_dirtest010075500017500000000000000002241237304661200200720ustar cheusovwheel#!/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.0.1/examples/dirtest/tasks010064400017500000000000000006221237304661200166540ustar cheusovwheel/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.0.1/examples/divide004075500017500000000000000000001237304661200153165ustar cheusovwheelpaexec-1.0.1/examples/divide/Makefile010064400017500000000000000002221237304661200170260ustar cheusovwheelINSCRIPTS = cmd_divide cmd_divide2 SCRIPTS = ${INSCRIPTS} run_divide run_divide2 SCRIPTSDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.0.1/examples/divide/cmd_divide.in010075500017500000000000000011451237304661200200150ustar cheusovwheel#!@awk@ -f # This a sample command passed to paexec via option -c { # Read tasks line-by-line if ($1 != 0){ # Result which should not contain empty lines print "1/" $1 "=" 1/$1 # "paexec -g" requires either "success" or "failure" in the end. # For non-zero input number x we are able to calculate 1/x print "success" }else{ # Oops, dependent tasks will fail as well print "Cannot calculate 1/0" # "paexec -g" requires either "success" or "failure" in the end. print "failure" } # End of task marker, empty line by default print "" # In the end, stdout must be flushed fflush() } paexec-1.0.1/examples/divide/cmd_divide2.in010064400017500000000000000012471237304661200200770ustar cheusovwheel#!@awk@ -f # The same as "cmd" but with non-standard "success", # "failure" and "eot" strings. BEGIN { EOT = ENVIRON ["PAEXEC_EOT"] } { # Read tasks line-by-line if ($1 != 0){ # Result which should not contain empty lines print "1/" $1 "=" 1/$1 # "paexec -g" requires either "success" or "failure" in the end. # For non-zero input number x we are able to calculate 1/x print "Ura!" }else{ # Oops, dependent tasks will fail as well print "Cannot calculate 1/0" # "paexec -g" requires either "success" or "failure" in the end. print "Zhopa!" } # End of task marker, empty line by default print EOT # In the end, stdout must be flushed fflush() } paexec-1.0.1/examples/divide/run_divide010075500017500000000000000004601237304661200174500ustar cheusovwheel#!/usr/bin/env sh # Calculate 1/$1 values in 3 parallel subprocesses. # Dependency graph of tasks comes from stdin. # Tasks 7, 8, 9 and 10 will be marked as failed # due to task 0 failure. See cmd for details. paexec -s -l -c cmd_divide -n +3 < paexec-1.0.1/examples/make_package/cmd_make_package.in010075500017500000000000000003541237304661200222660ustar cheusovwheel#!@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.0.1/examples/make_package/cmd_xxx_failed_make_package.in010075500017500000000000000002641237304661200245010ustar cheusovwheel#!@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.0.1/examples/make_package/run_cycle_make_package010075500017500000000000000001711237304661200230760ustar cheusovwheel#!/usr/bin/env sh # Attempt to build packages with cyclic dependencies paexec -g -le -c "`pwd`/cmd" -n +3 < tasks_cycle paexec-1.0.1/examples/make_package/run_make_package010075500017500000000000000003461237304661200217230ustar cheusovwheel#!/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.0.1/examples/make_package/tasks010064400017500000000000000004301237304661200175630ustar cheusovwheeltextproc/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.0.1/examples/make_package/tasks2010064400017500000000000000001641237304661200176510ustar cheusovwheeldevel/flex wip/dict-server devel/flex wip/dict-client wip/dict-server wip/pkg_online wip/dict-client wip/pkg_online paexec-1.0.1/examples/make_package/tasks_cycle010064400017500000000000000003311237304661200207420ustar cheusovwheeldevel/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.0.1/examples/toupper004075500017500000000000000000001237304661200155505ustar cheusovwheelpaexec-1.0.1/examples/toupper/Makefile010064400017500000000000000001741237304661200172660ustar cheusovwheelINSCRIPTS = cmd_toupper SCRIPTS = ${INSCRIPTS} run_toupper SCRIPTSDIR = ${EGDIR}/${.CURDIR:T} .include paexec-1.0.1/examples/toupper/cmd_toupper.in010075500017500000000000000004471237304661200205050ustar cheusovwheel#!@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.0.1/examples/toupper/run_toupper010075500017500000000000000006041237304661200201340ustar cheusovwheel#!/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.0.1/examples/wav2flac004075500017500000000000000000001237304661200155575ustar cheusovwheelpaexec-1.0.1/examples/wav2flac/Makefile010064400017500000000000000001051237304661200172670ustar cheusovwheelSCRIPTS = run SCRIPTSDIR ?= ${FILESDIR} .include paexec-1.0.1/examples/wav2flac/run_wav2flac010075500017500000000000000004631237304661200201550ustar cheusovwheel#!/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.0.1/paexec004075500017500000000000000000001237304662300135035ustar cheusovwheelpaexec-1.0.1/paexec/Makefile010064400017500000000000000021001237304661200152060ustar cheusovwheel# 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 = getline 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.0.1/paexec/common.h010064400017500000000000000002441237304661200152160ustar cheusovwheel#ifndef _COMMON_H_ #define _COMMON_H_ #if defined(__GNUC__) #define attr_unused __attribute__ ((unused)) #else #define attr_unused #endif #endif /* _COMMON_H_ */ paexec-1.0.1/paexec/decls.h010064400017500000000000000026021237304661200150200ustar cheusovwheel/* * 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 #include #ifndef HAVE_FUNC3_SHQUOTE size_t shquote (const char *arg, char *buf, size_t bufsize); #endif #endif // _DECLS_H_ paexec-1.0.1/paexec/nodes.c010064400017500000000000000066401237304661200150370ustar cheusovwheel/* * 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.0.1/paexec/nodes.h010064400017500000000000000023521237304661200150400ustar cheusovwheel/* * 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.0.1/paexec/paexec.c010064400017500000000000000633121237304661200151730ustar cheusovwheel/* * 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 path to a command\n\ -t path to a transport program\n\ -x run command once per task\n\ -y magic line is used as an end-of-task marker\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=\n\ f=\n\ F=\n\ t=\n\ d=\n\ set an alternative for 'success',\n\ 'failure', 'fatal', '' (end-of-task marker) and\n\ ' ' (task delimiter character).\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_eot = ""; 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; 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 = xgetline (&buf, &buf_sz, 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, "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 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); } snprintf (cmd, sizeof (cmd), "while read f; do" " res=`%s \"$f\"`;" " ex=$?;" " %s" /* printing result */ " %s" /* condition. success/failure */ " echo '%s';" /* EOT */ "done", arg_cmd, tmp, cond_cmd, magic_eot); 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)); snprintf (tmp2, sizeof (tmp2), "%s=%s ", p->name, tmp); strlcat (env_str, tmp2, sizeof (env_str)); } /**/ snprintf (cmd, sizeof (cmd), "env %s /bin/sh -c %s", env_str, shq_cmd); 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]; size_t len; size_t curr_len; int i; len = 0; for (i=0; i < *argc; ++i){ curr_len = shquote ((*argv) [i], 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)-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 [] = "+c:CdeEghiIlm: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': 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 '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=. Exactly one character is allowed"); } msg_delim = 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; default: usage (); exit (1); } } *argv += optind; *argc -= optind; 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.0.1/paexec/paexec.pod010064400017500000000000000310341237304661200155270ustar cheusovwheel=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 AUTONOMOUS 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 SMP system (or modern multikernel CPU) 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 where an empty line means JOB_IS_DONE__I_AM_READY_FOR_THE_NEXT_ONE. After sending the empty line to stdout, stdout MUST BE FLUSHED. Remember that empty line MUST NOT appears in general result lines. Otherwise B may hang because of deadlock. I - special program that helps to run I on the I. It takes the I identifier as its first argument and I with its arguments as the rest. For example, is '/usr/bin/ssh'. Both I and I may be specified with their arguments, i.e. '/usr/bin/ssh -x' is allowed as a I program. Algorithm. I are run on each I with a help of I program. Then, I are read from stdin line-by-line (one task per line) and are 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 an empty line is obtained from the I (this means that I finished its job) it is marked as free and becomes ready for the next job. 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_empty_line(result) # end of job mark_node_as_free(i) end end end close_command_on_each_node Note that I that does your actual task is 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 to be output. B works this way for the efficiency reasons. You can play with I<-l>, I<-r> and I<-p> options to see what happens. =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 with its arguments are specified following the options. =item B<-t> I Transport command =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 passed 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 calculator'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, an empty line is printed 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 =item B<-m> f=I =item B<-m> F=I =item B<-m> t=I =item B<-m> d=I Set alternative string for 'success', 'failure', 'fatal', '' (end of task) and ' ' (task delimiter character). An empty string for 'fatal' means it will not be output to stdout in case of fatal error. =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. 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 calculator's output. This option has higher priority than PAEXEC_EOT environment variable. =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 =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 calculator. =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 calculators. =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.0.1/paexec/paexec_reorder010075500017500000000000000131511237304661200164730ustar cheusovwheel#!/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.0.1/paexec/paexec_reorder.pod010064400017500000000000000046231237304661200172550ustar cheusovwheel=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.0.1/paexec/pr.c010064400017500000000000000122051237304661200143420ustar cheusovwheel/* 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.0.1/paexec/pr.h010064400017500000000000000030321237304661200143450ustar cheusovwheel/* * 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.0.1/paexec/shquote.c010064400017500000000000000034301237304661200154110ustar cheusovwheel/* * 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.0.1/paexec/signals.c010064400017500000000000000044301237304661200153620ustar cheusovwheel/* * 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.0.1/paexec/signals.h010064400017500000000000000027001237304661200153650ustar cheusovwheel/* * 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.0.1/paexec/tasks.c010064400017500000000000000252211237304661200150500ustar cheusovwheel/* * 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 = xgetline (&task, &task_sz, 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.0.1/paexec/tasks.h010064400017500000000000000041011237304661200150470ustar cheusovwheel/* * 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.0.1/paexec/wrappers.c010064400017500000000000000065151237304661200155730ustar cheusovwheel/* * 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 xgetline(char** lineptr, size_t* n, FILE* stream) { ssize_t ret = getline (lineptr, n, stream); if (ret == (ssize_t) -1 && ferror (stdin)){ perror ("getline(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.0.1/paexec/wrappers.h010064400017500000000000000037621237304661200156010ustar cheusovwheel/* * 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 xgetline(char** lineptr, size_t* n, 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.0.1/paexec/paexec.1010064400017500000000000000445471237304662300151240ustar cheusovwheel.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28) .\" .\" 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 turned on, 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 .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" 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 "2014-08-14" "" "" .\" 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 \s-1AUTONOMOUS\s0 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 \s-1SMP\s0 system (or modern multikernel \s-1CPU\s0) 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 where an empty line means JOB_IS_DONE_\|_I_AM_READY_FOR_THE_NEXT_ONE. After sending the empty line to stdout, stdout \s-1MUST BE FLUSHED.\s0 Remember that empty line \&\s-1MUST NOT\s0 appears in general result lines. Otherwise \fBpaexec\fR may hang because of deadlock. .PP \&\fITransport\fR \- special program that helps to run \fIcommand\fR on the \&\fInode\fR. It takes the \fInode\fR identifier as its first argument and \fIcommand\fR with its arguments as the rest. For example, is '/usr/bin/ssh'. Both \fItransport\fR and \fIcommand\fR may be specified with their arguments, i.e. '/usr/bin/ssh \-x' is allowed as a \fItransport\fR program. .PP Algorithm. \fICommands\fR are run on each \fInode\fR with a help of \&\fItransport\fR program. Then, \fItasks\fR are read from stdin line-by-line (one task per line) and are 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 an empty line is obtained from the \fInode\fR (this means that \fInode\fR finished its job) it is marked as free and becomes ready for the next job. 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_empty_line(result) \& # end of job \& mark_node_as_free(i) \& end \& end \& end \& close_command_on_each_node .Ve .PP Note that \fIcommand\fR that does your actual task is 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 to be output. \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. .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 with its arguments are specified following the options. .IP "\fB\-t\fR \fItransport\fR" 6 .IX Item "-t transport" Transport command .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 passed 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 calculator'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, an empty line is printed 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" .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" .IP "\fB\-m\fR d=\fIdelimiter\fR" 6 .IX Item "-m d=delimiter" .PD Set alternative string for 'success', 'failure', 'fatal', '' (end of task) and ' ' (task delimiter character). An empty string for 'fatal' means it will not be output to stdout in case of fatal error. .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. 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 calculator's output. This option has higher priority than \s-1PAEXEC_EOT\s0 environment variable. .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 .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 calculator. .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 calculators. .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.0.1/paexec/paexec_reorder.1010064400017500000000000000157071237304662300166420ustar cheusovwheel.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28) .\" .\" 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 turned on, 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 .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" 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 "2014-08-14" "" "" .\" 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.0.1/presentation004075500017500000000000000000001237304662300147515ustar cheusovwheelpaexec-1.0.1/presentation/Makefile010064400017500000000000000012041237304661200164600ustar cheusovwheel################################################## 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.0.1/presentation/dep-graph.dot010064400017500000000000000026251237304661200174070ustar cheusovwheeldigraph 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.0.1/presentation/paexec.tex010064400017500000000000000512541237304661200170210ustar cheusovwheel%%%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.0.1/presentation/paexec.pdf010064400017500000000000003155011237304661700167750ustar cheusovwheel%PDF-1.4 %Çì¢ 5 0 obj <> stream xœmRÛn1 å9_‘ÇDb²¾äú[*±H•Újˆ‡²- *[è^ ˆŸÇžv§Åñ$¶Ï9vî-´ ß¸/×fvYìjkЮ̽åL5Ô᪣B²í$[ãfåB­š4_˜ÙâÌî6û3û`ÑÌÞª™ŸŸÈ¶xc_˜Ó…½0 E ˆvÜ–k;ïµYŒc&Û16h#¨€+‡fûµùè~z!@™SqW^ÈDLÄìnä"¥£{ð] ¹fÊÇ-·ê–¾cÊKvÕ¥À ÝõP/5F÷MóJŽnë; R.nçEv­˜ÝÆwR%˜„~>ØÝCV|Æl«¸%dl“²SÜ[uKÈOiÔÜNЊû5ªÌm„ˆ3*IF îÝ‘Î4bç¥ ¥J~{™`‹ÀRV¼T¥K£H¬[-ÕBæøüžÅ±ºeÈ‘Š;÷€ˆ“{/×sšJùÔ¿“£ŒQРá0aàä5q•h¡_Ël_û.¹ï¢KøFFÃÏ©I Ñ}•ÂÃÙ^¦µµ7I»‚#Oñr ĶCÁM­%šPߘWJÑ­ôw­æAMPs÷wÙi£¸æÿéë0i^³]ä0¢©<}9Z ÚTäKmi €ÉÍ5Dµ ]¸òrÜt~›ýS†FsÅ‘Y(‹}R§½¹ïyaÎÌendstream endobj 6 0 obj 527 endobj 18 0 obj <> stream xœ­•MO1†{ö¯ðÑ®ºŽÇß¾HÕJ@Sq(=ð * °|´ý÷±ï"TEÙÝØïŒç}<ÞÜr­€kú ÷ã›íE~~Ç€Ÿ³[nƒI*•©ÎD*ðµ³Í´J‰‚æ 6[|å÷ýÃ)›ís`³mºÌw6ð¶ØäØÖ‚ï2MI”ùp;^ñùWÍœ².¾‚XÉΪ¬ý¹ü̶– ëRIë˜Ï`rÕs èÞ¸¨tâtTáMvqmóË´ BËmøæQ娦mÅÈÁ{eLŸWÙxb0ÛC=Pµ¹Æá>;mx Õ'¨Þ–N<ÈĹôȲ³.) ^"aäip|¬ér kŠ‚&Î(À)D,NhºD¡ÆÐ“5Fåêïk Ey#-(ì3=Žbâ`Ç’öÒ‰;RÓ¥ÖÿÜw7ðÊúœª‰·Y^Ê„j”‹¿Tó ].©p*¡8¸¢bm)¾Øjuý’îÉŽ§@ë ¨ÔáSŠ‹–p=£CpRXg ¼‹Fë±jV(3•¹D(‰~²%ea Do9I%~H½¦ŠiJi뉊2`:ʰ!ÛèÎwÙ…×mÞƒ˜’W÷tR+ 2vÙúƒ"[ ¹ìâÖoý¤#¬·Ä›\Û¥€Á†¢à‘ãa[­¬[~µ2(_E9»'HÖQ/Û—h놠kóŒe+½N¸šz§±ïëØíĸ<Õ_OìØe#:"&“­#ûÁ8”íh:ÖÞ•9ÒŠ¨šc‰ân$µ˜Nb“â?jÇ ¾H:ÅÉåI¯?L¨ü™<—0¤’¢ØGÝ$nìß&>™<'²ø-¡6ˆ’ã÷@Ò¢n/ü]öÛ]z©endstream endobj 19 0 obj 709 endobj 25 0 obj <> stream xœÅXKo7îyo^5—Ã7¢§ªmóPÐCƒ«8ŽÑÈv,)í¡èoÏp܇¸Š¹–R°ˆ!9$ç›Ç7û‰0 „ù¿úwµÎŠ—†\m2 WÙ'"4·Ô–Ssn8PMæ¸œŽ €Qký¦óEV,~%ÛûÝeVüA +~öÿΟ?ÅŸÅOä»ìÙ‚¼È˜WšAy"©Vkr¾ÄSI…Ôœ,ßgÕm€Xªð,N¸¼ár½É_ÍðÚi!U~;›Kª˜c:ÿ臜-óÝ ¯ÈµP&ßÎðÊÖ “_×ó¶·ë&,}»ü%{¶ÌðŽÔ2\V¿„¤²z¿Ñh . eøÃó¿ O§Ž1áöÕ‚5~Ü(å(O¶)Áx¥Oú[ZQ*c.QÙ8Üê”ê¡ZRWg–Y¡óÚT1æL¾ñ@)#­†üb†’è5ùÕlÎ)Ó\éüÒ/pD°þÞK˜TNz ‘ç Ö±ˆB‡˜¬FÉüþGéÔ!ÛéTMc¹FÂC¬œ ÝÍk0>.ª‘àF#û'Œ*™e6_ÍæŠ;ta“¿ Ó¿‡éçA¶ £E5 k×ýF¯ÂìÛFæ} x) ÷ Vz#Ëwxï›Ù(†‹¶˜µE(Ù®#ãڻ੒’bbÀs,§–W̓ñ͘©Õ.? Âu°ãE­ÂèC˜½î¨id—Áò› Tk ¦Äfú¾=ïé_Üó:È6atÖÌFŠ =Á vCÐXs¤¤ßajï*Yëéåä2·—ygÚó?tz+lþ$e{öMÐy4½ £–í}.GŠñκ›0Ú .Þ=ÀKÒ±æ ÌV©©9š'&è«ÌðÔ 8V-6ÊÇÉ9‡ª6ÊÚûÿQ.Ò_uÆÄQHÃcôôr—3©Š&¥.$ÇÊ“ÎÉÉ«–Åj€ôa0¨˜;¾Ýé¯1£õŸ½NÏÙýuÁíubÑVºm–o;åy¿Oƒ¶0ìmé±ív ¯ÏSÞ!:µàÐW‘ÉýW:#Hj§¾EG­5ê"w‘–¹m­‹0ûg]wJlcõb ¥_Ÿ?ÂÄY:é;Uº!GQJ‹~X*j|oˆÿ{€Ùû_9ŠH¼µÒB{7µ§ùr%1B­+[cOš€Ÿ¢5N·t¬ÈI8Ê—è jF˜ŽÀ.!‰3½È¾^Â`Þendstream endobj 26 0 obj 1189 endobj 36 0 obj <> stream xœ½XÉnãFÍ™_Ñ“ä@a«÷%G'âA2€9dr°=²cز5’œå’oÏ«æÒ´L/”ÃY,5_m¯«YþÌ—LÐ_{?]³_=;ß’Ÿ™v*ð~ª•W’;Vc­ŒQG…à!ÐKGÅìè'¶]ß.ŠÙ&‹Ùt9øå;ÜŽ¾g_‡Gì}!´É"ko§Kv0‡ÕȤáÚ8ÅægEãd[ØRLY çËâ·ò°ªi•+ÿ®jÃ]p+øe¤UZ—˪Ö< #B¹ªà­rÚúòŠ+á)X "7Æ•’´V„`Ëo!jD¨M¹­p‡.–7ù÷ÛŒÕÀÚ¨%ÄZ½¶€\e1å:y”1¿ÏDtR"^8e /"©µŠ):6ÿ„°~®j ¸àU­Ey^YX·™!çµ™àÊ zÞЙž·°Dnjí¸¾<­Lzïš°þ¤Ëšõ–tZ±¡7Òkë–V’¹„ª¸öjòlÕ^´!k€ñˆ@@ˆd™¼Å©Mf(Õªèl‘ãô¼¢’Ť x <‹A‡r=@¸jCïžÉ=RJçøÄBËU ¿LÃUï`e<¸‰è&Ò…:Þ‡FeT k2ù™”&b%8CNM02º‰pí#åÊ=a†Il%3–[Ól¤Sb]”®œ%Ñ äÿ¤ª-6¸Ñ ¬ T4ÒYkÛ•é¥-i­Š®Ý%Íû·yí*CA4’+m©ˆ¤”Áu$×ÑÕt$?ärØ+AÌt­K‹AžáÇþ0ZÖð2©þ`Ùר»Ôcu§†ê`Ý5…ÿŠª}DO{—ÅYo“¨l²¸Îâ,‹'Y¼ÈâõèÚãVô¾ü+k/!:Å]ŒeœµîX3 Ç æRLNáx)Љ^§Z>Z ¯úRœÑ ÝóÉ(§{7¥‹šðþ/¡;}ˆ«Qs…Z ŽÉ€æñ%D¥x$¡ûù›V‡ƒ}›™rÓ3¥'®÷­Ù¤]eí"k×Yû±Ì꯳ZdíǪW?Y¨é /”õoP(CÇîK Õi!J|v¡ôÔcšò-r>—£%Ùfí?õ*/¸È ®ïT2­…­Aר[­ڽΟî,í´å¶Ó-ð"}<Îâ&‹ÔüáÞƒ<Þ%[ºÌÚ{lLâ»~í“T›N‘qªûT×dGµ³Ì™x•Åñè,¶[¶‘+ât”þžwîR%µŽ‚I{»[ÈŽ­Î²öj´Å êOžELJ2ì€ï^¿Jâv/L/Ü88íyÏ£OÙnŒ;þÉ7ݹÑ/?%_Ó»³ŽøÀ1÷?úe˜:C> stream xœµXÛnEåy¾b„2ƒ4½}¿ „„Á£œ°1޽1V|ˮט¾SÝ3=ã½8žÅQ¤ÞruWÕ©ÓÕÕ=ùXr&JNÿÚß“ËbòÆ•g‹B”gÅÇRYé™StR0[6X+BP¡„‚3ïÉhï ˜üZÞΗ³bòG)ŠÉÏ4ìþ€ŸƒË/ŠýƒòuÁÉi!bIJý9¹,÷¦ˆJ¡™ÒV–Ó÷EB#JÏ bÉR„ÓËâmµ_7’´ÒV÷u£™õâq \Z©TuY7Š®¹¯nj •VW]ÐbÉÕÕ x`ZÛJÖpïMõ D… •®nküBªë~~ÙûJnMPb#5 N¸åŒki´ÖÕ<¢ôRë?§¿ ;¡/@Ó µÑ@¬‚/§§Hë_`ª&4¼£áœ†«¬»¥áš†% 7y T(˜jÈaçãVÉbLÕI pð®É^DÇJ2.Lõw-ª8qÑJé8A€i z¾$3B†ä¯kC¢H&ÿÐ:Á‚·Ý /¤QÉrÑc;­4Eþ¦/Á9Vëg«û3ÚÙè6f@‹çw5J¤£ä›.ÛF(f,—)é£#xÛd' ÿ®‹®)ƒ˜ËiÌ-âÜj,£±©¬LPUÔ2²©ãÜ‘(“ÓuDo’“EJ›,ú%1ćvV‰8ûžª˜s!ª9BE-]œ‰«£ñé€âó6ˆŽªºµ_Ý "T{Ìùubb›vÓ©”‰ÞLêËbúõÛ´áç™3ZwT×*ßÄè´öäJšjÞ“ÃoE”x`S@"4Š ‘‡ÉD@›÷YÝÙ*ÄÜÎ;Äh’ƒšWiø‹Ò±*âßõ–£ƒÒé¶nXCíO 41æÁ· R`¥N ÒYœj©Qâ¾N8´1½±¹ ën…ä<»µÚŒtýÏ;wš@z½oÇ5ðmÍ[ºR`׌yн:‹¦0Ž™Ô¼©ç0‚ ¨:`ÐTj³X›Bx´‚{Zà¶¾S«Fÿh”5Lxªst%\K±=vÎîz3ê’+e4b^yÑ3PÌÊ§Êø*ïA:Ž2<°”ØÈà»ãxSS¦›xœ¥Y–îWtžÓÔêZïpQ?ö¦n—³6V‹áè”AaÕÀl‘ƒ%Éq‹¦Óê6…Å»Á®ÄôÂue‹²1¨MÞ=º “ô]Ögé*ÏN²î6K×yv™u7Y×K³,Í;)aTbˆÇB ˆ¹Ê‡sp¦V*¯/âÑ¥·­ˆ5Íç+bÃS’Õ¬m*âAåôÍiã.⊢Ð2ô"Wl_D}=ϳt·:›w‚t¸ÑŒÄË2èu7>îFféâÆ¥+ü[ˆx2ãý0(›ãlâ †Kºt Mºú®3V}Ý B/Vª¬/²îv}ÝÊhüæo+#éÔ¸wÇ^ˆ’0z‡^˜;Û â)eèêAñôÍp‘uË,]¬´…žð¶{}‚ðñ4m#<>}ž…ð°‘p<¢é3Ap–‰ð½LÃ÷IR²zµªƒô*“Ôë~Þ,Ÿ i|j[HÂæ™.èG9ò¹ÄÐo9ß7™¡U^Hú)3´ÿt^Æg³…oô3µüGiqxƒÇo!b¦gá03s˜u/³´ÿôÃ4>-|81òka·Þesñ?2Ö›×㉎ǷémÜîå3x?ïàF!Ï ßUFÛqÇüuñKGÅendstream endobj 42 0 obj 1346 endobj 46 0 obj <> stream xœ½XMo$5åÜ¿¢HÛ}hËßF)‚`7»ŒÄqØM‘™d3™¿WînwÏd&J‡,Š4]*ÛÏåzÏe;ŸJ)¨”ü×}OÅì/?® *?ŸJíT!55Ê+®lЗbÔ±„CŠxÐáq1;þ¹¼½YŸ³_K*f?ðÏáÉ·øW~Q—o É ¥Ëîsº(ç˜5–d„6N•ó?Š6*ƒ°˜K•Ê"œ/Šßª£ºQìU®º¯#\p0ß׈ËUZW‹ºÑ"J#Cu]#Zå´õÕ%wVÒ;S£ƒŒÂW{­ ÁV_ÁÔX¡6Õm/|±ºÚ×V k£&˜2"zm+…4Êcª›ePÆü>ÿ«#ÂzT¤´¼ˆ¤6ÆŠ c(çgXÖ›ºI`„ÉU]`^Ln«%»Vpµ8ÊqtL\ U £©5–©vΈìð\]Ï÷ Ÿ Ïð³ Ô’“j }“£ØÂ&áG]öY‡­±Ô\»¨?ÙÉÉ×N@A­3uçV¡EÙÔ’B[óÏ¢VÕÂ~r«ULýx°’Àä’c ÒÄ R’n‘Ó¨»vöv¼¡êïšúˆà㰌߈5Ã]t!jÅ.ó0îDrH˜ ©lH Ë Iéȃ£_×lDÀÞ@\Ø^Rúê´6)Œ„—CæeX:¤)¯ÚI²mŸäL™f¥¬³xD«£y-'Ƈn;“6´ÛÙ;hPaÉ2”äcàï„ ö¥ŽaII9À*/ÔäQ†˜‹Žá ƒNhÎMDÛWjXéàÀÚZCØÇZa+¬ik ïG!ctt#Ú;OÊ P×=w޸л¬öV(ŠØ8:â ­¢ ¦¤^{È£w.‡ÉîØÄ¹  ( †R ÆÊhÁ·ˆÊö@ˆŠ‡(Æ´®Ç ÎgA‡hÂlt|FeëzT¶úºS©NÜþ>nç‹„3¹Ī&’©¾éëA£©W[ÂâÑ—Ùwû°ß42Ù}ÑÖ~ÎÓ/1\0ü3jX®H£–Ë…ig(b«ì[gërdžÏ"zB¾§gi_¾¹iW¢gæmε _ñÂzåë„V¦/Öx¹tduWèZñÍC cÙz„=‡¶{‡™€ƒœö×™Šƒl½Î­ƒï— ôLOê>z$îWÿÙ=niüF{q~ô~Þd~Þí```êûÜz4•é¹ÜÃJÄÃîeαGIÁdï'/E eRh )™”“œö“LÅOÙ:zúy1={˜ðñ³¾•z&Ö]‡Å㫜Ü®‡†³nÚŸv¿3ž£±Îþ½;z òÿÊ&··Å¿€ endstream endobj 47 0 obj 1258 endobj 51 0 obj <> stream xœµXKoEæ<¿¢f„¦·ß„0X`Á +q@b³ ~lö…K~;_õÌÔx7»ÁcbYÚ©­îúºê«ÇôúPR Eýóò¦š½ˆâõºÒâuõFØ`’Le©5ÑhD‹½:g›J¦DF'gÕììg±YmÕì7¡«Ùôqrþ-g߉ϪÓ3ñ¼RZér¢è—7âdŽS³ÐNZŒ˜¿ª:o´HÒã,#Œ×ðp~Sý^Ÿ6­!­ õ»¦u2¤ñe¿œöÆÚú¦i­ÌÊ©T/xk‚õ±¾¦ÍFÅàê6¨, µ&­W)ùúKˆZWo<¡Ëõݸ¾±:XŸ­†Ø's´°J*g¼s®^/“qîùˆNkÄ §².áeÚ:/“ÍIÌÿDXsÔ5­.ÞÙX¯I°â1Ei¼ïnM›ŒT*vß/ðÝ•¯w¯ß8d×/èû–>6d§‹òIJ»,¬¦P_à-)q öæä2öˆhýо@&¼ÐºÚîD2XC^KÀõŒ¸Â)8ú‚•W£òöÐÎ +ïXÚŽËKV.Gå‚•+VJOL¥ÄO_6&Ã,À¬ä&–VD¡¹â¡"8máµ&Diœhµ•>(ÓÁP’³&ö —×üñO“"ht¶–!Óy…†‘ 9M}3j¤ØuÍ*È8˜$¡cNôœÐ‡UÙü!¬6J°QLno‘“à9™lA a"Ú±Aa¢Ð¨Jïw&…F::ÆKïºI±¤êU9‡ ²á„£îY”Ti´¥ù¡eŠ.¤A g²ÓZÀè”P…H1f -U߃½ͨö všb„vNº?Ì«ìQ¤p*gLŒ§– LÌ"'üCúÈ•Çñ'Ü0º­º—‹ÑöhKC"üOí(DöÈNEšT4Ò“BxË•ñ9ç k“w,M7—ûö_"‰*EO“v,½ÛÓ%EíÝëzô¿Í„½mZ/mŠ!Ü+±ƒ^Qú•ì¾àÓè…‚Êlï¹ÀÊ÷¬œu~)š³ƒîŠ¥[^±nÃÒ¯nY·Ü“huÁÒjî÷^ ŒÕ4¹ŽU“ËŽæÀ'¨¦|¨š<^ü”=m³¤« UÓW=×Ñ÷|µBܬY÷7KëÞ/Ö¯GëÛŒ,®Y7ò~Í«›½S =€íécÛzÿ”C{÷˜øˆÖ½<к›¡3ìP¡;½;fkËÒõ^?ìäå|OgéßF‡ioúiÕÍ|c-„Žð¦á›N²¦~¶¯ƒôŒIu¿Þ„ÿAÒôÐŽ‘¤¢ÿD/”’”£ŒåúN,ýÂ1¿`–ö¹!é{fét7Ó#:ÂMÆåõ §ã@ Kt.ÔŒ4œ35ç¬û‰¥Ó‡wÔô0Žðó“^J>B–ùÐøúx”Ó;tã >Lû‘~øÂ÷‹8ü )LjôçÕ¿þm¨endstream endobj 52 0 obj 1097 endobj 56 0 obj <> stream xœµXÛnÜ6í³¾B D* ™w‘EQÀnÄmš&é¢yHóøÄ—Í®í¤/ýöž!ER»Ö:–ë"ˆ–r†3gÎ )*YËKFÿúßý³bëUW/ ^ŸJi„m­ŸjD'xkÊk¹sÒ•°ÖZRÚÙ+¶ö~+/W‡ÅÖë’[Oé±óâ'üìý\~Sìî•/ FF îw,ûŸý³rg†]]ÉU+•åì¨ÞðÒ¶{‰RhggÅ›j·nI…©¾Ôj5¾«á—âZHYÕlSÌVóÞ #uWÒbÁ:£ªC,`®UÊTœ¤šY««ï1”ˆPªê²Æ/d®ºÈóWÙV0«ä6Bµ®“fYË”ÐJ©já½´B©·³_çˆN9îÃsµp¡œ ¦VW'uýk²«–$@L Á/ºèA¶¤E¢e¬ ïïñ®üëE­«ëh‡Tà÷{z¿¢Ç%éq/ü\óêé^¦­I7.½×rÅk…täÅûüŒU[ô íɘ„ œWçºsÖšŽÃË4‘FWyzž„ó,ê,#[\ØÁ2ÂÒaGE¬Jó/y¦œ*G¦Ä*Ò"·!$HU6\'&‚7Ÿk 6:¬¥pTçýZx ½g¼Ú®9Ó>}¯É¿_)uοÏkòË ]-(;Çø¿èYͰæˆÐ¿¨¥%¤bÞ>Åáî×Ñÿšå~ÖG}NÐÿ^§ÑAâË úSrŠRÐ3&òPT±!.;OÐíZPˆZ¶¥\ÞÄÝÓÜx…Dõ„ó á½ê‡\ iX;[Ξ³ïÖ!ÚÍÚ§ýCò€YóA|¬á9v–aWãëÀƒãUþîÙãdž—ßeÙ‡'Q×´ çކOÅÀŸ~>¦ÄO\»„XL` éžDOxØ–,®£õE˜%F,è¸ò®&qáªÅA ˆ&£×È6%D…#],!"0ÅÞ/Çû…«$?Oœ!\©!Ð*™]ëyIQ'ÛzŒJ±#…¹I–€%ü„÷2Sz>lwÔô½lwVàøi-ð±ýÑÆÑ3U8Ú:ƒ~,P›Ì–Ü8ÞŠI§“î¦YNa«lÇ¥š|\–βhP‘›VzkšµM¯èJª ­WN^ŽÒU´ ö4áä%d[æœqÈœP”¤C_Õœ[ö -°26Šá,¿‘F·ÜR¿—p§>W½±ë¬æ++…Wj­´¼ßL3G|SÎᆰ+©²©M´iM—R~>rå~ø•*^…$ËiÐfÚhÕŒ$Š˜ÿh‡šEÄTK“ˆAW$:l9*/2ãÛ”ƒp< ·¢‰…ÒÙØ[æH"³¦ËK¦Ñ—5™Å-n?Êzë+~Á G}¨·ÞÔn¥íŒÐqÔ+úWÒ‹»¡mhº ™Ë$ £Žùs4L‹ÎyÖy<¢“CY¤ÑõÆY’á^ªÑ¼­Ó7ÌÐ(/ f4£³"ÇQÀBò,:Ñ&$ÎW`ë«hk™¶“ɶ‰¶ÈYüßi‹§m#Wí¦SrWÔ€ÁÖL©ûœd{.è:„;ián’=I²½”¦çQ6–¦N¶É‡£[ÉmV‹m•[´’|s\ù&„Iå*Éæk£Mþ«JÃí4z•Èú$ÉþL£7öÇÑÛl°ŽÊ£ –ô £>¾8´BШÚG·•ÝÉß“ d:­7ˆÀç×Ãøn¬@pþ(ȪÕñÐÁW2îë=%V ¿>Ž–‘E²ú1kçž—[TZ§iörm—¾¾õt€6AÍáù¤+à={£[ñ=ŽÐýµ|Ð([2VáÊšÓu•F§ƒò¿‘˜;>¦ €;cèÊ2Jíˆ7J‘™Hïß ¡+uøÚN²ç#]:uî¯C3=  ÈX”ÓÃœŠ·"ƒ“…ËHÅûvBæùº,aDÈdÙwÇhzh02„nÅHƒì_¾£ñ‹„Ñ‹${–F»w/§éalÀC뉰÷ë^ w§±Þu{”ÓûìR|â_žÇ¿ºîaF"ΑÏqi)Ï,½,þÅ…â3endstream endobj 57 0 obj 1584 endobj 61 0 obj <> stream xœ½XÛnÜ6í³¾B( DzÍû¥( Ø©‘nЦŽk´I Çvøšõ&éß÷ %v×Z×r#Èj2$‡3g¥Ü”R¨RÒŸîytQlí‡òt^¨ò´¸)×QÄ<Ôè •ðeƒ¹*%“J8¤ˆ‘íÌŠ­Ù¯åíÇÅq±õg©Š­Ÿéggï9³ŸÊoŠÝYùº´PyDz{]”;Ø5•Ê c½.NŠ6UFá°—.µSÈðà¢xSíÖ&¯öÕ—º±ÂGó°F^V9mLuQ7F$ie¬®kd«½q¡:§ÉZo«cLIXë+E^'ctÕ÷0 *4¶º­ñ„/UWÃøbˆÕ†uÉ(˜¶"ãV iµ³ÖVs–Q[ûîà%ªS õ"©¤ry  6V û5Íj] )k…”¡ú\t̙۰ÓQ­¶º¬…<1¬ó˜š²¥éôïokWÍÉ÷M¼¡ŸýäÅyòqm1‹>Ù—WÍi@‰„º¯)ï–“ B*[a^Ÿ†12'¸ ¤òž·tóÛ×Kã93 ÐGoaÒa&­Ä¾ RSkZ}õ|ˆ4Š®Ú$^wÆp嬰µ¢Å6åj© Ô¯À…÷mÍTeE ¡‘ÑÔl¤¹›iÃeÖèèA;U6Êçe×þ¡¡œB×¼k"EΓÏ•PZÕßìí†9Ý pˆþ®³:;ä•Üz0Ôè”;×uG´¥MCÔšÊÙ=(p†E]b§ÊXa[}¤Ö6PËTtðO’€$Mº&N6ÑàhNÕœ2EÙ´”f4m4=1Ú&õ"v€VέȗÂá´´ Ô+¶òE8 ™’Oh ’°Ô€ãLh¥¢2$jJÄ`}ìÝH–úßï&¢A „ÙäuÁ> ËH4fê¼HDU·™“É¡ÉH*%ÈX»ÒM1ïcF¸åwá£T‡_iûûÄÈ¡ *N»HVâˆÿqTK³.#Ÿ$=¿1螉q‰™ñ÷ œ´²R£‘ƒ¨]£‰24ñ­c¶¾¬ù"®BpÁѽ|V«å‰4nØÒ+h4Š5®qÂĨX l0z4Õ(’_^×§pÛ¥ºÎÙÙZAzº©Úa½´ærXóldM[_R32œÔ8 «ƒd}d ¾ƒìÅäîDYø‰Žj¶žõV …Q+P-ˆK>¢K'kLåéÜDeç&¾¥m¤rº—Êê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¿BjJA%´%¢¥’4m"’´ÝÎ=¾¾ž~¨8§ÿÚߣóÉÖsW½½œˆêíäC¥¬ôÌÇ©©tR0[M±V„ BgÞÓ¦íÝÉÖî¯ÕÕìúx²õ¢“­ŸéÏöÓÇøÙý±új²³[=›pR:ÑbÕþWÛû°*¡™ÒVVûo&ÉQyf`KVÒx¸>yYï4SIRiëOÍT3ë-† üÒÂH¥êófªXàšûú}o¥UÆÕg´Xrgu}Œ<0­m-Hj¸÷¦~ˆ¡B„J×W ~! õ»~þº×•Ôš †S©YpÊ@-g\K£µ®gÑK/µ~µÿ ¢ñ© bx N…aÊrÄûa½À†úÖ`£¸g¸0pÁ‘&â]è¢d@ºÒ€•Ìj¨æIù´Qõ¿ZéŠd^ß­|×(«Z!‚UбܖZÿlÄJ­Äà¢[ù±QÈÁEÐkÇ‚·õQ£)mš"QŠÓ<¦[xRÄ”½úŸJ=»¦Ð/Òÿ×”|,ÒðJ8n^6YÿÝÄÁJ¦Z £e?¯#B;#_¢Yr …¶IÛ!MÇ,¡è§‚Kp4„bÆÌô -#+Ñzt&Žvj}Ømdý†|P1Ó-LÒD˜”kJ˜DúCJ¯(N™ÌŒˆÈu’Ò"C¾»¹Äb';Ï:2u.*%KuóˆZËÜ´ÐtxŠE¥xߥ0r2N •"n´Lšg7ÙwM$5¡ÏÇ“Éþ·/Ó8ha§³ßy.Æø±[ÎhBG`c._ÓŽÓL‡èÐì4'ô:±äYÜHÉI6{½­®îx®gY†Aš¸ú ¬Ä·Íè"B:ÓY˜•H±„ÔÎþÅ•y€àÛÂ-ºN…ÛYT‰SÇ}%‚w(mcj65WaY­ðÁcœ »ÁePÏ;…šÜô*jóf¤¶¡k…ÊRaÌܽ"”dšÌ ¸§k…ØÅx6 GðA§rDÙƒÐD8æ¶¾Ã×D?k˜ðAjqaªx\Ze7ý¶H¬”qÊ®­1Ãå>…€ë%)‚UÚ"I§±No]Îø2zäÊfðUº»ç/² éwS5ŠêŒýŸz„¦³GR1y¼ ûŸî-ádGŒor Úû0Ìmœ¿>ß7¨Còè8>-È<:”£NÖß¶½v*ð¶¼Æ§h¼³÷.(h„äÖ ¸¥‹ûWfs:™CAæPF}ˆ•ÐÛMê„¡^õÂË,¼ÌŠN:YrD‰Òo™("¸È§¡ ñBª{ÖŒÎõk,Îù8þ ±&¬eA¿êm¦9×=|²°²§Ç,nÖ΢g5*0êóƒœ×Y–3ƒ:ÒÍ^iíFyö ËÎ ’9嗽ƖY–-ygi$óèA7ZEÉ©ønÄ—ñYâ ZøÏtû¬ç ÌX»È—£ž/_/”Âöc–ý… ½+ˆµîdÙOY¶›“°·îÔ‰ƒ×—7sYXŒÊÎ?2Ógýtd]=ßA肃=C¯³ìýˆfWù«ÎÃGyô<Ž —mø$û#^æ‘È£W½Â¦Û¼ ê|.ùoïέtŸÕþÓÞC?ꌧíÐÐ\St_݉F¯ebÿ÷@/r´½-%æ9Yp¾¯ -‹TýC¿»¯F} ê«VO­³<{µ`¥=·@= !¨%Z¶ÏÒÑ[+ja–öÜ%°/ÑrZ!.F'é‹GÏù0½^¤ÖõcšwF©Ôˆ¢cç3.5!>‚9u§¬{…Òfeí>gÒ‹ 3Šî2Μ•NQ'¤¨¥ …/ÅžÒÀMúÚã\ûBsÌã5›ׯuÛ¬‘…®ô%Ç¡ç¾È ¨û†yKŸŠB]ª<\\)¬@xpÉ¢lœ·hý²A¸Ö”Á¶¼Â6w Üxš NÐÛö RëIßD\Û í!V­ÓW—ô(w&§AÈÜH˜bزDÊ%–(nÒ#oYcË„.r[Û¾»‚Uwk«ç´ V±½§K¶Øò^ÒÍk¤Ýf…µØqÒ€ÍIITKá¡wâüŸÕ~à…ùyzŸõôðò¶üöIï’n³ ÂÉÊŠ²„¨]í¡ê´tÎÓ±KçÜjê£#mü')^¯fC‘³>ù·§e<˜Yñzäg›ÍÞ½ÖE¼|®m凣*^/Ç+nõë<:[xžÌÝß·ã=¦¼wŸé;ÃÚ€å¬û· Aj\’]3 ÙÞŠ^>÷÷·Ã2>šXŒõ_â!­- ô‘Ùα?ÊÈì-Ê2F„L/ûýîm#MÿdvÿÑ¿äÚGü4cô4ËžäÑÎÝÒø0ð>|‰Ò…BÃJ×ú@Çû·ò[)w›±òSéx5 q®ú„.ù¸ʳÉAO=2endstream endobj 67 0 obj 1875 endobj 73 0 obj <> stream xœÅXËn%5eÝ_á ÷¢Wù͆Q˜H ÄÀ•X0,&Cf@"ó@ðù÷»oº‡¸ïÌE‘Ò•²]¶Ï9.—óFhEBçŸþûò®ºø!ˆ×ï*¯«7ÂxŽ*¶M &åEƒ¾”’I­b̃.¯«‹ëoÅû·ÝV? ª.¾Î¿.¿ÿ Ÿë§â³êêZ<«tZQ;£è?/ïÄå³&AVëY^UÝjHDå0 vA1ZåUÝpv³—ÿÔU>z˜/j,Ì’ccä]Ý•´ÕQþYc¹ì òÜ™uðVÞ¢ƒNÊZ/9{ŽÑÉ/`lÑØù°5cX¾m'Žlíb¶YÜÞŒ6a ­´5&9Înì´gyÓvÉÐ"Æýäž™] v3Î&.ó4Á'fIÝòSÏëÑûËá›êêPoµ±ç’ŒU¶ã2x°Ê6(v –ÐpµIÃ’!žSмC"9=´9Z4]4.Œ¶¥4‚H%çR#† ò4Z™Ø)íïš : uýV7¤tJ>6,ÇâÈ÷ Õãx$+¯m¦7ù΀èèy³6è~r¶& Ì4´2ÓZyˆo ÚÕ˜‰nä|Ï´'"+¿Ìî”õ;’þ@ˆp'‚§ß艊ù»7Œ1Vg½›G.VcRü餑“BÔHH*öYèó‘ KÖb§’ñêƒr‘Ó3Jùþ7€dSzËï’¼²SFé’>/4ßã ÊGKÒåHl@JÖ%·h@´Vïœt²‹ˆ“þßÔò ë¦rr6 mí¨ì9¿YhŸ©_RŠû/ÇÅŠN ´x1&üq†cdEù¸òbüð³«|}k/õ€Ëx/³‡úŽ0û\ùN…ü=«þbû(öendstream endobj 74 0 obj 979 endobj 78 0 obj <> stream xœ½XYOGÎóþб%3Šv¶ï#—;–B+¶ƒ”Hq8Œ †Åv¤È¿=_õÌt÷Bž,KK¹¦ºî«ûMÅZ^1ú×ÿÝ9šÌ^Øjÿl«ýÉ›JáZ>M…¼5Õ´Ü{é+ Xëz´1™m<­–§çóÉìÏŠOf¿ÐÏ£gñgãçê³É“êù„Ó «þÏÎQõhR}ÅU+•ÕæÞ¤Ó†W®Õ%*¡94Ü<šü]?i¦‚°ÂÔj3·襸RÖGÍT¶ž)æê“Ú #µ­‰X0kT=ó­R¦„ÕÌ9]PÂB©òc[€ cE};¡ÔŠ´Œo:å!‚µLIéµ ´¢eFÔÛ±ö’¯ðX$tv<„V˜ Y“k¼5ïÔ÷¶~ÙDì?›¿ÂŸ\ÂÃpƒçÁ¡aœrw1 váÈP«žÑÏ6ýÐÏ"âN⇭ø!üóHÙ‹á¹ëBr vAxªú ´ð«‡‹ß5¼>Ý"$Øó Cµ ¾×`£¾EnÕ{$丑È’9Æ´Êz;È)è ¶œGe¸:g‚ïúO ÛE-Šà|µBÉ]‚ÆqÄbHk¬ÜW€§=X?LÞü"¹{™°[ [ÍÃ^¶ÿ"ÁñïÇr<$ô÷~ãOõñÈ|¼“ÀW <Ž`·5¯aaZNëM¿=Īä%c¾ó=¦)\û¬ÁÒj <ûE«´â¸ß¡/r+Í_Ò0Ù#•Õõc,SÒ3î2¿K‰{iœž¸=éà0ŠýþÖ ás%û£ÅÕMÔ› X(zØxÉXb%+#&•–”qæòìY˜u…iÂ'ì^ÂN/&z/%z)Ñ-ÊQÓº@Ú5¦GÏårMp¯5§õqÑÅy7 †ã.8_©‹kÝ0^ýâ~Çì­ØDuÖà#™ÃU!_í™ySÀ, 7íUVpê½V±¡{³Ç-¶ ï’¶v-™Ê»$z‘Æ@Èþ“/ñÔçÞ rÁxýK1ö¨Ìu‡HâÛ°ÉêΫ±lÖ*;g†G¿“T^[+À›*m¼ÂE»é>ö ìFz»ß—ŒíçñÇØ=^áRòYf¬ÁæŠöb¬Ý]˜åù–0p º×'†§2¬åáݵÏåá‰`+Ÿ£@2¯Å\#hôr•ô‡µûrÿDÝ*lx›ÑTb­ÀD§€UJûü"kq‰×qzIy{»è?a%¥Öx–2Ì0{/·a“•¹¶înʼœC™+ßʘi-.-ˆ´ â¥^xñJô¾ˆÝ)^”W–•‹kÑÊì9ŠÝÛ(ïé]k­Þ»>›„7¾þž#÷†)]…u×Y­Mý½™ ¯¬Ëväã^œmù‰ÿo GÞ2ik–ßzF†ñû ú’8q&¡T”^v& ’Q±0vú;Lù*s–Àí´$ì¢H{’h·‹ûôâH´WîÓ³’çV8×ú,6‹®¸ï£ã“»X#JßQ\s•¶Õ]ud»HWû¯V$ìwÃ…Ì«ËYzuù!]ÀNí|•¶Çž'ìaÂ.Ww]0Æ{± )?IÃzˆÇj·ºÎÂñª•æƒà·â2(³›«.8žÛežOþó:w{endstream endobj 79 0 obj 1834 endobj 83 0 obj <> stream xœÕ™KoÜ6€{Ö¯Ð!@% ¢93|öèÖ@] @Óè¡ÉÁݸi€8uvm ù÷¡VZmL[˵+ 0`Q”8oÈáPû¹Ö j-Ûëêº:ùÕ×ï7Ôï«Ï59 *¤GzåêŽß…)ÖÜ¡U2èô¼:9Y߮ﮪ“ßj¨N~’§¿üÀ—óëoª³óúU¥EhIc½½¬®ëÓ Ök0ŠŒÃúâϪ·ê ,ë­WÈO®«ß›³¶CéF×üÓvF¹à¸yÙ²a,5×mG*j£CsÓ²¹èÈú棼ŒÚ;Ó\ñ :*c\ƒÒku¶ùž›Ä.’™»l‘u8Í:)hÌž¶‰Üm3˜È*´Ò†(Z”nBTÚaóGl#ÁžŒO»îI³—ְƉò7¨ñ."6Л}ó¦{ß^üÌ@1cˆˆFŽcÇÑdŠï˜â Û$&P‚!$·­•ü$Â)É¥­D˜J´–eé^ÚúªMPLó®í Ùð&êjx lÒݼ‘îRÿ-;ÖüÝ’W1BlÖß¶˜ÆäñŽŸØ~DzïFZÃm¯Â÷b6òø‹ 1æÈo±>¥5pœÿ’ÛµHû4yi”ž†'£¾´ÁóŽ·â[“¯Û®7å; ¥˜J͇Ñz,„º„¤RÖÆÐ“yÌ~CJƒí‰Ë¨“à-f‚7‘UmÒtvQñjRí Û• d”éWªwk4ì_4Y^"%‹”#¬)Þ ΛA,DgŽXû5ðlç$’ä±2P/NŠ{( ç¤£0Í#`"WCà„ú4ò:åÂ(¬µòà@G&.Mo¼¬¯ ”uÊð„D‰™¨´í×£'òfòx#csEHAV ™äV¼È¼•7c´~Œa†Š#ÔfÈÕ¤'dµ\Cd´ÌŸ'É f4'øR1E–ü4Å2â-粓ãqÄë9yásàÝÇt¯§q?ÆYÎE6mt±Ü¶¼‹`qÑ9¥‹],¶-ë¢3œtpÑòC3¸Ø¶\½Øæ%§6W!ÒÜõsúÁVšûÓVÇ"gܯsÁbs}sx˹dñZž½E[â±x9‘»^Ëû2ø}¦Ó^rÞ+òûü·ŒæÈ”»”'£a2FJêž º¶Êm˺h¨ðÐr¤‹\Ð¥ÆÁ.–Û–u‘Ü3í±s.je÷óDÚBçòDÇ,Rf?µt©þ±phÊ8&”óÉbF®&—ÀŒ4”2ð`’žÉ-f‘rò``™"ÜX„Kزƒo¹aY÷`‘‚ŠöÙz*»xî— s(ŠÈ¡pf‘ÊF…ãh<{u^îyŽŸ¤Ä¶x‹¼ÅÂc^¹m¹/©V?Sóø‡TCÊî}J}äkf¹m¹O×õS¤ Æ!†´ÃáWɯ ·ÈWÕ¿iúæendstream endobj 84 0 obj 1258 endobj 90 0 obj <> stream xœÍYmk$EöóüŠDg>l§«ú]äôÀˆA£Oä̇p¹—M‡¿Þ§ff{f²“Kzw$°[©é®ª~êuzß×ZQ­åoø>¿¨Ž~õ«ËŠêWÕûÚxŽ*vV˜”¯WXK)™Tƒ¡UŒ²éÉqut|R_­¯_VG¿ÖT}'O~ú_ÇßÖŸTOëÓJ‹ÐŠ:õðu~Q?9ƒÖT“UÆz®Ïþ®zk¨ŽÊA×ì‚b<¹¨~ož¶+6ûæC»²ÊGòy Ã,96¦¹hWF%mulÞµ0—½q¡y-‹Yo›—X “²Ö7,\§ctÍ— ŽhìtÛó–¡ÃnÖâÈÖδMäd´ *´ÒÖ˜äX؆YiÏÍ_`— Íd¼Ù²—ÁÎBãDù³FÔŸ˜êÍO¡yÖfîgßP2€0$êMðãÊ8ÅQƒñ@¾ƒYb…éð0ê"ãéYu*A`7! @§3]âüÛÃÎÁóÞ«h’è!•lïùu¶ð­|tÿ¾È¼î_ÁÆ*¦Ä PÐT…é5CMÛvEh‚Júú¢eA¥÷fó|üÛ®<”Øæ^XB×ÑFÚ¨JkgÂ)Åèß ÙÙÛ/ L‰åÂ%ûõÐ ¿€½°Ë`…&‹“¸æZB û‰csYbUf\ËyÁ%a RUËÙÙÈg­C’ŸàyÛ{>À5Û .gÒÜ¢¼‡íÚ¤m±äQœkNHçÒ‚RÅI€r4"Œ’/v[€r@JÞ›8 P7@‹C^÷áùc‹Mˆ}²ãH“”NÑ+kN›`¦E&K ¤6->‡‹QQ‡z*8AKñÑ*'àR,MÉ…IêÞ@†PFíNÐÔ¹=AØ–Õÿ¹c¬3ö’zR6ÈøÃÔ¤e—KsêIÑ«{§ÖJª±±ÏÔè¦|#í+ט Iè('}”ÓP*¶yç™ú3SëLëÞæ½ãÓ ëÖ›u½µóc­Ü¤.®ÎÞJ›íû)ùHc5_I:ÃÉ£!^#yDþ/]GFÀFéÓ¤ ÖÚæë®´ELÍo=É;*ø”#´XÝ¡Éè˃ N¦‰Ü|šw|ޏg$R`Ô¾èšj=¹£.;xµÿ:ó^gêj¾nÞ`ó8#º8GIÎIE":ÚXVjo Ê&í-icRH(Ù1iIabI…bnÉúyäle½€Ã z’3ù$‡Ç¯£Vì-zgè™] -AÑÖn rî¾¼¥ Sp‹QY“ïã€KyÀ|ˆ·B‘óè…©#µÃt=p1Pq¹ òc,¢á’/L¢ÝÐÀAÉ.¡— cñ˜Âhº µòã.£Æî0“بÉé‹”\Lx³š%è-ÔÇ>‘I#°¼)€´‹EH­3)ŠHÌ®ŒA™pWøÝ…A¹ñ‹`"(wÄ€ó´w _ÐË{K—7Ž&í+ic; “ö–”MÒ´sÞ0iI“p—òö)¯17øöž]êä´ÈîŸ åX,BªÃÃ6&鞤Î1ËuåžµüËpèÒ÷ð"8,)’W±dUê.!o6êùX|¯Û¬;±*>äVÉèöóãPá­2}§IØÜïüå†/?b(Àão'j.mʱEHô/H#¥ôÿ®ËåX,7ß@»¿»ÎzïÞ‚ƒ¼w‡1hAÑfsä®ÿáï91Òš…[έ«/;¯Ø°¥‹eǻߞMî•wc4jÂðÛÄä·› oN«ÿY’ûVendstream endobj 91 0 obj 1378 endobj 95 0 obj <> stream xœÍYMoÜ6íY¿B‡¤¢É~=¥ P Ú ôEb'nØqâ´h¢¿½o(­Vòʱ¹»1 +jH¾¾ù )¿«µ2µ–¿áyr^ý곫ÊÔgÕ»š=EsWGŒòu‡±&%N5ZÅ(“WGÇêïÿxQýR›êè;ùyðÓ7x[V=<®WZ@+“5ÖÃãä¼~°‚ÖT«ØzªW/«ÞSGå ‹jrAzΫ'Íö#“oþj;«|ôh>ka˜5Ž˜›ó¶c•´Õ±¹la.yv¡y#ƒIo› “²Ö7$R§ctÍWh2–Èv:íYKÐá5ï³âHÖδMp‡f´ *´Ò–991)í©yž]b3ø؈'̓œ…Ɖò§¨ >5¦7?…æi;J]}BÅ !™Ìh‚;ÂoÔœ‚È ›ßÛÎd>84W"€Y R’Spu/»’AX…ýûs¼Ûüú¶uÍŸk™2ŸËûòóAæ™,ÌïYË+A¸×3é–9>kÍÐgÌ#NÐ+m°ó¬(EC±9•É]˰À˜lÂK¡½@åÖK’W¸;+-–ÇAý= €sxæ˜g5!ä³c.¡[ŒæL¨DùÐ:²ûYÏÙç¼ämgTä×€ªÍ1ñpU!U„Ïâß.´}~! ðÐHm]”ÚЭ9mÃϬh l’…Àј8”!+VFÎ`1&E%`7 (5É{ŽÓêc„FhåCíù±EŠbŸÉ^Wñà$R– 8ts°ƒÐ"Y1’ƒS“ûœ(s(51gŠ2”¢zhŒ7:!š14%Fon1cP)íNÔÔv]éYO¶·+ ³Õ(Ðûဿ1È•¹\ê¿H¢ ¶wúç­•¨}¦E7˜àÙ¡ÆÔ…™¶¯™¹åd+@Ëi ÈämÙɺգÏÍB½Íõz@ï~è•ô„Ê’MQ2›µÖõf¢µs'ï›G£Žúî$Õ{-{5Ê.Æ]Ž²ÍŒg 3.FÙ‹Q†@•„8õ^øå(Ãí¬“…7_£i°R 3…¹u•g¶Î×Y¿Òh›†f¢‰á×ý$³¯ù)·NÆÖo“%¬glƽ÷æÖ鸱wÉï$»¨Ÿ¹ÝÉñ¡w;§4)ó<Ùd\q¢lœ“Š=d\ð¾ì”wh4io¤Ñ$#iz“ö@ ƒ<ªnÌ UéZ"_¯J^#eûªôh¬4ƘڒåVGÞ‚øÐ sú‹[–2[³sîÝQ¶„aBn9+‹äºX6»‘ëX™¸&·#ƒÐewÆyìÕ)75²Š)L&lx¹òe,³Ãâ}°aåL¾ÄNª8\nBˆæÄFÓ­¬/w‘5\¡ÊŽ;²Æè,ÎO„FÂÝn–Ÿ7´¦4öyl´G–ñÝ-§b‘Q|˜³÷mŒâ Nc²Aq¸-únã Üøe´¹ä D1‡¯çå˽aÿ&ÖûMF“öFZ›dp1Ûkm£I{#&•ÞÁo6i¤I¸kœß"ÌÌGwž]Êä´ÆîŸ åT,1Š«ü'­¾¿&|\RGJ'[øæ³\VîVOË×±È}ÒÅ"ª¼¦ZŽa6¦çä鑸N¶V·1U¼Æ%¦¢£Ã|ù8S!©À›Cà"S“°¹å¶/1biÝß)s)7aàð™S¾ŽE6tºë§wÊzMÿïÒ\ÎÅòöëy÷Ëël÷Ýh0ÈáqƒöŠv4‡â}|ˆµH²1g_b·>ÙÍ ‹m[úø-¥|ûÞ†µ§õÿO&ÿï°Æ•9îqõ¯Ràendstream endobj 96 0 obj 1450 endobj 100 0 obj <> stream xœÍYKo7îyÅzØE±4Éá³èÉmŠº@€¦5CÓƒ»©áØud§m.ýíý†ûÐJb"Qq„"ÈŠ.çññãÌpý¶–BÕ’ÿ ¿¯nª“Ÿ}ýú¾RõëêmMNÒT§½VÂÕÞU1R¬!"^tzVœ=­–ï.«“絪N~àÇéOßâçì»ú‹êÉYý¬’¬´RÉb=ü¼º©OÏa5ÖÊ2N×ç¿W½7ª–®µõBcæ¦úµyÒvšÅÚ5ÿ´.8 -3Êj¢æ¦íHDidhîZ¸«Y߼ᗵôÎ4—xAFaŒk4K­ Á6_cH‘Ì|Ù¢Õ°á¼n–ÉpÐÆ¬Y›é†ÁD˜B¢h5‹Ik!n^&Å6’ZÓq»φ½m ,ÎŒ¿hØŒwQëFõîGß¼h'éoç?P¥1`ˆ*!±vS Á€ü¾ÕQÝÐüÙ&”!6CVó¸y€Åæ¶SÍ47÷ôEêg–Iú×4¿àGŠtxa1¬ÒÍ5KmZúw«šeš¹ã•xà!Ø$Ø.AÙ+¾nÉóì­Ee¢PTIý‹åÍ ?^òãŠi ¥bL^ŒzOVûiþå4Z¬¦osË/'áræàöatjÔŠÁ³2F1¨„»e¬ÈèÎ|Šáàÿ Ó0˜&E›ö¸ÓÚsø"am ½Áç-1„Ö&gÉ%Õ¯Úa‡8*£Ä—£,mÒÕ°¦yßï4v¥Y¾cóX£rèð ÇsŒ4¾àÇíøè¡b?ÒÞ&ê“–_)µ=G­Öì0’è5¸R|j„äÉy…4#œC S`˜éS˜w8Úx¨µ4eÙ .JŠÛj•ó™qP¬¢sü[˜k…D \¯Ñ°Ÿzu²P݇2¬öȧpŽÂ<Å*ë¹Z… |Ÿ`IY•td%¶Ø)±<ôÆc :Ð.ôËV újÞ&Âa”¶?žÈ›Ùô=¯ÑÈ¢¡aJ %å žu>ð›1Z?mb¥ï؈Ôf¬b$gÀ*¡WCœªÜ'ê ‰8ƒCÁ„Ï·Ó\Ûø`©€º3Ó/[öLèOb°ó…1o=žÄ»nÎ&‹~d¹Ìad¥ö¨ÅÛ20Å’̤n¾G½Éu_ù9™ìZ0& Ô34sT1n«”ÑM® pAE‹Þ|´HP£ìv’]N²å†ï/~5Éôð"øþÍjÍCÆàý$»Þ–͈¿ÎމgåôXiòzb™GÚ.Ê{bÙÆl² ÞrIb–é‘9¹ áÚb¹oùÑJ>JÊÜ¢CSSa±kÙZ†cDh§ªš+iÑÞÚæ)2¼Œm*WÒñ„p”¸?u0ÑÖnN§£‘‘íB·–,ºÖ—fôÑÅ@¯àµèO”_Çt.%î3ȯãÿ‘ô1G¦<¤<2R>N‰ÚŒÁ­ÆLȤʿΰ* Ý6Ùv‚Vm4ƒk×1@#°c_ÐfdÚŒò(²`àNÍê>?ýæqÎVyHYdt°GAFÃÜ€ŒÚ·l•û–Q§÷Pvê=ö±Ø·lˆœºŽQ™e{µQƒS‹¾3j‡Û•ÙÌ)g¨}Ëñ!%ºŸ,ÌÒ§ÂÝÎg`^k€vä–=³HyDy`Šo£q1ão?; ÙÝ1–°l'„Ÿp_Aé(=.w–VYê3¼ÖзÞÒ¡lÑÞè–Ã’7Ø£ôBA ¢Õõóÿu)Ç%‡®Gi®<¡·’ºìê[î[6BUøÕö°rwúCÉvzËvŠÛ9mÅqäÐpæ(ý¸? Gï#Ê#ÏágýQš5ÜócY7ZîØì«¡™Â“Ô$}üƒ²!a3Ÿ“·¾fšUxÅŽå¾àãþjH:=þõgö·Š…%òYõËrmRendstream endobj 101 0 obj 1445 endobj 105 0 obj <> stream xœ•ZËnÉÍš_ј€Íz?²tbddd"`qIKŠIÉ–ä‰ó÷9çVWwS–G%#±/«Nß÷=UšÏêu§øoø½;-6?Çîêa¡»«ÅçΓú$_­M4ºÝkuÎ6w¨>%nzón±y÷S÷xÿå°ØüÒéÅæGþxó÷?â×»?u¿[¼}×ýc¡ºÐòÆnøµ;uo.ðÖÜi×[LwñaQ´Ñ]ê=Þe:ã54¼8-þµ|»ZJMX~]­]RÀÇí z9íµËÓjmû¬œJËO+hk‚õqyäb£bp˨Ü;––R¯RòË?ࣅ…Ö-÷Ó¶>*grÈD[×çC{çÜòVVûlõ°Q>–Öfoæ+v³ÿƒ6÷&äåUÑ#Ç彨—´ÏÕ¨ ’,ˆklÓ±6-ïÆm(Ì}Niù¸‚)§Ñ+![¿|X­uï”Íaù‘cÒ°cúÿ}ñDA[ÄÎËZÂüµö½ qÙÃýð%®/2ç¼_ò§–+ü@õÔûÞ ¸‚vý©ƒ…ã…Ýò:I¸Ø„^i£Ö†æZ‹gË¢/ü!²|ÏåJ¾–åÛÝÀâé5ÙξåpK¨+.ñ²d>ÒE9'—åýÌ€e7Þ¤‘C;`ð¿»•§FŠ‹µIÜ=~ˆuFl”—_Ͼ;TîWô×Z´Ö¶÷>§â§÷ï½§6\Ì Ó/{EËñKyÚUÈÃjðÀè!‰JÌûqU¾»?—Rvþ’_ëqí_]á¿Ójtw%$7×ü”Åó3Ç̰/ÞWÚŠŸžuÂýÃä¥íÊ/èIEH?Ív0tTIÌ»‡Åt½&¹ú×ÅÅï%[uїθ"áÞÑ=tÏ↿™uOuŠ¿¸˜zo‡d³ À,MĶšw×cZŽ©]^õuT‡~ütžç^–=Ývž÷y?zà<ý§‹£eÉoz ‹¢Ö|Ñ“¤®þ²ó/·ÑÙô°XóeÌ@цŽÚTg]Ò‰ôMÁòk|ýv¬³1C&/W›’-î÷˜ïµ½\¯†¿©®Ÿa-ß1,"ã@Z¯ÏPkS ¶‹¢âþIB…jjiÎê4ÑÖVøtÁ·%ܯ ÷¼½X`’ö .MÔÖð°+S:´l}Tê4^Ì߯ÐèÒßÂê¤>W`¼¹7¯þ¼0Éö˜å6¹;-¬u˜Æòp¼öx–ÇëÅ/ÝíÂõ:zëºÿ‚ü´(Ìáç?CI–"HIc2c*—‰è!Y§ÎçÐÏ÷šŒ‘æÃ(9ްÒHê®Ir½ø§°þ»ÿ…ÁàÑ)g»‹‡žŠï“s>É(¥ž¶òdRÏv^õ>ÇHf³Ü~ÙßÜmvûõþæaw³_]ü§„ú ê³7±EéÓYŽE§ªŠIqæð¡D+° 2¢V¶%:™/°ÑWX&as®°J ,(}sDc¡Ø, p‚tž%A•Ì’`ØÕž6$ƒdmèh£6æg{ܧíýööîfÛœA jòuƸGC¢bO𠝡¼àYX¨PòÇ,ÅK(ÔPÚpœÀÑUR´âô†Nâ\7s†òÞu¬GkŠUH„\\qªEÌZ.PB¼x/Ìk9 º1û-ø³ð/Y¨×¬eœ;@tAÙËŽ±–y6Tæ-e‡ß …M¨j:˜&â-¨ÖÔ4vˆXPÓ€j¤µ5¤öZƶì:á¤YN ´´±JŽ“Dáè<¾‹›ªà·‚Oÿúà“†BFRsXáÐÓG$£¿?üz8nŽ7—wwÇ5’ ½ à<µD" £±ƒèʼ%Žˆ¨ë²ã„«Ž\æŸéSKÚ’œwȦ,ø²$@¡‹drpö§©.”’Zÿ¯E;o1âRoQðlq(xíñR „à@fUnj^¬!*ü_Q‘˜D5åHGT‡ˆjT{xÎ4N"ƒò1¨’ã(¡rN2ìš$/µþh[®HÐh#¼x4=›çÈ„æ. àž˜§¥1Á™·ªœ—8V³írÀéGó½8´â@–1÷­uµ¤MGž€%e#E†æA÷dÇ`~8G‰Ì/¶Õ4ÏÌè/É£B¡Çx £SÅP`=9aëURÛ€–›‘) Hu™ýS@«dÐa×kjÑ×›4ÿXsÐR×W§íÇW´“6H ],×Ij6ÂApjXñâ« ÈÍÈ[¾›0™¸§w•rëà…€dr©%ž¨åú—)B`Hkªû¶3TðÒH•6…Ÿv˜Ò„Å ›^q†RAšñd¹Ñí ˆå¹jtFѹ̿@"—å¬A›æ¹œ™§ìXEEœb0¿ÒÌrìDÿêè‘lšØ‰áåSÊ‚ªuÜYìP1xfδÞdLW80òŽ\$dB˜ˆ+)“L@Éx;–4ò–¿ÌÄȬtd›QÈ©Ð'…©-'—{« bà½ìn$e¶´vƒXa•»•\§¬)°8Ï4ÇÛ&’ƒ™Ý£d0¼>†g†‡ID(7²*ç™ÙÝŠ·Ã’–`SRo*Ôjx÷d5QÇ­DTn±çLÍÅó¾ab"£¤qS aËRÞ¡e4ÝoÃÌŸã"'×Ú°,ÿÔšò|²f”iŠóÉ:H¦¶[wµ7b û–6lz(ë·møòæáî¶Ù*PN%!Vr]?I´“[¤á9G^gûéÙ²'Å!;-é^.R+WXÇù)ÞñEh9”LuMC‚ ¬Ëåe~®a£Ò³®®iÍÑh*ËQ2”e}Êr|<+ËjøX—Õî©.«ÝíuYÍžê²¾|ªËjö+KÓ‡†é´3ñåÊ‘”x’'‰%³•–_w’/|sÝrFè=oÎAtc”ÿ«fyÜÞ^m>˜]ûqNÀA ê±Ìº¹Y §Ï&CÆg²öi¸xþ¥RäRʇ÷¹$Žœ¨hÆ5Mð&——©4W°ÖVXž\†5ÕÃü÷ð®Ž8endstream endobj 106 0 obj 3060 endobj 111 0 obj <> stream xœåš[oÛ6Ç÷ìO¡·Jbx¿ ØK·Ë€ë`Û€åâ&Aã$uÒ¢{Ùgßÿ2)ÛRåâfØôyHžß¹PR>Tœ‰ŠÓ_÷}¼˜íýêªÓ›™¨Ng*e¥g>^j¥“‚ÙªE_‚ œyOƒ^ïÏöö®n—ç³½ß*1Ûû‘>^ÿò=¾ö¨¾™½Ù¯ÞÎ8)‰8cÕ}/ª×˜5TB3¥­¬ÞÍÒjDå™Á\²’F`…‹Ùïõ›¦•$•¶þÜ´šYoÑ)Ãæhr-ƒ ¤­•šëìJl´Öõeìm‚ÝÀØL=” Fö{÷þu¨À¤ õiZGpõ2îÏ V›²Üën'Qņ ÇœòõUöŽ„ïëÛ»ðÁg«Ø L}Ó´‚i®‚­ßSÓy}tRcÝŸ?‚Pàã1Ào…aÊrp9ùÿÂ<éãš>éƒìI0ºÖ1>’6éúÚ ¹OjÚFaÏCsb–‹Üñi|•5 ±¶>}qÕ÷¦£iìPYئŸ7š6©´dpÚ¸^¥ç¬Z/ÓFà0Þªøó’äùbüuÜ$XPB#OS/iüp¢k2s^HáÀ‹¨Ûº]v£„ªÏiaQ]¿ÿÇ^û6¥uþQ7Š´‹2l ÌÈÞþ»A7äDÐ ¸ÊÂe–ž˜(KE‘6«æÙ[i,“p ÅŒ >MNˆÉà”ËEÓaˆ@ KÕ ? ¹§­o0¡4©-¼%E¦¢ 2 m½$Š,mêÙÔÇ'ÄË2]=!“'+5Éœ"…§þIM§ãˆmo’løAs{Ь•¹¯³¹‹ çYøyHˆØ@¸F÷h³pQzždáwY8„Àª5Ï'§a¬‘ÔÿÍÁ é–yLä»T.à÷:¥rg×R;Æñ%€ÑNÊâXòȶZœCˆ¯s-&*Ž‘_™L 5-Ó+Ò&‚—ÓŠÍX¡AR‚ãX«|¿Òxœ“˜“ËTiþAÅì^Ö{±%5Žd:†Te„õ1žñð×ëÙÑß1áµTpy”S­£÷¬.Ÿæç42‡$wÅ’¬“>s…Õy1P´Œ¤oÂú|’5xÝBÅWqåFŒ-R ¾›E™¥^[ä.KÉ–šÒ¤UΜð¹á"6­à!¦ýÔ¡·M‡TΧ­LöÈJ¯S°Mvl¨ãWƒrÆ)Ì¥G µè²"hƒgäÍ#:dyŽóˆ u1ˆÑ*N²ì<·®òÕ=j BP­Z'¹Õ®Ëâˆó,»{ÞÑÇ6ýÐü˜.³­²­eÓ{Ô‹ÿm-ó•¬çr` ãÉdÆ#ËÆŽž¬ìâ–ƒ&í ZI€å8úiS¶Æ®»H…âí@Ö»ÛŽy@?ò#’ÖxÃ<÷:Òoæ~´®üc9 »ÜÜR0=;œà3ÓIù Ç1o…4&Cx¼ÓœæÖbwIà÷üËÀ=Òî`ŸèùßÝ´½gæš à2Bå«Zr%ù²#LÇ7âÞÈ]Üú8Ç }ÿ×¢þnˆý[­{Çðt‹ s¸%ÙA‘·–žà!ÅÝ·­[ã4A4ã ˆb8Ýô# -½=}~†Æ0û$E· µ^÷p–§„ŸÖeQMIŇõ±¨_Ãyy8Óm:Çȉ¯òGkæ™r‡³uvjõXvíŽõ]6¤Ì­ã§!s1@æ(“Ù*ºk´ÊØv»º•ÏZѽ7ßéXFøj¡wQû–ÿáã+Ô¾ÒqôuM™¤ÿ pŠÂÒ¯ƒòò¿ lºG€)nvQñ¤d.W¼Ç;ºÓúýä–•Ëg±[&Ùz$âݱvvÿX›nñá—²ú1¯v{ï릪Qåîÿ)úÿþ€Cͤñvö/ò4> stream xœ½WMo7íY¿b“ô° tirø] —´)êšÂ@uŽ$ÛA,Û•£&¹ô·÷ ¹Ë]ER굓"ˆw4$çë=É¿*)T%ù_÷¯fG¿ùêân¦ª‹Ù_•vDHC-yRÂU-æªu¬ "^ôüxvtüKõv½YÎŽ~¯Ôìè'þóü×ïñ9þ¡újöâ¸z9“lt¦’ǪûÌWÕóx•2BGÕÉù,G£ª ,|QEV!“ÕìúEÓkÉÕï›ÖijqeIëzÕ´ZDid¨oDKN[__ñd’Þ™z‰ 2 c\­Yke¶þ¢F†ÚÔ‹aÙ¢4]dk-w½Úcêë4ÛF­º…IÌ3´Ž–Æ3棅‡Ž‚\¬/rÑ×ë”_P6öI9L—I2q‰eÊ ¯C}S–³2ŠBý¶A!†Rµ­ïšV #utõ}PÈ£ÓZçÿ<ù((\P¼¨ à·ÆS,Pû㆒#h¤ôðn¹& [ª_#–¤ºæ´TšÑ6šSÓÚ P&O¹ËÃ]|&[H¢•™‹XðpÛ·J ë$åiç·~ŠE¢!ŽñÅÉ X"tÍ]iÞÙ©¹{‡N( •rükR_GÇ@gÙ5«”D KÇ߉F¥” ½EÃqb7°9k&š;töÇIÓa|ø(´¹`à˜š|øüƒÖ ïê£$(òŠ[¨±<`–Â+§dL{G {©»©¼èvP‚VhpÜÝx E”Cº*ø>_ùEóRÐVº¯†x7{³¼ÄEžKÞb¿0hz”3¯µ7£Üvà$òij2ýíh÷7ààü|œŸyßG¤¦Z:\°û€ã[KLX@2tϸ6ÜÙžd ÷‰£¢Û鮌®Y²0ÏKÒ«"½.Òõ¶½¤;+Ò»"1Ã=ò6Ä×€nÉyŽvćŠ6ÔrÕÕ×ì°ÇX*A=ÞTEóyv3¶Ó'YÁ×vʬ8oКqâè{”z|‡2Uøº/GcEБý å+÷˜Ü}Ó,L£ sÞç’ª4.”ÞM+‚5Lbžµ1zrƒdtZ Ûæ'Gá6ŠŠŠž·P`*¢>`rr§ É9R½mxK·ÀÔY Ž2Åa-=·‘B#U´&˜z˜C"¡u†©5ä1ZBàþÒ(oÉP°’·7_ûœC.· ­#ˆ‘õÜÄÝ‘„ä=ñƹ6²Þ§ŠbU;"=ÇÀ×R,X—9Ú²yDk‘¢ÕzŽ>> ê!pÑàNR)ò~R트™M…õ¿_:KÙô/Á+”Ík\]3BHæÝø_v˜g}ã‘`þùR<õ}Í2(9(ÊyÅÔï+ HëqŸ½³ª½Ða&}ãeå|XòíD+ógõOºE#UÖ»n ް1h¬×¬wY_ÓrÈ'¬5§O«š½°µ+4)bÓè Ö‚ŸNþÊY¬ŠÓƒÝÍÀ¼Û¨»ŒÒyýu§Q÷夫8ºìcåB‰(«¨my“¼•÷½µ+í.껣AJ£ J…,}3ib0øm3¥7ÍŠ*U¶+ˆ2uƒù•‚תð^¤’Ê.„±’Â[Êó´þ ë’R,ÜMJÎdÓû#׉‘÷Q™¤ÏÕ0Çæþc•h¦¢iŸµ 5x_Prˆ¦©@qô²;tçy¾ ö:êVQ÷a Œz´£WQ·Ä0óI¯)â!¯µŸ<\t}èq7Í[uGk6çùÒ3þ ä§ä×Ý(6<n²®QÚÛùŒã6ó½üqNP?’{\,Ž‹uâü]¤w:/RqôàMeМ&[PÎÇfeṗüb$¢l±SÈ åÓˆÜÆ1‚º«(-ëv®l¦"÷ÈmÔ%üW›çu«ùœ÷È_]e;åä¥í9Ùɱœ—ùι'ó ^uë‹R}[Eâ>¤kq}ÕÚbuÃJ6‹ ·iý@å‡7”¶ð’Ç_ ß ÔÞÜ]p÷±«ëu‚;ƒt¥QJG^¼gí>hcð‡SåðKG¥nxº‰êÄIÚ8ïÛíwòCIjþVc¨ ÅŸ§…nAªùa©™ÚH\>Ó‡£- ¦Ê¾JÿL$•çã2†pøx„Buà™ÚHŒËCtH'©îuxxúÍöš^än2Îñ|ØFà@¢Wâfæ Ík ëËëåÂ+‡ñÏ€(ЈBÔm=ß周µS‡x?Ô@­ÿî¹oq¦Kqºy,»E—¾™ôŠób`…è–xýyqçâÌGm~eõ!z£Â72ÿ¡ïå™ÚFÒÿh÷ò GÝ«ð3­MÇÈ¢k%÷%0²ì…Ö‡¸àp‹­ñ@üÌmìK¦2ÏÓB·}Ρ.Þo:_2·|LÌvoè÷F|w{ŽŸ÷0#¾5nþ,`óÚËÛâ?+0»endstream endobj 124 0 obj 1511 endobj 128 0 obj <> stream xœ½XKoÜ6îY¿Bq”:,—ïG\ܨ‹m =Ô=ØÞõ~ÆÎ&í¥¿½ß¥õî:–EÕxH‡ó}œéc-¸¬ýkŸG—Õôw_ŸÜU²>©>ÖÚ©ÀCš(¯$wõseŒ:ÖP-ÚÞ­¦»¿ÔŸnójúG-«éô³ýÛ÷xìþPSíìÖ*AF+™v¬ÛÇÑe½½‡]c- ׯ©zï¸ÊÞÈ:p‹½T­¬„‡{—ÕŸl§™(Ò*Çþn&†»à 4ðËH«´f—ÍDó(Œ즷ÊiëÙMVÂ;Ãæ˜ "7Æ1MZ+B°ì;ˆ'Ô†ÍúesˆÂ¨è"Y›(ãó®S[c »J³mÔ²]˜ÄHœ£ÕZçÿÚû (H \¼( àO´‡9Å áÿ¹Q8šÁ&žÅ° æB[À"E*ýhÃB?m¥Ð®´ú”&ÁÅdL#ô(ìïcêŒFh—Ï@è±)†NðÿÛ¦uçv´*»´+.Ò†)yÊý¤Õ䨒yëk’-œÖìbc*dßË X’ Èl07Šâ´³WÌ<`«Ð^‰£š|Q¼CÔ”ñ\à!¤åjÔAôÒªYiÁ×–Ñ`dôå«¥”¡³hÈÏ “¹FšÛt•Ç­Îé0¼ÈÞƒm<§ºÈÿ‚¦Ø=(àJ’B¬‰ŽÔõ€Ap/×Z)–v*-ºé•à³åZá@v¼À„ Šþ¸p =¯¯zÞ(¸Z:îaïïbí)/zq–ç*oAlÅ6JåÄàµöfp¶8•òOij6]¦GÀ -<8÷t3 ­–‰ŒdzìÈ¢³ ¸`×G€’ô€.#÷¶ÁÎ%½ÉRó´èEº+£·$Yà—ç%é°HgEºZ¶—tEúR$"¸Œb“²ä8G; Ã½˜õá´Má÷F>ÈâÔóMuN9-Ç%ÙMœÀmzÖrã2+Ž\0T-ýˆð÷oÓI­Rô|-ö˃Ž!¥k£òAo Áo¤0 «Õв/*ñ*ëˋӒ‹¢CƳØÜ!%nµv¢bïÊL1‚ìãc´)ÚFª×Ì5%ÚZs›ƒ}V‚}œÃ …dû¬Äé]‘D&çØû¢|% BXÂ`V¤y‰çç.žÝEÑM‹î¤H—eô èÎ×XÙ*Ò~3´ñ¡Þšê5+»Ã¢½»Šhëb©ÏèBÚªîÃRïB]®8FÇÑ^ÆŒ³¤ݺAæ_í ÈÔ¢7Õ÷ƒ!Ÿ“¹—_&£«)è©›™¥g¿ÄN[Î nõu˜_Õ=áñ¸lBXFý2éþ+×RJnM†y^îeŸ³îVïÕ#Â0ÞùMaÀkákÖ"º€ÏÃ2Nû„2Їª/GeI/Í ³úfênZr‘01Ñ·-‡e|QV¯”˜˜^*³cf`²_rÏ{Ym>0C:\«S鵿›÷fÆã· ï4/Ó“=ßRëRp/ô:ùðÅKœsâ%Jž 5È«ajì pu¤›ÝõjW>èÔ?é` ¿©¹·È\cïM¼]®¶=û7Çñm<$°õvä'§aëèW ]·Ý÷Ed}&^,'‹¤;-Ò }BK˜•ãrˆò—A`ÛØ#±XYÇ ”ßã5™fÅèN×eŸž³’K®—w^ž÷u”ǃ³eG_lþ‡w*ëx1f˜OÿR5Þ¿u8¬~Ög’Ι'˜AŸ¨Ö|ˆ³ÂŽËÀªÿecß~endstream endobj 129 0 obj 1407 endobj 133 0 obj <> stream xœÅYmk7îçûK)dz:½ŒÞJ釴†ºPHŠ¡šê;çâ³ó9u¡ô·wFÒJºónì½$œ<ÒŒfžy4zÙw g¢áô/ý.Ö“ùo¶Y]OD³š¼k”‘޹Ð5“V fšŽÞ+ß €3çHééñd~ük³ÝÜœMæ¿7b2ÿ™þ{úìGü9þ©ùjrtÜ<Ÿp2:aÆ&ý,ÖÍÓœÕ7˜#›“W“èhÓ8—l¤èáÉzòG{4I’JÓÞNgÀŒ3ØükŠ~ÐR©v=)æ9p×^MÑ[i”¶í9 –ÜhÏp÷ À´Š¤š;§Ûï°©0Bí²¨a“ƒôÆ“µ™æ5X@{Fk¯DR Í8B)¯e=bQ)þƒ~(Ϥñí*úám» ñ9¡}”áR$ÁÄkT–YåÚˬöŠ„žyçÚí£pÞeTŒWº½žÎ®¼ißRÓ:q$©6öÏ“_0 B`^äq\‰ØYÂJ$5«É’e¬'ßÒDÞk[ºÄB…9xl5sR·/Z2/Ååù÷t†6±é’šsJT¶¨üˆù‚ê?–¿0)x¬ŸÕTçEý&‚#ÑÕPk­\$$D¨“¤®L£+¸;dZî§X;ÜHÊqÝΪx¡Šuô{¨,‡œhûQvîP<Ü¡>yiÇuIì4éûM丸'9]+zÌ# R­¼ŠÙöªÊûY¤Rù¶G†üÔXó¥—ÈôN¸Ê­óÔmLÕt—íÙä<³û´¢\'»èw•eosk•{_fÙi–ÝìZ­óÜ»ÜÏNk‹\Æ¥4ËÝÉÿöI]ïéJ\›,{¿ÛZ¥W¢9И8µo¦ ?lFäÖ“N£;…¸:åÂK¿Àš¸%ùjMîq·,ƒÑäZX¦>M ßes· 4'ÝÏd¹Šúm;ú‰ˆw–ÖëBÙï±)о°‘¨¡^ê_÷²¨eU-rïÛÝÞ [õdúº‡ÚÛ,»Ì²—= iø¡÷<Ëð€¡½Ç]Fµÿ–ˆû¼.ä¾íñp±ëÃ{˸ËÝÞäÃÝqÝâÃÔÅ¯Í 62ìG; ;¡ôr§ä¹-}Gv¬ñFcÊÆ×øEOßÎo2½K‘/‹cÞ² ¨õ”Çc3„²Áë2|¾’QÖxÏ5åÓŒÜeç¹µL]»nIwÈ…Ö2·Þì.‰½ò²èјíÊö–tÙ>=½YãyîPž4þ5îìtXž@1•N<×=y*¬/­;µµ¦ú@ÚHÀG¾ým{_„Ëoz4Ô¨Ç4µô#¯¢B-Sîqù8>´!„ŸæšrH4éáŵP©lUïwe{[U!d¹¢¬s«¼œÉòUàøGmŽÇžOR4?|„ÀCÐ99$ Þù6ݹÁNw~ëº;¿ðÝŸDÒ_q“îüJÃßRÞ|ÖÇ (瘎(-Kì9àêá&Éd½–ÌóÃÌ*¶¤WuaœØa Ï.2¼ZºU‹ª›§^ÆG#z‰î}*SVïG•ëWåÑ)¼Ô:%}Î¥…êdX=OEóLšÓBx­VA²ºÒ¹):Õœ÷8ZÔOÑË„ÚØç}BGíOYa30%Þ!Ò”%ŒðŒµ,ÏX*,i•éé.Ác!A^›ÁtGëêµ+y.­&¬tc®5®›jdõ˜–ßï_Mã×ÀÀbrZ>Æ‘ÚZ¦é÷K”ýRìááëx\¶xH}„mÕ¦•ÜÃÇøÐ02ôÍäóc¤‘Kyë;€„ÛÞî^‰ƒ™«,+ër@^ôPtµŸˆðµ¡“¸ÄGr %ZŽü,tXJ˜}TÎŽk ð…S¡»áÓñ:|ÖìP`…,»?öñ.Ä®¸~Œ/’Ž&¾ï¹ëÃqŽw¯ÿK|Ì÷¨ê}¬> stream xœ½YmoÛ6Þgý µ:i˜¾¿è—®–aÖÁÀ0´ûàÄq´±S¿´)0ì·ïŽ’HJ–Ò(o(ÓGòxwÏñá‘þ”SÂrŠÿêÏã‹ìàO“Ÿn2–ŸfŸr¡¹%ÖwM¸áŒè|c™sÂå  ÄZœôê0;8ü=ß®w'ÙÁ_9Ë~Á?¯þø>_çßeoó·E¥ó+æõÇñEþj «ºœI"¤æùt‘UÖ°Ükñœ+N/²wÅ›rÂQÊuqUN$ÑVCsV‚]’).DqQNqTR[\–`-×B™â#æÔhYœÀꈔº(UÔZU¼€¦…,æqÚ 4©äN;Ô6á’8mt#VRÊbéG+'X=Ñ7«B8ÅÓÇÉį`‡p„kWœVv8S¬½–)×8¥©•µ'^ÅLc†a‹U˜¶@¡#ÎÚb[‚ÖÙí„*6å„I…ÓÅlËÀZª´ùgú+ ÀàÁsÌÃàü SDh ¸Ì!ü†z1Š`¾qŒ®B©)αsƒßA#ÖØßyèá`"üñZ–¨a‹£yÕ^•ªùŽM/Cì|´d¥ÒOßW„²z.³-aQʤ(¾”’õ*…­dkp\(‡_|¼À\V;ƒ¦áWH ¿Ø#çœeÜÀ$ïàQÒ· æ£eÊ+Kõl‚¥­i,WU´¹iE[¥œÍ§¿eÓß»å øÿ/q>ª·ŠŽ½£á¿ÌË>à4%UÑ 4œáÝô6á·]«—×f‚Î19ØgŸ4~76JëÎK^™ƒ!²"ÌKˆ~sjécƒë®kàq´(ÎPǦäM«û1šH!%ÇQo¦ ±€†­‰Š IdET0Çæ¬¥ðÁ ªzGÁÚ°KöÕ2g ð_£˜J6R±×ȳF‰vZꘃÈâÒ!Ì,p”6%R&a1 ËÂyE¤ÿMÀê–¾Å!g(l1ÜÆ”¦u~{F!,õPœt…°­€"„¤x¬î0Ait—YSû‹(= ¿ŽÞr÷(Ú»ëõòclΫ±Ü(Èr(9¯ˆÙËÉÄ·=897·Ä3—ÍI  ia,~ÞV ‚‚Yz'= ö£ŒI8±î8«ú€ÃØR†‰B˜¬ {VÂÒéóIÕ‚³ñ Èv¡µ ½kl)°ç[G¡uZ˶>/›…֗Р7’“0eQu;•äC'h1þ££6Ø\·N¬ŽQwWÕe¸G†CIÛéڬЊÀŸ‹¨Î]qƒð·oÈS 5¯|¸ô—ŠX<bUWŽ> ~rZ1é·í´î$óEhAù«`­ª\ŽZ|ë)ôBµÁµ.þ­›Ž¯7«œ4Y_­çeƒì<È–AÖ¬åæYè^…î=œJöå,È.Ú&`ëÈÇky߯Qèí—®Aò—ùHh}äµ­²¢J–ßíÚ“SÈ@6¯áÑ{üû0’‚!Qð´•Ý×ÿøHÇgiIGÞk‡º»ªÆ(îFÖ›·L?¸ä‹šaÏCú-*`eÅû"dÎ}ÓÑË0÷e½^Ã} Ú$|Ò9æAö¹‡ŸÖAÆBëi½˜tÅó |Þ¬Ö›ô×Zµí¬ËáÂyÕÓ{Ù¶9ÙÜ? tÊåÆÝ„qÑóyâQÓz_ŽØ-ãÓi(1™e÷SöWòþàzõaXÕãBáÛÄ4Ôóuo¬gB…g@÷W¸ë‹piqìï×P„(Xô€'DÈ9"ñj^—Ë>w3ÅëkwÞ²¦k£’S%nÛŸb%p’쇄¥CwÌÆ¯×V1§I‘¶ì†é;>¤à8}O÷îAl¬%j˜i0Z”X3‹Gê²Ãí,Ì‘‰ð, œí F&|rÕƒ[2°ïäžõÈv i…ªbÞ¶»Ã–›vžÄ$ 6øÚ1­ º+£šw¨vDjOˆÌ²Š?ÆMÁ¢ðjT³csbÇún“¤Õ£0Þø((gð¹ö—ÖDa bÅì½EÅ#+æx4w’·]ÑÆVRb<‹›÷ïkg?‰[íENÂÀ1'ûø€ §…¼#Å6&Ý]SmìôǨ¥$æ.`’3N O™?ÒS<ç=˜G® ïLÉÛS¤»YO:ásþÎ!Y—5;…ñ‡ëXóÛ¹6`%“Á•Ìõ¿dUïG ¶‹YdÍ]{gwî;É%ö&ÀÌ5a)Ê_ºç²HØõ@–¶‹ Œï*{æ€ì¬Iº½ó9^üÙ¸j¯Ü÷m”ǃ3€² ê~΂o¼r|§oN„Ó›?Ž·¯ÿÍ^Þåå?y2«FP¨]z~[‚rý¾Íþãò3endstream endobj 139 0 obj 1785 endobj 143 0 obj <> stream xœíYYkGÎóþŠÁ<<­¾çÁ‰B”â ØÆÒÊ+a]^I¶!¿=U}ïjFÒȶüÄ»ªëøºª{ömC k(þÅçîÑlãOÓ,Îf¬YÌÞ6BsK¬ê¹áŒè¦‡¹Ì9á`Pb- =ÙšmlýÞœ//öf5l¶ñ3~=ùãxlýØ|5ÛÜjžÎ(*1¿b»GÍ“mXÕ5L!5o¶_Ï‚5¬±DÁZ¼áŠ…ÛG³çíf×särÝ~èzI´Õ@¾êÀ.É¢=êzA•Ô¶§X˵P¦=ÄÉœ-Û=˜@‘R·¹ŠZ«Úoà¡í¼ˆíI%wÚ¡¶žKâ´Ñ‰­¤”í±Ÿ­œ`QГa†NñzÆn%x vG¸ví"ØáL»ôþY¦\rJS+£'^Å>ˆ1CŒ°íI{LGœµíy^XgsT´ª=ëzF$N·o4–‘«´ù{ûÈcžc> ’ß3E„¦—9„ÿÅ‹NÁ =%f€…ÿN;Á eR´K0 PC©ge»ó_?ÈÌQ昫¬·­”í~aŽÒ¹ L‹ â× éÕ‡õ³®å;Tæ)|Ô*5t¶;8pÍC]ÎF»÷1(ÎYÆ­—ÌÊEÐ{Q£øÙëd±=¨„Š&Œ#D)g›íßfÛß<·™{›UKÀo e›hË„Ko TµÔ‚Vuh^4ûÎp–hßwB`(˜Ç»añðj-Œ“0RÝ.¯è<^‹bL•,Â\ùPÜt”c|0(¿vaì'E[9¦[؈£ìŒªÓîsZçÅsý®ðækæ¡Ë‹{'D»¡Lø9)€ xk*¼¯HƒÊáµyÒò¨Ãa¾³°1/ ¨vô9€:…F׬ÖqÆ “`&™×ÿâuPfŸãÆ…ÙÒ>Œ)wÊWj¿K‹ZêÃXŸa‰SöSr¼#§q!@ÖIt[†¾ ¾ù?ƹBÙ ž}˜!4v0 iòOXáÀtXË‹¬æRâ“•áѼ̩FSqæj8F±wk`=,»ì,nà 7·gÐ’ˆGllwLH"C»3BÆ¥!Ô6Ì*ŽÏ j(ÔÚ«j™QE-¬KøäÚh'SSF‚[´ñ‰ÚÆZ17ÐxÖÂÖ½˜QN$.ÙÔ¡cΣà)dŒ€N„¸…y~ÝÌcÚðŠ· Ù¯Gð@÷–ØÈŸÁ°˜`¥C„åPë " @ÁtAÃ4£ÎƒƒP¬¤§u°õ("Âu aVòÚ´s4Ã9hë•¢“¼v;ÊЋÕs­Á¦÷]:)RÖ V©Âv¬áhè¯AB¬ kJM¼Zé°ˆ_„Èq°Ô7|#e1LX{º¼|FêÕ¼CðBF&'¾ÉŠ-øaÕÝU ld çŽÓÃàô!³EÚÔø¹§=KÙ:Ÿ.¿`6‡¬ªådO£±Èž†;Qe{/` Ðýa€ TpLâŽc1ŒÌE¦ã°ÖÕð³¬GdŠfDÃÞPR g©>C9T Îí«vbže™ýµeüp4M´ÿfÖF–ةМxÇóN3ïM¦™z™©¢ïÂËrÁ‚fÏ;ÌÔ|5†žZ&‰t`µuŠ8c¥ C]‚Wí¡5¤eÐN‡Úh•±á?ÚUð%ÐjøR4—à”ã”uÑ>Ì̳L.s,ß];ÊA¡‚>ŸÀSƒÙ©«j|í_MòXæ=Œ`…ëÌwÁXÇÌ àÎ3ïh\C€+[pw„et‘Wl-Þˆ N²Ä(€ËÖ(öÀÃ` uûhޱ1´Jm§l¦£ΊL´þSÒ~š÷j…ÃÕ3Q/ÐZ€y2ÂáJÒ+ƒ›·ß»†4ž­¦ÛóW¡‚¼[$nz¸Ç×çi/_îØáFÃùôæ¸;ÐÏKãYä¼Ôª‹µ­„¼óDÝ"ÊÓc3eG¬OrÞ9Ê «!Ê;9rWj ð35/­ÿÕjä<5ÏT)L'™·1°«ŠD¿Ê[ëüe7ìŒÎc×¢ÚˆÇétñ1„×ÅôLÏÛhüŒí<#€jØg(û©PkluÝ"HÓ] ôÓt‘ë‹‘SD—÷I¾|^2^·ŒM×-OÎãÍŽiqS”òtQÅ·Kñ¢JE5zÚÁMRkíÒMP}õ~)”‚½”.‹@1ÿ¦Â@> ‘î¾óxSÔvøÒ9(”V7²ºç3¯“‡w>7¤~zÂFRï¦þp·Ì[IDH{¸ck¥Scq"]Æ«x1ûRÞ¢\Lwb$–±û¸°A>ÿßCÃüöû`z¾Foèg}÷–ï£Fyj>LpšªòžòÁYM–W±Íò7Çiº{#qRnâ‹Ô»uS…5¹/r :Iõ<MýH¥åŸ¦ä_ŸC°ZÝëyhº_#†ßÇ‘‘;¢r 9 $G!ónö}ºÉ#¾s-î£Âe]å“àʽôz?§›7øª\Ý)õ›òéj ùòôSRýÛ—ÓööÓÙJY endstream endobj 144 0 obj 1947 endobj 148 0 obj <> stream xœåX[oÕFîóQ„UUª õfïÞíC¥B¤¢j¡‘xh*Ds#"7NR|¿YÛ³>'>!>Z¡Éîx.ß|;³öÛB UHú×ýÞ9žm˜Òjg­-ç)¶ !^T0¢TåavÜZpѨò1h-Œ3¥¨j'¤‘Ö•ï+@u° Á›8Ê»òë”›÷ÐXH(ÇpNÊQà>†à) c¤htzÛžgkC;d¢! ”™lí‚ʆ„Ød鯭_PU¥Pg#ªTÖ2ÕÊ ã%꼋rnV°Ô[HE!׺œd”u Å–Ò5šbëþ>'ͽªMØàiÙ>ƒ|^*±ñ$—»dç´¢úAøþ.ÈŸIþÒY¡ŸÝG9'ùˆ§rD¼ù\¨d…‚"Ç0~FJI4¯ºÔÜö64úð±¢@¿¤Gk—ŒA¡BGy zAœ„†peˆ*–óo*ÂY7NxK‡&a**M«u¿\+#œ‹¡Ý}N>/)Êþ/¥—¤ÄKÔE}E Úû­ÊÒ#@?¯Øàn_\×m £Äàt¯«úß$¦šá(l']Í(÷`Úh`þõ&ðÐz™ ?%¹0^)€0ÜêtÜP1ù±çbÞã@§vÛD‡^æ9P‚1÷élë^‚¹·ªC›1T«’édé´¥!AHÚéÀµšØ2¢eî ýP`Œe97ï "«9QÞÙ”V_¹DE¸IôË Ïû"ÙÌÉ$z‰E&Á}êNµÇV7‹ÇÖ§!èSWš° Ô~Ýè!‡¡ ™Œ‡Ýa¥ch†”>àœÍag:¸ß)B&a>ûoZ¦R½Žöèí!,±¾Ã¥˜»ÇnŠÝµŠq«žRµÜ‡±%¿wdtÛ ^q•d Šä ¤Â'»t:˜ûÉtwŽmÍ0:E€~èÆ²Â¹´íXn¨6|–¡P(9ýž0‘Q6iâu³%ln…ž<çÁ o„îÌQÁ´æôDs«® `i ñeÂðΠ ¦¼yß^¨öBI$ àÆµ -,ÍxðÑ)ßèÁ@dq¨±ímwß0ÜŠŒÃ4U^ɘê%$ªÞà°ö–@#pÓ6ÔñëF¨`uçÜFQ^8Š×’¡ÓŠpq*´&SÀ\ÿ8uЄãx¶¿Ô™Ë¢¼°ë›1Ä}ÿ‰vúˆåˆ|hÈâç" ]ö¨Qýþrùm*±¡mlÁ Ÿ‹(]F»ÆvÔV§UCÏ1 Kâh£°ˆk‰Á ð/ –Þ³”Y^ï,F¶ å?­É¨¨£÷ûCòökW#k;ý7óahnÏCvwäË]¯ Oe_]îW«~qŸƒ: ~'§™íœóöwÅhÛ',ÝOŠw<ÓÛ)äÝ –vYooðu½lù’ŸÈQ³48ˆKleâO§ë*â»&LŽïtXVàÛè©oYkáëá=}òZÄ׌à»ÅÒ!ïf,÷Ù¤'‹»Ã>ºÀóó[÷è[·žé𭨃ÇÛî´™ºVœ‘'a®ƒ½‘çù5&÷›+²]ò#OG/F¤¥V–§O’^òzÌkyJmW¼}í„am­6½ +*ë¤ÿ3Åjqm ¸×둲žóÅ ÞŠW•ÿ·‘Ñ’‡ÑK¯G.6Yï)ïž.Ö<­½¹õ ™S£¸è?fÅ±Ï çí#Úµ ¤]Á»Ãy˜ô”sSÅt¬ “‰wô1ëf:¥¯ìý@̱ ­}<÷é!¯È]‡æK¼.ÐÇvV>hLoüêúLYø~:ÙÌʯ¿‹<›ý ~P Rendstream endobj 149 0 obj 1857 endobj 153 0 obj <> stream xœ½XIoäDælþ„ s°vj_@\‚Ä –æ0Ã!“t’Vº“L–a9ðÛù^•«ìÞBÜ¢Híò«ª·|ß«zÏy_²–—Œþºçñ¢ØÿÍ–g·/ÏŠ÷¥4µ.L5 ޚ²ÁZî½ô%¬uŽ6½<,ö.ïnî§Åþë’û?ÐÏË_¿Åãð»ò“âà°|U0RZð`±ìÇ‹òåV}ÉU+•åä´ˆÞðÒµ¶D)4‡‡“Eñ¦:¨ARaª?ëFµÆ jø¥¸RV‹º‘­gŠ¹êº†·ÂHm«9-ÌUM±€ùV)Si’j朮¾ÂP"B©†Û†Š§3%´R*ÙÖN-‰¡Z˜–[S5´Spë„­^“Óœ1§~Ÿüˆ`9GøðÑó­Æ„#†!üDyX‹êº”j³ÕIÝðj“Õ§ÓZU7ôsI²;¬‘¢e\ÓP»ªº¥ÑE!­ÁìE-MëcúAJ'ÂuuO“«.ÐÄÀë`s–v‘5¡a¹›¸ŠÖ3À;zéªH‘rØm€%aÛ…~¾$Ý*LTqN{ï¸pÁ;ìã nI`ê½Öi-áÎe«µwåä§bòÅ›àTBÄÂÿlMjl›‰î­ ¬asüÁ ¤ð·oÕ9é¥ÙàÆ‡ÌA `ÛŒëeZ{Û1Òù{T O Â켇 WCû`2È.cJÃWµt¤FV7'I9-׆X#‰àš-œ±ˆÓªêïš Þâ ‡”†z’4$jˆŠœì¥a ÏÉndá8áCá…·{áí(Ñmv8IÉúœ䟪Z¼ »ïë â@в¥üêI'Éé5Þÿ¨ÉÑE‘<ÒÔ9•Á §.òšBämp'¥Ü·ƒ g1a¤žéò^RE³ŠœTK—AàÁYº4)#ÛZDRºù&ŸZöK­z^ÈoåúƒÀIH1€|l¦»8`¨ê’­CAõ',({—ÉMÉ.E<-ÀMXsMk‚•½ÀòòMHº¬È™—î‚n ätœòÃÜ^¡kž“ò¯ÚÙH|‡çÁ¤@µkÀr]%å¸ßU¬¤Öà¾t¶]Éô¨#cŠ(ê“~]-¨)½bmÜÕ¹DÝsI£"uNFul¤ºm…^X”uoŒtÃJÏ5Š B€‡ˆ•þŸš·°îDµF˜Sv´ ùdA k-7œù=T^™ì–Ò&”bÛr§„iˆA3¯AWÞÔÏgÆ6DϬÝ1üR¥ÎI²ŠŠž»ª‘t=™'êáH•=RV°À«Ó›x¥ŽÊ1ð‹4·*û9Ñ¡èºø,Ž´oIö.fyö2ˆNj?nóè<D®D›î6à¤1#)Ø 8êÀE®Ñhµ®ÿ%…’q´œ 4ŸšSÆÒ•œ„G°»èTZº_“p–G2Ó|†pÚ´Ò­ÑŽ*^f¨3(ÖiÞë,»Ï²»${mãÁÞF›ÐzÜ}»#mÕ?²6ËTöTÝeát+w=+/²p@ô7mÏÉŸÅèlk_÷¬eàÓfLO×I{-ãÁÜF j«þ?Z4 _’XŒÚk"/=Üó<š. ×=rfÄM3>¢mØ041ÏpE{|×Hjý¡[Où9Ï@Ü.ç,Ãxï·à€OþÓ<œ"N£•ó~çáÏ‘ñmÆá¶y†KÍÒëþsº^§ÿ;âñŽn‰Ø¢{ÚéJ.=]Sç>›ž£!À÷ßpL—/õ »JY‰ï¤¾´liÂÞÔ oØXxN²ðj¹`¬T›½Ç§ÄxØ6uÖÊ=©?OÎì F2#6|0)ÃÆ…õªø^êypendstream endobj 154 0 obj 1395 endobj 158 0 obj <> stream xœ½Xßoã6 Þ³ÿ ? 8{ƒUQ¢~í±[uØ€Ýà{èÒ\Z´i{i{ë€Ãýí#e[vÒ:Wç’´@¢Ð"ùñIÉú˜K¹äÿæ{ºÈŽþrùü>ƒ|ž}̵U^øø¨RN°yEs!rHá=+ŸfG§äËÇYvô.‡ìèWþ8þógú:ý%ÿ.;9Íßf’f=æÍ×t‘OÈkÈ…F«òɇ¬F¹†|©\ „“Eö¾8)+ÅRe‹§²Ba½¥áYI¸ŒÒºX”•A¢ôÅ]Ih•ÕÆןüžM~x_â™l™qDÎù£‰D±ÖÉ$£¼ž@ø¦&@£Àº&œ¥•Sè„ô9¢ÏŽ*Ê©Ãs³`t Rk S†oQg9øÖ"2N¯ksr¤¹¡’UŽ 4X«}¿fÉæà‚Pª®Ù;NJ©i©„‘“R ¤5RTK¤Ö©žŒ ÉRùÓr^R}9° C\#!)K\ñ))q–ΰ’àQõý<°Í¨–{†nK j3àk“[Zî¨SÊmÉ]ŽmÕ2- ž¿·5£¹Äí7Úê@Ø!²´\ûK n¬ÜÜ€ÝØ:+¾k Ñ×=Ñ›¾b •âÎ/ë~xÇˉ±Õ#h9ãS{½I²‡$ûPV†[jPÅ›$¼O£E%åë$ëFÐ>m·ï£´FX” å å$¥/Ø—"¢}ÆJ°ÝÜÖí}JÕE’ué{½dj#(ŠÚÙÃÒûUQªj­U*ú]$¿kë׌¢ m}¸•^¤\ø&@=𔆙ýºH.ÓhžÍ6:W:·^‰€êYúç‰ó¦¬,Ð -@ñ¹ï­é¬kí§ëd£ûÏP'³VŽì‰l5àgÌø´¿=¤ît¹ž•Aj†Ž„m[¡‘6ÚJtÝÚºNG³4zJ;Ù´1H»`•Oë~§‹/It”jäŸõ¦LoɺyÓÕ$^«ðÖ¯ñ=¿7­ß“HµÁ©Þ¼§^:Ö™ùÜ5éyz¾\ ™÷®™ÏÕíãO­ë® {|´ºÓU{]{[½"IǧÖP’ ãΊ[&) õzŽž­ÇN²«”£ƒ[d·1®m–ª[Äó$¼]Ýœ»¬~%Õã ¢É"€jzûà'ûåöÁõx††¸æ—Òœ"¿Â5÷5î›k½®Ç34Ä5½“dŸ:<ÛçvÍ5îƒëñ qMi×’N`û¦Úìƒêñ Q-é ûí:~EöEâæ1æ=¾š3ŠÙ!±ãé Ö}ˆÖìAš}pÙ;¯,IÆN#ë7"dRÁöúu¾ÆG9@—ó;º$ÛL—#ÔüÊézLÔtÇÓY’-;ºäFºôëéå]Ö¼ûÜŽ.„‰wäLWW¡ÿõª¶2ÊXawÇÑøÐ82wÓÙ6_±¡§7ö³­Ü±mŽs<¼—®6Ñà.n6·0£¥U/\w#Gu„·Ùÿ‚Ř²endstream endobj 159 0 obj 1353 endobj 163 0 obj <> stream xœ½XÛnÛFí3Ñ Š!Ûj½÷KÓ¨‹h yHúÊŠmIJÙÎúí=³K.)ÚTLÅ2 HëáîÌ™³³gV|Wr&JNÍ÷bUüíÊã«B”ÇÅ»RYé™fÒIÁl9Ã\‚ % œyO‹ž‡–×ë›eqð¢ÅÁoôñô¯_ðuøkùMñì°|^prZˆ±l¾«òéQC)4SÚÊrþ¦HhDé™A,YJ#€p¾*^VÏê™$«´ÕÇz¦™õÃ×5pia¤RÕªž)¸æ¾º¬VZe\uF“%wVWKLàim+CVý7ÕÏ*d¨tYßñf®¥ÑZ·±×æ\KË„³ÕŒVJá¼tÕ -8÷úŸùïHV¤ŒAÄl8ža™÷†#dyXËê |iÍ8wÕ‡Z!¥ }Ä®,ƪº‚Sà“!NùDà™\Ö3AÀ ZD*‰)'_ÓÒ“<íšžˆ¸¶{²Œ©$Cœã½%«‰ñ_½ªMšzCÇøÂ|G°ÂÓfYrî˜J Ö” Q]ÔÊ([­W5æ¯Cœs„)Fb¡®,ùHQ#žèxŽh^/m2šê¼h]ëB1c‚/çó^)8oèCZß§bê?Ñ86ŬÉDKÃN <ˆjÿO¶±äªoñÕ¸'w’G÷-"9@n\ !^-ñ`/eàE¬“6ƒ3`SUwu5«[â)4í ÎÆÍT‘צþDÜ"“ŒÞ»-ÝÀ‹ëíYœ™J°·=GôA›§U¬õX Ø,z4œ5J鎆~=6VKöl^@g˜ßh˜ÀJ4ÌጕRãøRx£˜œ$_8±\…Ûn…QÒØ:F䉎£GÖ“?M(½JΤdzг1•r¬U¾¯°) á ¯> ,©iW  T²@‚“ ÖÉž”9(Ý ­&u†æ"L‹JๅHâ$ŸB,°‚‡XŒc£]õ>;½À^¦!§ ¤w ‡&`÷3sÏÑEM|á“ˈ=×Â-^©>õNÄ–ºí…Šwû#úÀÎn»ýJ?ÍDgDÖOõ4©b¨GRŸ÷mOþ>n€Ò>u7oú붉z8Oí2í%Tawõ4ÕÊç¼·Ó­ Ú`”d2ÈêI6^åÑ*º29˶n$Ú§m ö}”Ö lyFyŽ‚Dm {WF¸1X.l7· {•ÏË*Ûº3t6„›Ü Y;ûø Ôþ@ÍP©*uÍ6î*Çì_3ŠK¤©ôvTjta 9ärP—RQÛnm'Ðu¶áêhB Ë·Æ›<:Înp§2•fзe9Ö»åÓÆ|’ª>÷5Š8ެAÓ•cLƒŒóÓµ6Ó½¥A]Å&ºÎÂrºY[ÑÖ1?ËŠ€N‡¦[·JªÔ‰H-óèãfmDÛ¢qh]ò/ZÖÿ˦ƒ\Þÿõ.˜Þ†uó›Çtp8Û¸Æ÷âž·qÌ&Ù&'{ó>nVÝ@à±gNÇFn¸•›¼é´wÕ"úi^ý¹Óìîè¬4Ò‰¸l&ÆLíã÷m:JÜô8n×.6ýuj·9ºGáO/×±Â×6L»ûíXø¸pâV3(ü×Ãäa{› ´evrиžÎÐ×£yrËä­æùÐ\ë}p=¡1®¹¢ß¥{ç:Ü2ÃÞ Ûìƒì馾/Þkû2~qNãú$Ss“GÇ=ºš[Šy8^§³1B«â1¤Ù)¦âûi¢uÝ»Xn«°Ñ;;§tþ©ayÄ{—ÔæZûeº¦g9B—ãßÎíF—•LÓÏäH×M¦¦»Ÿ.³mÝÑÅ·Ò¥îO×ô,Gè2A>†@ÁLÈî€~êÚ™‘Æ2ûŽ&”ÔôÔF8Ò^>Œ°mãÔæŽnÛ“œŽí®×œÊ}ÕËÒÌn§“Tß‹+­¦ÉÁóâêäþendstream endobj 164 0 obj 1550 endobj 168 0 obj <> stream xœ=OMOÃ0 åœ_ácrhÛkê\C ‰¡H‡i‰ûúÿ8]7Y²­gû½çJLu=˜ú¥…íÁ lÍ8’xGµ„>B¥»˜'P x‘r4ïLÝ=ÁqÚ˜úÐÔ%ÍŸoµtwpc,M(¤GE˜Êz€yVUDE| !˜³•gUlÙ AÌ›½w”|J$ö×±ø€3¶{WqC¥·½«ÐnÜÌ]Ev媙ý*黤ƒî©ë$±´4îm㨌|>ù<\ÁÁM4?ep*i52±ý»[׌„ÞÑ{~,?µT-FŠãS¨n”Ø 'Üë7Ù¡ÇÈÔ¨®‹"2Šë]£]¨#Ïܶ¤ò—yéŠÌ"›¥Æ?ë `cendstream endobj 169 0 obj 290 endobj 4 0 obj <> /Contents 5 0 R /Trans<< /S /R >> >> endobj 17 0 obj <> /Contents 18 0 R /Trans<< /S /R >> >> endobj 24 0 obj <> /Contents 25 0 R /Trans<< /S /R >> >> endobj 35 0 obj <> /Contents 36 0 R /Trans<< /S /R >> >> endobj 40 0 obj <> /Contents 41 0 R /Trans<< /S /R >> >> endobj 45 0 obj <> /Contents 46 0 R /Trans<< /S /R >> >> endobj 50 0 obj <> /Contents 51 0 R /Trans<< /S /R >> >> endobj 55 0 obj <> /Contents 56 0 R /Trans<< /S /R >> >> endobj 60 0 obj <> /Contents 61 0 R /Trans<< /S /R >> >> endobj 65 0 obj <> /Contents 66 0 R /Trans<< /S /R >> >> endobj 72 0 obj <> /Contents 73 0 R /Trans<< /S /R >> >> endobj 77 0 obj <> /Contents 78 0 R /Trans<< /S /R >> >> endobj 82 0 obj <> /Contents 83 0 R /Trans<< /S /R >> >> endobj 89 0 obj <> /Contents 90 0 R /Trans<< /S /R >> >> endobj 94 0 obj <> /Contents 95 0 R /Trans<< /S /R >> >> endobj 99 0 obj <> /Contents 100 0 R /Trans<< /S /R >> >> endobj 104 0 obj <> /Contents 105 0 R /Trans<< /S /R >> >> endobj 110 0 obj <> /Contents 111 0 R /Trans<< /S /R >> >> endobj 115 0 obj <> /Contents 116 0 R /Trans<< /S /R >> >> endobj 122 0 obj <> /Contents 123 0 R /Trans<< /S /R >> >> endobj 127 0 obj <> /Contents 128 0 R /Trans<< /S /R >> >> endobj 132 0 obj <> /Contents 133 0 R /Trans<< /S /R >> >> endobj 137 0 obj <> /Contents 138 0 R /Trans<< /S /R >> >> endobj 142 0 obj <> /Contents 143 0 R /Trans<< /S /R >> >> endobj 147 0 obj <> /Contents 148 0 R /Trans<< /S /R >> >> endobj 152 0 obj <> /Contents 153 0 R /Trans<< /S /R >> >> endobj 157 0 obj <> /Contents 158 0 R /Trans<< /S /R >> >> endobj 162 0 obj <> /Contents 163 0 R /Trans<< /S /R >> >> endobj 167 0 obj <> /Contents 168 0 R /Trans<< /S /R >> >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 17 0 R 24 0 R 35 0 R 40 0 R 45 0 R 50 0 R 55 0 R 60 0 R 65 0 R 72 0 R 77 0 R 82 0 R 89 0 R 94 0 R 99 0 R 104 0 R 110 0 R 115 0 R 122 0 R 127 0 R 132 0 R 137 0 R 142 0 R 147 0 R 152 0 R 157 0 R 162 0 R 167 0 R ] /Count 29 >> endobj 1 0 obj <> 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 195 0 R >> endobj 7 0 obj <>endobj 15 0 obj <> endobj 16 0 obj <> endobj 22 0 obj <> endobj 23 0 obj <> endobj 33 0 obj <> endobj 34 0 obj <> endobj 38 0 obj <> endobj 39 0 obj <> endobj 43 0 obj <> endobj 44 0 obj <> endobj 48 0 obj <> endobj 49 0 obj <> endobj 53 0 obj <> endobj 54 0 obj <> endobj 58 0 obj <> endobj 59 0 obj <> endobj 63 0 obj <> endobj 64 0 obj <> endobj 70 0 obj <> endobj 71 0 obj <> endobj 75 0 obj <> endobj 76 0 obj <> endobj 80 0 obj <> endobj 81 0 obj <> endobj 87 0 obj <> endobj 88 0 obj <> endobj 92 0 obj <> endobj 93 0 obj <> endobj 97 0 obj <> endobj 98 0 obj <> endobj 102 0 obj <> endobj 103 0 obj <> endobj 108 0 obj <> endobj 109 0 obj <> endobj 113 0 obj <> endobj 114 0 obj <> endobj 120 0 obj <> endobj 121 0 obj <> endobj 125 0 obj <> endobj 126 0 obj <> endobj 130 0 obj <> endobj 131 0 obj <> endobj 135 0 obj <> endobj 136 0 obj <> endobj 140 0 obj <> endobj 141 0 obj <> endobj 145 0 obj <> endobj 146 0 obj <> endobj 150 0 obj <> endobj 151 0 obj <> endobj 155 0 obj <> endobj 156 0 obj <> endobj 160 0 obj <> endobj 161 0 obj <> endobj 165 0 obj <> endobj 166 0 obj <> endobj 172 0 obj <> endobj 173 0 obj <> endobj 68 0 obj <> endobj 107 0 obj <> endobj 31 0 obj <> endobj 185 0 obj <> endobj 29 0 obj <> endobj 186 0 obj <> endobj 27 0 obj <> endobj 187 0 obj <> endobj 188 0 obj <>stream xœ]O1ƒ0ÛóŠü €Z‰Jˆ…. ­ª¶e ‰Búû’:ø$ŸmOtýµ·&rñŽ^ˆ\«f·0ËÊŠ+CqgyÒ$=ÝMú÷ǃ¯èßåñ,ë:¯Ê-DNaö’¤Áš¢h­[«þ¤=0èÝyº´ÕÈþCIÑTâ¸Éi 6榹I*`,~ÏxçSН`_U¾Sª endstream endobj 20 0 obj <> endobj 189 0 obj <> endobj 13 0 obj <> endobj 190 0 obj <> endobj 11 0 obj <> endobj 191 0 obj <> endobj 9 0 obj <> endobj 192 0 obj <> endobj 170 0 obj <> endobj 118 0 obj <> endobj 193 0 obj <> endobj 85 0 obj <> endobj 194 0 obj <> endobj 69 0 obj <> endobj %BeginResource: file (PDF FontFile obj_174) 174 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 32 0 obj <> endobj %BeginResource: file (PDF FontFile obj_175) 175 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 %BeginResource: file (PDF FontFile obj_176) 176 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 28 0 obj <> endobj %BeginResource: file (PDF FontFile obj_177) 177 0 obj <>stream xœ•X xSÕ¶>!åä0*Ê‘V1§2(B£ eh™JhKç9C‡´IÚ4M²’4M𦣀‚@G&[ŠÌŠ2ˆ½ >eRï½àp]§îÞûÞ•wßûî»ý¾¤IÏéÞ{­õ¯ÿÿב0~½‰DÒgî²àà9!‚|_FŠÏHÄ¡½Äg¥@¿Z»r{C)ô÷Û7Ô¿á ÑozðÇ©D’’až›”œ‘­ >&p´iSÆN š8;!25&\‘¸L¡ŒŽLP(é—øÀà¤ð˜HeFàè×¢•ÊäWÇ×h4ã iã’R£fލ‰QF®ŠL‹LUGF.HJT¾¡Hˆ |x¾q?ÌMJHV)#S—%ED¦&2 óÊìĤ¹Éë秦)Uj"}ëÒŒð̈ÈåÛVDEǯŽ[Ÿ°nØ´#gŒÊ=kÌë/š0qÒs 󳜙Ƭ`F0+™éÌH&˜YͬaÖ2ë˜fÊÌe^bÖ3ó˜ Ì|fÄü3YÈ,b3“™—™¥Ì+Ì2æ f*Ó‹yšéÍÈ9Ã1:¦Èôe†1™Ç™AÌÌ“Ì`FÃL¡éfü%sA²Dâ’ü½W|¯ÓÒ¤J¿~™~÷Ù{;œ­‘Éd3eǸq\.w·Ïú>{ûò}cûMíçé÷UCÿL7 yàôw[ñXçãŃƒê]bêî'_x2ð¨ÁKçþ+?ƒ?ñTèSçDóÀ®¨Á§®‹‹ª%bb—Àk%‚¸I¬A»…Dußó7å€L\ò(“7±U°Êö·¢Ôßb^ôF»4G à[¶ê`7• ÝŒ8’/?\Úânâl¬3 ,nåÒàOØâ¨ûwJÞáø•Šf¼Êÿvàùç6ÏJΑ[²{[å1l”N¿Mèö“E•èšåûÙOi£€)²g;âQ†ÈÉ.Yœ+ëÀÃK÷éV-Ù×5F*ÎýxÜŠMÅ^› \u*È–¿ÎfB&hÕdYîOžÁe™u9 †€©l¶Tù`ñèL"ÍDO®æê¬V0(kiÄŸ²û °È[…/c®?N'ÆrU¼ _²¥uPë2¹ œÂ@±]ouJöаâ|a•£ŠÇ©Ó¯“)dú̉äe2åúœ€ntâT9) yÂÀן_[¿ “f¼A4ˆ`Ã]Ñ{OrGK»ãpÞm,,HK\ d˜œÌ E_À1'诩·Ú£UõB‘ÉQà‚Bp:m…Õ´"¶BkažcEíe3€#f2ˆô#¹Ä‚O ®÷¾}Yp;-.Ž‚¬­ÁW:ñË«t»¡¸ŠžC[ù·COBp ¸úhàJ²hÅÚ´˜(¡9Û#ßö .Ç©‹hó+ñì«;Ü6Ò7,È`Ò[™á.Ö i•à„*n`×døYÔýErV<&ÿ,þÄ{JÁµ\½µn£¼{1«ÈÏŒ[_ûoÜpÀ ¡‘%ÿèv|¸Óäõì%†õlV,;¢„˜ID°XÆËvñ@Óö.þEò Ž’b.žã±‚ÝSéÚßœã‰H.ë`¯Âgæ«À5ÖÁÁ-»±îgÄrûÁúc{Ö/ó­».Äëä©0ša¥Éâh—Ü»C ŵ˜ÉÃÏZ?(¬²Ùvrí²jpe$Í1f£Üz¾Áq"¸ùLÅi(_,iþ ƒþ*q§3*›¢‹îÕžp7´rö¹[/6¥ªvÊ=;­¯ìŶB»ÛsŠf³bm™¾0¼$ΖÜfò4áëkêӄƸVãiýnÓ;¹ÆmŒ0F„—žÚ(79ÍŽ|0€%ךoÉÖ­¢3>QÚ¬'3@%pïà…8šl4=Xg'J«%7ñ))&ŠOñ·Xo45EN˜øeOXñ=aMUÊôÛ *ª ¼B5)bG6m¹T|*ŽÉ+gªh{8,®üSµ¥(L`µæçëó’U àÒ´•èfgôgEÿê?°€8Ž¿¿~8iÈ¡U3ÈE¯šœ_v\Žm²—îoMšeg~ªÿ®µËSzHà·ìš)»¼\-Ù)KÅhq<ï,£(sp»RA+W³ Ðks“F““þ£ñ¤±ÆX»ÒXm*$™Áâ̰_wï2Ũ‚€Ë=Ó±ÉßР/Ù œ†M§lcNú[÷`ÿÒM;ap»Øvp——ì¯û²‰á˜Íæ_´ê0™Xº±$Ê™~¸ÙCàñz(þjõx綾§pº/_x‰Ç‰d¬-tchAÒB¹:×d=‹VÚòlùN“‹âÄA½}´ö}àNTÄ®¢eѤÜBFÍ?5ûfçžKí‚æ‘ì‘¡ãdz"¹©å/(¸vÙä¿%t»¸VŠ'ÐÀãó¸ÀãõQN@­†&u ›:ÈÖšL‹'g*_FÆ?³FoSÆæ¨@e¤ü”'à‹d!™HÖå L òÑê!J«vGí¾ë8Øÿ2¢Lã…8Ì–Õ@­» ÐX|%”TQQý;C­ízº(™èÎC&ª„·ÀÖÚúTPúŠñÑ×ÀUdÅ´ÐM†\Á—zߪkîŒ}6Œ%~ŠÔezºÍ¸'~Tý€>îñâÁ¼…<ºÞ}È?uÖ›|©!ŠkâÉjI“¸èØ|”æäê“!G®b³@Z¥Ùô*I1-䬬©cë·[¾OúÀX \ › )£Ý$àÊîÉyj³ÞlÐÅfn^± ,Ó»L‹Í œ)ϬË+Zà(Šu',€Cöuo§ ÐÒŽ¥ìÝìĦ£<”´YJ9‡Åc(°€Á ÏÔnÜ: ¸ápïÜί~8_Ÿ•Ð$xõÿD(ÅÆÂL÷†ÚÏ|*cÆÍ'sÉ«×_Çëß³5\v•S õÐí’á2ž¿,Ù#Ž“Š3Å'(ƒÛ)qã!SN:ØœhˆÜ¶ê÷~a‡½B3Kåç}CŽÅY´¥*åx‘-m„æ–xH ]kPaûÇ Ó(p ¥W±à÷ ÷PF¶ùP¨+žž- Èêõ›€¬ÁõyÛ ÛÊ Eˆ ½ÂSÏMÔ¤f)-:àFÂíO?…ïÐow½A]Kë즛½t‡údšÇ”JŹË×í°½üòëd ™üÚ2–L½3'´œvî» Ô–¸à—y·Õ]°ÇjË…ªIzÊåÆ8 ½AwË|޳çg«?½ŸCùJÇ ÊªÏÅ+>a% °êJÆ;ÖaÉUœ„ 9¹Išy²0ò››º¸WY5a"(²Bˆ·hJ:qn§äºOƒ’(;ùCPÂî„ýç÷Vç¦WË]y‹¸RðTm2ØnµÅ¸‹Ô”›¸×IÿLò‚0]¦Ž¦ìݵùæQêZE¥>ò뾆ÀJ|šZÃãX'|wGà‹cΓqq<Úï<°hýÅÓ<)]>¡~ yZ ±ŒÖ¹líÄ>(iëÄå’C8?Hqãm> ²!Û[P˜Y;Áe³ÛŠÚSÞ¥LÀÄI€ÓΨsK„Jh„úB‹ËâÎí,rš¶[Å·Õ–Z:¯q…3¸‰d¼š,Ÿ×¼éMðκvÃÕŒS9µ¦ZÇP£†HͱSæ4¼*×y-´?òÁd6kµ“ý-y´WÌ þ)Êi¹¨>aÙIyù…ï.âxô›úÕ¨ºÏ.¾‡½$ØæãÞ6ñ+¾»é8‰M²Ã€~æÃT-·ÿÁ»ï 9O¶a;ì¢\\ßcþ/a)^À<ŽÃáÞ# FCÍÿJ*Sé T“äiü¾gõ£Å©êÙò'Yû!|ŠÌ¬TÑ®‡€#lY-ÔÚÁe(¥.T]¹/ø-{×ä‡dõÀ·tO‘I\L.þÝåâÔG•d²ŒDá«[ñIdqN&ÈïWÛwðcùhÛo­ù‹wïƒnFÏKÚÕþxóVÇ.Š’g}ÿŠCA#UÀæØx¥&ΨåþåHõõÙ–Ž#%êµ>(þ?/ üµ®çÜ¿šè™ ˨¢Ø¸ÝÉ4Ñj:8&.lX·Ü?;$767Ì'}õ`O»IqŒ¿¾UãLn«¾Û$ò…êhýƼ8KV€•Í;–v3óƒ—ñ²¿ŽÎ¡éÀŰÙÉh…‚BêΦvß+QìòÙ„ l ìoÛÏâ3þå'\»q^O¸¨äõÝØS èžjG÷$¥ñaõ«¾Ãáøí-Iâ<&ÅÿÂ3¼5×–nÞbz#c$éEé*ѼÃTd¶S+“)/=.[ ù\Þ±µÁzÀ_ÿbÅ"¢Y¶H¿d\±Ú 3a©}Õ¡Uû×µiÏÁ'Ðønéî… ~:tþõÏÐùÍ¥Š™Ïeñ¢ïÁ5»îŠEwwù0ŽßIߤxN¼ËŸ56&ïЙ|Í]BÕß^ê9íosØ\ÔW,Ýe‘o«Tim\14GEÁ6ƒ|q~¸:166R `اSÌ ,[î©o2; èñ™)Œ6ëö¬½êSIWŒœ¶5Qi*‘ããåǯ>(›u}d57·’ßVšZ­ÐZõÖáb®“|Æ7k·ÇÀX§I4RåüXuWü SBgeŸ@VÚå¹Ì¿ ž³ÕjΗoHWXs¨±ŠwDÖ ?öëÀùàOž=ß®w¬®0ÒƒXMùêp2xþ´ ‘†âIß(>å°ßµ³gá"÷å‚ÏG7›ô›µcNe„<)}ÅÖ¬ì,mÌVXɽD ¹¯Û åG’Ï$}çáh¥Ã^ì ©šëŽ£†'õ’å0÷>y{{}KÅÚˆ¥kB6ÇË“gùsO¯lŽ V®µæ·¤à?Ë>l©)uцýþÛ¯päW’³])Ò®tüï=nƒðwkØ Å!(ºX’É{Ý¿¢þÞ›Õ)î_ñP18#nª¹†C$7| M/ñwd;­¶ùL6ÅjMfÊRlÖ}ò„éV³% r#‹ô9“Ì dÀ‰ÓÉ‹5év_'V±%Pê»®TXzeµ€í_"wòB¡ÓN)Wª‡,Jä=:™"`ñú6è@?|ª±~wÍÎ8ËÑq"B”‹ r¾<ǘ™ ¹`³SWµÞ¿Pg7S1³Û®ÖööÊà.¸Uë6äæªU¨çá9ˆ¡ãŠÆf.Ì+òM¿l½Í¶S }É\þ½Ü(ûcŸÿ1*è‰nÒˆ³ôC‡FoŽðþÌÈc@j´M%Üê…ùFš —SBKQE§H;TU`ÿ{Wpøª HÅH2_T¿iñ=h£¨ï<݉éíØþç±?.£=+þxÏ¢  b²B5ó`",ÞÝ õ$`oøÜûaëÉ3Ÿÿ쨇vhÑT†Å»”4.޼´bJFœ… æ~‚¡18ŒÄy’i$fBX̪; ou åçöCYOêɲ[ü8À¾­-€ýn ¤oD$~ãið½pM§Ä‹mRôàþ7ÓIBY]Ôƒg>‡×“¡³â,©¨îšÍ•ƒ \\mFuZ¢!5×,'_ÿ# _ ¾kª*ÍöݞŹ4;Åo|žp(.ÅáRÑßóø, žd-"g¤cjÕ(ȉ–´ñ³AÛ\o<ßÁxÎu8ê=7ÿDÙÑ;Å¡q…Àk°VÁ ãjsŠ>èu߯vèKßí ELÄg¥ˆ]A”Xv‡i ,:<#+rÛh —‘bLŒj„Ò·îÝBwé YŽÏ(Ó¿ØÂ–4ÓзÑ&ï³´ð åY þ‚Òó×xeCÈä<¬Âï{pä•Ñ&zSM'¬8Zm¤YU´J¯°”»•—¶ì)/ 8yâäq¸ÅáÀIÈQÑ«L乯MQ .ñ/Êó=à+»Ëá­¾ÔpðpW÷Î{cIäÂåKNõeŒ»%A‘:¨ïÅc¼[Gû\`/tºÞ¹ü1”w®8v}6lˆÒ’R- ½5ò…ÑLZ—á£òÃì7%«f.4. Š›íú`¡[lµô0¼¬º¥`âr®¿ŠCðõocÀ×ÎN¨“q¸þ<µ’8™ /¥4¸pL^~QžÍJkzòm5ãÛ>æzíßd.lýáßc:U­¸¹“jY²Õ+û®/í'ïë7¥ºZÒ€­ÿ@†ùoI1© endstream endobj 21 0 obj <> endobj %BeginResource: file (PDF FontFile obj_178) 178 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 14 0 obj <> endobj %BeginResource: file (PDF FontFile obj_179) 179 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 12 0 obj <> endobj %BeginResource: file (PDF FontFile obj_180) 180 0 obj <>stream xœ—yX×Ò‡{¦§EAÓ 1wÀDPd]A”]‘EPAàŠatØ‚¢¨Ü5QÙ‘E!Ä 5Ä-&ÑêÉ{ï0~Éýî÷ax˜~š®ªó«ª·ªy”Ò(ŠÇã Íí]]õt_¿ä&ó¸/Fqÿà#œ%-ß%@*|¤¢tâ‹ ²ñÜjP4Ö¨R|/,zyXxldð† (M¿šz‹ÌÒÔ×Õ]¤¹,4 2ØÏg³¦½OTP@¨O¹Ø¤éæ«©cn4wnLLÌŸÐ-sÂ"7,™1K3&8*HÓ%`K@äÖM«°ÍQš>¡š#ÑÍùc©iæ¹™¢(Óe›ÍÂÌÃ-",#­¶D-¶Ùãc·ÍwE¬Ÿýv‡Ç@§ A.Á®+CVm u74ÑöÔ™1SeÖØÙsæêêéÏ›ºp EM¥©i”¥E9SÓ)êKʕҦVR«¨”5“r§VSfÔ,j eNͦÖRÔʃ²¤æRV”.eMéQË)jeKͧP+¨…”=å@R”˜b¨`j4¥L¡B©±ÔfJD£T)5j<5úŒŠ¡&ñ”©e$ ”y|'ÕÃ›Ê å]Åå>êëQ—FýÄ_Íÿšÿÿ’PÉH©\@ ‚k‚Ç´Ew•…ÞÂáÆšÙÍÔŽ}lô{å‰ÊHù²òÏc´ÆÉ#WÙ R¥Ò¨ò~좱;Eê¢`ÑÑÑÑoãf;2îUÕÕ»j.j—¸T‘|*»zN_Ê;Â}àscå¶ì<Ù îÓ?€·ÎÓ]Ø[ð‚Æ.PÀâ ºlJšŽ=:P£‘Agƈ,³aD\*áFËx½Ý°¶›ÏYÃ÷ìϱHo­õîdq»ù [7¤ ïTôu½Ì°ãóÝB…çz¨”ªç½êƒw½üWÄõ- Aë÷g¯ŸÌoŸR,y^ÖÙˆº˜šðT1žƒëY@0^ü§n6ŽÖX,Á ~ÊB%L¾í°Øtž3¦$".5ñ6¼•ñªºá‰'ÂYø\ûƒÇÍÄ£ð$¬þNFƒÊÛ_`¢‡ãŬ•y=Œ…±]WšÛ:ܱ2V¶vZ&É'$6soóî<ãs=@³NþÁ[uƒµô`&hÁ} ³Û/lª“>ð.YR`‡4°=žŠuq Ö‡1x%ø¿8]TÛLB*Àn%°P·yº!¥›ó/²Ç6Ÿ»˜WO_ಔ¾rtÞêï%¹b:4¾[È•+•Ÿü¶ìbºn,«eaiê.­Œ‘$D™è#’¢z®§ž÷ò17å1ÿåˆ~EBXBŒÍgpÓa6•`‹¡ñ,9Àl!hþ†Çb ¼dbÍ¿Guj8*Ίó`M­é¤‚µu&ˆÑ^ ƒ'ã ÷¦¾¬¿Vvú¬§v Má ‹bQZÒοÀí³Ô±û§wwïµ³ð#6PäË ñ.o ŸÏåÂV†û ÄÂ|”Ÿž°kt²æ¼Ûñx:%¤'M ŸÁ)$R‹:ùDÚ,zÛÑñ:“iꧯ\»É‹yn9èÖ)qwHÕ^’AÖˆ‹X¸K\ÔÁ>˜ôÉ…Eó Åu?Ü¥EÜ„Ä[ðk¯ºìÛùð’[ƺ—û~½1‘x “Ö ©Ø&9]º·.ñÔžÆäÆX£F®5ù±âëãqua½HãªCçŽ+/®EçP]à‰´,ÿ“áÙkrVæyå¢+ÌÍTpüÚÞెHõ=nü åýÚÁsn" Sñ˜`…'Ìw~ˆ¥´c¡ekÛ÷⸦ˆ­! !H#0¾ê)¸Õä`7epJJгÉIVõq=€zý!Û~èƒÜ×OUXÇ©J?µçÄšàs´©kÅžoΉᡠ~*4/óè»Ö^tîŠØƒÈU¨D>Eašv »Ä ±äC4×–ò 9 >çBì˜ÒÆØëÊMF»=5ÒéäS­I•3!_Ý„ÓA'ÁSZ$_úñùT¾\— \«”÷1­x"nOóJbHV[ƒÃÞœU ¦nLƒÛ S¦˜5{wiD8oGñ(…ì Í϶U/M9’ZŠN¢šü3ïæHa¿R‚ÏÍá²N'‚sHëJŒT”±ês̵ëu…5×%É-«ýVůF†®¯»k^¾¿zb÷†:¢ö¿FÔ~ÛÍ$V*Ø ]O¬šèI‚J)I¨ÙqëqúêÁOX@„‘StvH-æ}c :ƒê÷h’Š_Ž?È©8 ÕÈ=ZÙ±¿,#]}ˆê–Ûbš€Á Ý„®&2Ë”ùœ7ƒýÿá2ºi,ů¾œòM¬-üHž…K ¡`Z'¡ "1øívÞ5/1:&Ó0‹'ý0ýçꦜëõ÷nRTŧdžlŽŠ‰Ü{³K  êÏ4]¨Š )iæáÊêLrNLbUÅ™øôaß³ ³IImWU¹­É?ÞvÆçQrÞ°Ì20©ƒñ2ÞÉN@ |NÂXt"½Óÿ†ïM‡¸`.QÑÍÜûÛ¼ú~ιŸ/_ ¯YÄÓa6ÂKÈÈ2Àþ8tð\0€Å¤jõ PŒoã:+O5XIª|ð@ ˜X€­±;¦°Ó4’~à5‚§Œ÷ Á¶…‚w£±ÆÐ÷[|#­LÛqBÜ"LÈÚô5Qr¶¹…¶Do™óýÁ‰„Hòñ„w%p^1Ä £—¿“þÕ÷ÏAéƒÎÏŠùž© ÞYÄðŽØ½ë°Ðx… JOϓĥbßø²ãF5ðn¶u›´á&³¥èȾrt}›š‰o©["çm¡;·ôCÌ3sÝÀ‚ ÒÉf_äRPDÎæâ­î›¼PcúÆD0îMÓ Á‹‘¿x½sº–·¯è@ޤdGu| bžµÝï¿]“xP‚'`_6н¬¯ïjY͹Ka&&žaÞ’ Ø™-²Zoµq‘‘űKY¨¹[ò瞤¨³ÞNðúëªdï±É7D ·4øÿ»’‘éŠ †eêéåsÐÃþZÕÒŽz™7˜÷Oãä!ÛÇÐú ú´ úéAkNÄ@i ¹ãdaaç„•I¶v Ó ´ûI|0³úúýô¬Í¸wI¯F·roïðê{àtŸ ÏaWV¯,6Sôùü:Þ…>µ>’³ëÎ'4Å?Úš›z$Rº½t#òflVÚèúê嶈w=]ùcü-¤ê/~QÍ›.G—K<¿Û˜3·Ì¹0n_è7{²ÃŽ¢óLÓõ/^Þ¸©F,’“¨Þ´óà y¬\‰í§ÿäŸ7þn ŸÓ[øÙ’bfíi­‡dÀž€ ŒÁT GãõØ_À­3²m…)Âû@G‹äæÑõòφgê#"ú3Ò‰&ƒ¾4V7°1X´èLs¾úƒ>Bü%Œ& ›L, Õ>]<,—‘B+ÝXä'?í»Š_îEòØ÷ ut[(Žè²ÌAæÈÓ7|Óñqÿ½[Ù{ÿ§ý¶ŠœþÇ¥Pô‡Åˆ£Â?´ù, žÌi]Ü¡ïS£e$_µm3`@݈ÖÃÍÑKÖ`óWÅ´­ ½»Ú«ÁIÁÖ“å½—~ oKîƒÙWÉ¢¾/´|Vå,NW¢èšhœ–AB#ïl/d“®»G8ÜôÄtXØK:[i‘á\·6ý›Åæ‘¶+Ð|ó^Ì!Œéùþ¹¥ly™Ø²Š]ây¥µõÊåû=ÜmÍW{™Kð%+çË¿wœ¾ÞØê§5Ó~Áà!˜X ókyõòÙ|¹9ô±#©tŠ— ¾¤ã·¡˜˜Ãè „û{²…#wvHè#w IÍVqÛK~ë#ï |XÎqìCà a$VœQœ…ÛÞ÷»”Î}À'÷+ˆt¾´/XÔ×)„0Pû뵈SÇY%¸Jy=Éåò]lHèr/<ÎOsÏd†phaËëíqOAªÏ‚Ñg@ù 0 7ª«™ÿ³qÄÈhœÅ¯j‘]„qµ¼G÷È#X 4<Î3ôe˜€Yb¹¦âѾXÙ3.Ž7#©Ð4¼G@H+Ÿ›Í=d‹rr÷£ÃLyL~|âÞÔ¤xñWË3«²¢ Êè¯â¶%EFfd†Šg´îÈÛC ¥“°%aÿ®œdÉ”ê¸Þõ˜ç¤·+)mc¶H óöeåŠ_¶¤…& HðÒÝùE‡s+*’¦U‰²+Þ¹/5iJóËóSrveKöìßXdtžDV=tã>tXG¦¡—ÜŽ54ì£÷bãJà*å•1yg¢oŸ:XQRº'±X|W˜œ™³1Ëœ,µ%ºRª°Ú§üeü=}Õ _#óã/–¥¥É‰‡Èüøo–¡êSKÂcXÕÈ˃C|8 «ØF|Èyxáýèµo8~żÉ\=7‰ÏÙÊ=Ùý( e2y»rã÷&%¥ŠñÀ?ÍRv¢T”¦‘˜³+¯p_nn–x¸e¸NïìÏÃ/I^¿¨gïO>½¾Vå«‘² ÷Õßh–bˆ#ã}fUfµ_u…7Z¸uæxkUsîôÁ~¸–uG¾§c:âÒ¯£nt Ý(®Ë>\ñ —\|³ô@ìaW´Ù#´"vE„®[\R jäö4^$•ÞÇ«r#6†vr0LõHcœ…Õ—3¿+a‹±š3(—f¡u(ymñÝ삦  ªÃÿµšÿÇmªþ‡> endobj %BeginResource: file (PDF FontFile obj_181) 181 0 obj <>stream xœmV TW­¢ º@l·”Á%]mÆE”M@e ›´ÈÖVAEä+Š¢@pCEÑ1Q´i@\H» ‘hÔ¨Q3óªóqf~£qr2sºÎéªîzÿ¿{ß»÷}šÒ×£hš–Ø-ñô4Ÿ¦»+Ž Å‘zâ ÂÛ´·´™ȘAÆú'F¿ ÷Á¦à7bhZ™˜e§ŒM‰[½*>t‚Ü|Ö,«IòiS§Î’/ˆ‹[#_œœ@¢äžÊÐÕa )òñsÂb­§LINN6 ŽŽ7SÆ­š7a’k‹ýSý£6)†å±ÙÕÉiµS`·É\fõºAG¢'; …ˆ4°bñ`l‰?KK\p$vÃ)Y+|‰] ¾guD«á•bum™¤…'i]øï]4çØó ë«÷â]'pÊ,fÑ&¿%ÂVW¾äðÉ# ˆk¾€ᡳ‚\?tq|YN *&]쉃Tb{)ý±ØhöͱãHš–ÉÆR{°3™Ã‚k¯{øÔD¿´lRùt™UXàbRw<ëª@õ¨ôÈb IýÜBWòÆÅ(|×x"n¦w׫‡gž¾i?¼6¦V(ló8±ÓhU6K1‹?{ö%7\)<Ó( üܪ¼mÜŸ±Vk ³‹gë°âsl@OQâ&̓‡b¾kô‹SW . ¾ºˆ8W»zÃQ>–Q.èSƒÝe0VÓÇ¿ƒ¬&Fœ‰<ªÍi޼Òé°3†“2ÿYÒäåhàÎ7îÕ%³-· mÍÛ²¹ms÷sÏŠFósçæw\Áe¾¸½þRªBéÅ£8)|KŠJ«`…š~M½€èç7¦Á˜í¸Zx¼ºj}v¡ìº$kkÄNI}¡­©`nëq»w(‘‚V•A™ ê®ÐO¿‡ö{ <†³D}/^ÿúÎô%)àÜ÷.=p–…/à Uóç¸:aVÀÔ‘¦HÇÁ0þVs#„5ÑÍ`×YrƒŸDÐÖÍ[6—m-Ï?…òÑT¹y}³É´0Ï92âpèödÄÍp°¾jODy´¹)Å#EQÜžu¾AHÉÙ¾p)H_6i@Ž-QˆÌ’MB—Ê·ìŠ3ާžA\ÏÍ›OO®;•tH … åjž\)©ª«‹¶™æ™%œÅî|9è!ÇLj¹sªòQ›Føc¦èªû×±â°2:^-º¶þŸ¹©}Ú =}Æ9M;›·°èa7á ü‚^÷.ÂÆ™¤vñm}ùœ¸ÃˆþZ3>¤ÜïÐ4RÝá3&޳¯ Øž-4øÈ¼¶öQRQαˆâ”}‘(œs\ºÈÂvî‘Ëî²4ë§n3ÏëLóék`®E]H¬»ŠÇ$–­+Š­Dç¸æÆ¦ÇÎEDž”IE%*ÓŽ"¢¼Í@%äa&ØLa±70}l߻܀ÑÍ=˜„ã #3Kº¢RJfÜ!Èo“¾¶é añp«Å³çX·À™bÑ,Áã@"‡¡äà cd}èûöéú¤|Y»ïÓ|öÕ]Œv á²3å{lh¹Â=1M–ÒêUâƒf¡ e©I\çÇy}ýà½Û϶/VèxýË£Dú»é‡Š~—2¿$;Ù²Sqw(¿Î?Í#g•ΠÏ&ö¤ª±‘hkbÉZàÖ¬x7“åBþÉ9÷*§8f˜XÁU—ù¾w!>ö<¯|R_\¶…Ey;|ë± Ð½rïBê†ênúE7ö㬭»Yk\Í[ww“I1o+ûÝ‹ &~÷µ6“'Ã}xDØ aûZì c0ϩٕ']Aì“ ÏÑSþ £Û[¸ÿ†C‰gñ6Lax "°B`¾x ðœ{zUóÜjlphÚn34á _âÑNKH|éaÏë&Â?âCžÚE}æâyšW覥D… Aʪ•*/߸¡HÖ!IÞ™µ5 q –Ú› Sþû ö9…nÁ>³øsxiYöúbâÿ/*>Õî·ŠÞ{¨o^…÷zè^«&£%ÑÝñêÞt7I¿ÈíîËœ¼…TbfÓ9ÂJÔ]êµ3ù5ìÚµþ+0µ™KÏËKB%Íèü¾²]\ï>,õ€ïTXª[uˆµ-4ôÞgZùÅâˆì(ùx¬‘³=Ö¦êjkmAÏ8`æý‚M0åeo+;Š6ïʨüíTC±Œ+N>INÎÄÒ“ÔP£†Œ«4ü«‡y"îâ+¯5×¶#î› 1.N^ÞBvÞâì yœÛMÉ?*§{Y/wµ[4çØ­a½{Û´ÇkˆN ¿xwÇ·Ãòˆp£æt;ºÎõX·™Î¶t“éR.ƒ‰jݼ…:R<æó¯Ô¦âlsoémà…xþ= .‚4þÈ7§¯½_x   S\o`’ß}5Ìn¡ïÝ„ LÅyØÝ‚»{õÛØÊ«uºÃaý¥`ܶ õðr>Ú)Dx_ŸüSö!’™Ñ«×0Yý<6T‘§¤Ie¢û>ð-+)cqð‰ÚHÓOf¤oUjlx¹ÀØX³Û¸?EýiK[œ endstream endobj 171 0 obj <> endobj %BeginResource: file (PDF FontFile obj_182) 182 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 119 0 obj <> endobj %BeginResource: file (PDF FontFile obj_183) 183 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 86 0 obj <> endobj %BeginResource: file (PDF FontFile obj_184) 184 0 obj <>stream xœ¥Y TS×Ö¾1psUÛ«PÛ{±UŸs­CµÎJAœ°¨Ìƒ  !@ œ„1ÌCȬˆ¢ÎÔ«qµÚÚÖ¡­Ãë³vµçö?¼Õÿ¤Ïö­õ¯…Åòrï=ûœ½¿ïÛߎ<®ÁãñÈen›6ͳük7ŠÇ½Û{¯A1œéw{àÀvuï2ŽÃ¹±Ã`ɸy(Áçñ£”Ë„¢ØÈàÀ ±óxß ÎÓçÍ›;ÙyÆ´i󜗄ùGûz‡;»y‹ƒüÃ¼Åø"Ôy£Ð7Ø_ë<~aX,šÿá‡R©tªwXÔTadࢠ“¥Áâ ç þQþ‘Ñþ~Î+…ábçµÞaþÎÝ››Úý{™0L$ûG:» ýü#à ‚X¾$\¸u™hÛòȨUâÕ’5ÑRï×X_7?÷€ÀõAÁ7…„†}6ú£÷?˜?fÁÂqÿcÑø 'Mž2uׇӦËgÌTÌš=‡ Þ'܉uÄ|b ±žX@Œ%6›ˆñ„1ØLL$>#¶K‰­Ä2b ±XNL%V+‰iÄ*b51ƒXC¸³ˆÙ„+áF¬%>"úNŸ°#FöÄ»Ä{„€`Š`‰þÄb á@ "CˆOˆ¡Ä0b8±ƒx‹x›ØEÐÄb$±×¿Oü“7WÑo`¿ø~÷ùSùÀ޵+·ûÃ^cÿœœEf ÞRïQ êJQÿKÂÜ8} aàÿ8´yyð˜Áæ!ã‡4y9T?lÒ°¤a? _>½5û­ÇoÏy[C¯¡Óè+#FŽ8;ÒsdÍÈGŽ”ãGWGµãu§ÑN«½³òªQFiFýΕæÊù©™fäÕpA|xƒ{@«ë’ Á€J"ƒA’JŠt•:Æ’rÙ]ŠYÈ#‹ªAÃ^ bMOíáTÒ4Å>Hv‡Tƒ¢¾»@ÆÆ’ÈΤÑ0² ö©)©çnש©îÀð¼™÷´®ëäsKa+ýÓ¶Öyž;âvû35i%>Ìb2^ˆcZV=‚ÚwY¯à²°Ç9» .!ÿy§ñøñ¨u Š ćã§j,OM´yŠÄñ’ÍðŠ™÷y',Ãñ‚a( ‡Nù Ù#û)ãÑP4ôÙDhíž½€C䋦ÑKÝo=y|é‹k×/ºÍ˜î¾t)Û½eNbæA ^`-×BÉÂZAˆ#Œ&åÂî™Øp7w4TåKiIU³;~2U½ =OõmÏHÂÐçöhU”@ñ:yƒ­É‹‚«,›N4sÀÌkî„Gïð¹î.]ªC$š„`#.ÛY½Phâ£wÑj´öCïAGhÿøÛgûD )9 DhYô¾6PÓçýÇÀ ß¾ú®ü%ZÆfDî9€je–£¡H3œüº"ºN> B‘´Mš=Éú°ƒ±Gù/žÁápàì—ÈÎÓ;.<ˆÝ¯È ÿSµºŒ¶ÕÀÅÒçÏ¿píüªY3\V/]î÷Õ)¦/™° §3€k¦s‹@È¥šÄ@Ê d°RÄ.Äq“e“L;t§+2I4 É) ø’ÜkÈÙÇ>”Š€ Ža–¢Aßê÷;an'ÿ<iyÏ~ŠYS—$šì»‚¾$ùކ³à¬Ùp"rb‘]W ÍI¾@òzç–Zœ{ªÛqõ'â䈡+ýòÊw`ÒjÔ€ª0•Ô”%´~´Á5Êc;[/Ø«23ÈÎè>j_`¶Ô Ä·¢ó¦æšùÜntw¡ÅÉ êTÆ¿lˆÃ…^&Ÿ&ÜÜ•¯b÷E×$¿’U¥ÜS€­ThxФµ¾¦óRFmLÉ §AÊNȨ¡¨0»&‡9tqåæWþpðxh}Të»'2sJ‘wÖš<ÐDU5Ô|ÿ}z°DÇè…Õ¶˜Hì†ÄA3¯©–à"y@ºËÈÁª ͤjaÐÒÕ€Z¼øø8áî«;ímÛå±z¹>voï‚tŸI#*0x*7á39ŒA£Ðäö r„Ï5×—”°¹‰ÕÝïÉÊyó+#Nêìλ„ëGÙVb£™_‘½•—2 >ÈD½TúÉÉnÝøîZGgcH”Iµ!iŒv»¯KÛÐ^Ù[P‘n1ó¾é„~ø|®˜Ó•V ¢Ád5+Ñä·üùnßù+»$Q6 ù'‹ E‘Mròõûts¢»±ó'õ ç.J^jëX.xó~9åJÄÝÆæÌº&#ÌJuç?ÔÏ*]ð>&$lØb•%HtIasÝbóѽ]|eæUr">÷ ®F-YÔgd€õ½*r 2fû*›÷X PKbµz˜IlNe`ÈßOõ-^Ì%ò9O¼xM%[wY—>Aî@‡íÓÈ”jÙUütJq)rÙúÄ…gJ$•Fn…‡íOØÔSœJPÞCßeû—c:8µ€ôÜ’ŽŠ¯tF]!nLé·,I‰{ºâÎ_9È>@õgºù3ïtg·ê/‚ûé/Ý¿DÎ;ÆOÂËc+‹ë³Ž15é¥À¨{m»×²h9z‚ Ôâkn/òíLep;À$è=ŒL ²cØ%×h ѾÒÀ¸ Pë|ö6¹ÕÙHÍaICcßlƒ»¯³‡]=uåö•}IhËHhÆ hº½¯ öö¬#áì=H}(ûˆ¨ÿ¸g‰áÛ‹ËKfد¯!,ä.¿ Í.@J{ÚÈümƒ@oÙý}øµ*ðê«1(?·ÁÒ<ëYöwI­WœCäÿ€%¿?*†Y‰ÉGR3·ÇÌkéìAf ¨™ú}a6(§°dÅ1ˆ$ãðÎYñE)l¦ãlC…³ƒ“¥6êZ驈ëu,ˆÌÒdfç" '7Öò® #0&_iHÅïÖbŒÀ÷Ð/Ž:mFHiâ…òp‰oxb¤6»ÌQÛ™ (alŒÈ·ÞëÔõö/¾«eûDþF' ý·<È£MrƒD$JF-ó^¨9+¯=6_¹Õqâ3Þ¶A_‚ƒ0m¿„¹Ø8͇ëic98)—çˆFƒ'ÅÌúËxø6|§õI¥¥ ñ \6jç ¬s÷IŸQºKtÙמ×Á¡ÙŸP}vìLO; ‚çhx8º¹!·hjA‡M"è]Ë«áaù  z6—'¶%œ÷A¸næ·œ¬ÍÿÜõ y;ÀràV• ›“¶GIfê5õ¡f¿ ¦…ÁÒðúÛ4¼þmä­ º:&]d’™UVUØðÅ< _4ßëCvë$k|ÚÇÙÈx­U ÇYÈb.ÁùN^‚›/ñÌ–ÖÓð^¤U@Té2¬H‰¤€ò3 Õòze= žvÞzÔ ¬‰«bËó‹ô…º¬“ª»Ÿ²ÒÊjIýfñ.Mx+, Î Ô”%Kg„”F±JYRˆÞ&¡^»Ê;ÕÈ©™¿ºÃ·àðß:aì ™mP@oñjiooi9y²ÅËÃÃËk «CËé'>ò]á5nÂÒC-M ‡NftÛUÖô›m-æ!–.*¦,mºè»ûB«±ä@Χ¬vp´QoV©ÄtL¶âÄø MNbÀ‡@S¡= (ö)ϪZ^gÁ ñü³•eÁcP·Á°,[§qÛ¹ó¡£:/ D*žŒÑ)@Û6}=Øô 盳 üôÍÞ%ùÿ7ݸ¹÷3*1lÌÜ9ºF\!ŠÅBa…¸¦¦¢¢†Aîh„ÕãþÐŽ=Œ5l»"ïûd÷&û ê:Ü{Ï­=(ajÆ£y]z$NoñÂÙµ¹ ì¡]uêÛq¹©×déà’´l ¦>óÚ¸ÄÇ×P,bvÔ¤J+K+N3õšTDw»ÔrCA]6ÓbN<‰ÛuóÑ“esèAÖï¨g^`NtæÒEÆÎ¼ÀýàuüèÑ«PP452’´b«YíÀªN8ÌòÓër†y}óÃÝž¼wü‹ÉbX—d‹Mn—[S±¥/·P€9I`u= ³i8ÚÙ7ÚtåiVo³—D“Ñö𧞀k¬4<Ö%ÙnCÊiÖ0Ûo“woá’Œ·±Hj-(d¡ƒuùÐ7,\¯v¢96¾sön#l®ÚìoDß9x'; iùás»àçt9€v3’¶ƒ­>Œ6#¦Í»’ݪðˆ”Z)À-lwÏrå ‘E킾1ÿ‰õ;¸\ðÍ¡¶fcA¼ƒâÊð^<Ýø?=‚7§4qõf^>—ÊçÂqírkz·n36U’Þè†z“Æ+u›S©ýbܬÎO*•‚$üÁ¿c5‰;‘‡öÓÔƒšVM›|äXaµ z|P 0°:òzW^º4=º 8°×Ë­LÏ> Åé‡(=™îs‰3T¹â < éåúÒnYþù‰sÆ“HàÏ|x™û‚>í•¡Rz§lÞ’‰&é×1:™ÎÈtaºØfÐ t%º}ú3ºóº3ºSíàÕ•g÷{&¬3üÌÌ;× p]ŸÂô¹’+­àõõÜ{È9Ì]8oå•çdŒKÌ’M`>5ᇙØ\ ÿáñ‹‹Û]K™… ô ÷–ÏO´½s§Ýsë&w¯,º`7ßõÌå g;>:ã¾vëÆù–ïL0ËÈûƒ_'žõœÿqÿ‚»A7†ÄÅ*·§3ÈSiH¨NFŸ¯«¤àðßî[c‚ìm8ú6ÄÉáÎn% šÀ&È’…°_æÁȼ8à´¤„¤%ÊQÇIù×ed¢?ðoì2¶ßE*€ÀÇ6’ñhÐ-]WÞQµ?ƒÉlL¯ÎØO=ÿû[·È¼ é@P°n$úަŸw/<©› ¸ý¬€oñàvøÞãøtShuH€(4$ ^ÔÐT]ßÀ ³voü ¿ù‘©Ã Cws‡‘wîê/æWW-Ž«> iŽ+ôÑ$«T š Ý#3ìË>rÑ÷[429Ð=ûî" @„üÓe`ØV?ŽŽ¤D˜åU*?••iÈ¥TU´1RªòZÖ6 OÀÏË€ho¨.«¼,º~| .ø=FŽU”K½1oû>p ìo8r³€2£úb|³ØvøíøTAõtJ8ÀzXÇ¿9¬kŸVG ÃäêT¹ÄPò¢Ø²òíÐþ‚è€w HUèBkIÀ)`äá¦ñ¹u\,›]˜LÔI\›ˆ'mÝA~ ªD5:i¡2'>F!ŽÙ©9i:@•‹*Œ CR6‹á*û˜Íp¸™÷²ãë8ËÒlzê¬ímn·EªK´lÔš°9­ñÒ£·îԨ˷V­ßºyʦ×"/&^¨‰v'ù já±å·Ï4ïo¨föù kÔÕê­û„@+ÔŠ4¬6$^‚@ðAEÉÞsÆöôl ­‡ïÒ²Ïqï7P§+k+Á’´pYØÖõŒõ§ DÇæÃ¥áBì¢ý?ßÛœSÞz¤›Z›nß½Íkâ6ó9Wø‚ÎÛqçâYô‚Œ÷à ÞA _¡ÉtáAL@L Ä‘‰ï±Ò[8m‚ëpó®3óá3NMwÚ( —hôÞÇSÈÓéÒôi@ƒ?"•Ërï¤ä$ ˆ¥bKäÅ•¿]…oÿG]ÖÃJ:?'/ϹÆxƒ*=†!Žêt•. P±R¹XZ ÌU³°­Bmh]JªJbœ"ËE™™z}VÊcµ[ŒýËšÍ4(NÊRf#LJ>¿€;&sykó㇎Öggf@•«1ŠÄs×ÏÚÈlþ(nöµ« '_ž||Ù=÷=xpÉ2æ²=k®=ǃ Xè~ÅÞ\‰¶æÙ¶›wDàY)Y¢’åª :Î:„ðXí"Ùé»x›g¨J“œ””2+ººâ›sÏ0§”<7,ø~bâÞÁ•^çãðß´~Î ª©Ð‚T"‹>’sA‘­Õ+“T.‹IÈL(MbÝ8zƒ8Äd§˜"™Ñ™žžÉ@â’62͈œT ¨±4æT§™µ{˜²Ä6Qu\¥\oóEÅeÆøM:+)Xt()ó׳Žùx”Ì¢ÊäÅRerjj²%÷MpÁm¸oMr›OC ™×‚”À"²d8€5/A,b½ò—ÏB|E&ÿ&üp>c¥°…¾ãù°AO'Kbý·Ä)Sc5@ÒMÔ†W§¡Ý¹€O¿È°ÝÕ¢¦ìlNoyšn÷@b.Þ5ü²/\¾‹oJ~`âëE&þí=€9ÇMæs;w sŠdS1E±Qʘ¤d}ùï¥*•ÕNâ2yi¥¡4/Óê/u½j"ËHµv,‰ìý8ôrAkF#¡´ ß. ÚǪÝp:ÆÀ±WŸß¼yu"ƒÆº¡þ÷š@Òü3ιcìJ¯YS)&t…¯È7Už&Ñ‚0Jš—PÙ|Ðd¬`º>œaó|¦Õ1Í ­,è®àïNt_Áþ½@`[ 6{äaV'ÿÊ´J­VãÇbYø¨çëŠÚÞo¨£E ’§Û Ýã=Mûo^?Qpàø/ÑPÔÁ‚9¾ IEƪ’:“*;9“)9r¤ [âû;f¯ðp÷ÝÍÚZ†[?vŸ2ž _Y±ÅuúÙ‹3ޱ@§×¦¥^Ÿ«Ó=È öHMQbyð̧à08âá÷Ͼv;ãibnʾŒÙrwñed†¬Ù¶*¬ß©7ïURcDŒ0Áþ×Ë¡=ö¯'ÿó¨ÿnŸd‰]{C×^†³Í¼ßXþk »»§ttzüà V›= X¦Q§&bñ—ˆk«eum!çÇ¢Qø3mG‰ÿÉ/÷¯p´ŸñÙmÚèÃä£ 40¤¤c7qöìÉ»÷O¹,›÷é†eïKàÛ:fpb·,~’G¢˜,y@ç@f€]¬Ð¡¿ÙÁ¡ÓaAü/S‚ï¥ endstream endobj 8 0 obj <>endobj 195 0 obj <>stream dvips + GPL Ghostscript 9.06 () 2014-08-14T08:47:59+03:00 2014-08-14T08:47:59+03:00 LaTeX with Beamer class version 3.10 paexec … distributes tasks over network or CPUsAleksey Cheusov vle@gmx.net() endstream endobj 2 0 obj <>endobj xref 0 196 0000000000 65535 f 0000050483 00000 n 0000100906 00000 n 0000050214 00000 n 0000044535 00000 n 0000000015 00000 n 0000000612 00000 n 0000051108 00000 n 0000095900 00000 n 0000057555 00000 n 0000084015 00000 n 0000056921 00000 n 0000079081 00000 n 0000056387 00000 n 0000074240 00000 n 0000051149 00000 n 0000051179 00000 n 0000044727 00000 n 0000000631 00000 n 0000001412 00000 n 0000056123 00000 n 0000073576 00000 n 0000051231 00000 n 0000051261 00000 n 0000044921 00000 n 0000001432 00000 n 0000002693 00000 n 0000055329 00000 n 0000067853 00000 n 0000054788 00000 n 0000062411 00000 n 0000054501 00000 n 0000061435 00000 n 0000051313 00000 n 0000051343 00000 n 0000045115 00000 n 0000002714 00000 n 0000004017 00000 n 0000051406 00000 n 0000051436 00000 n 0000045309 00000 n 0000004038 00000 n 0000005456 00000 n 0000051510 00000 n 0000051540 00000 n 0000045503 00000 n 0000005477 00000 n 0000006807 00000 n 0000051625 00000 n 0000051655 00000 n 0000045697 00000 n 0000006828 00000 n 0000007997 00000 n 0000051729 00000 n 0000051759 00000 n 0000045891 00000 n 0000008018 00000 n 0000009674 00000 n 0000051833 00000 n 0000051863 00000 n 0000046085 00000 n 0000009695 00000 n 0000011083 00000 n 0000051948 00000 n 0000051978 00000 n 0000046279 00000 n 0000011104 00000 n 0000013051 00000 n 0000054094 00000 n 0000059203 00000 n 0000052052 00000 n 0000052082 00000 n 0000046473 00000 n 0000013072 00000 n 0000014123 00000 n 0000052167 00000 n 0000052197 00000 n 0000046667 00000 n 0000014143 00000 n 0000016049 00000 n 0000052249 00000 n 0000052279 00000 n 0000046861 00000 n 0000016070 00000 n 0000017400 00000 n 0000058643 00000 n 0000089437 00000 n 0000052353 00000 n 0000052383 00000 n 0000047055 00000 n 0000017421 00000 n 0000018871 00000 n 0000052457 00000 n 0000052487 00000 n 0000047249 00000 n 0000018892 00000 n 0000020414 00000 n 0000052561 00000 n 0000052591 00000 n 0000047443 00000 n 0000020435 00000 n 0000021954 00000 n 0000052665 00000 n 0000052696 00000 n 0000047640 00000 n 0000021976 00000 n 0000025110 00000 n 0000054433 00000 n 0000052771 00000 n 0000052802 00000 n 0000047838 00000 n 0000025132 00000 n 0000026952 00000 n 0000052868 00000 n 0000052899 00000 n 0000048036 00000 n 0000026974 00000 n 0000028561 00000 n 0000058355 00000 n 0000088470 00000 n 0000052974 00000 n 0000053005 00000 n 0000048234 00000 n 0000028583 00000 n 0000030168 00000 n 0000053082 00000 n 0000053113 00000 n 0000048432 00000 n 0000030190 00000 n 0000031671 00000 n 0000053179 00000 n 0000053210 00000 n 0000048630 00000 n 0000031693 00000 n 0000033665 00000 n 0000053287 00000 n 0000053318 00000 n 0000048828 00000 n 0000033687 00000 n 0000035546 00000 n 0000053395 00000 n 0000053426 00000 n 0000049026 00000 n 0000035568 00000 n 0000037589 00000 n 0000053503 00000 n 0000053534 00000 n 0000049224 00000 n 0000037611 00000 n 0000039542 00000 n 0000053611 00000 n 0000053642 00000 n 0000049422 00000 n 0000039564 00000 n 0000041033 00000 n 0000053706 00000 n 0000053737 00000 n 0000049620 00000 n 0000041055 00000 n 0000042482 00000 n 0000053801 00000 n 0000053832 00000 n 0000049818 00000 n 0000042504 00000 n 0000044128 00000 n 0000053909 00000 n 0000053940 00000 n 0000050016 00000 n 0000044150 00000 n 0000044514 00000 n 0000058105 00000 n 0000087471 00000 n 0000054017 00000 n 0000054048 00000 n 0000059525 00000 n 0000061752 00000 n 0000062939 00000 n 0000068327 00000 n 0000073846 00000 n 0000074753 00000 n 0000079562 00000 n 0000084419 00000 n 0000087752 00000 n 0000088759 00000 n 0000090025 00000 n 0000054670 00000 n 0000055236 00000 n 0000055772 00000 n 0000055892 00000 n 0000056288 00000 n 0000056815 00000 n 0000057417 00000 n 0000058006 00000 n 0000058525 00000 n 0000059110 00000 n 0000099191 00000 n trailer << /Size 196 /Root 1 0 R /Info 2 0 R /ID [<92F647226830C28BAC490277C13CAAF1><92F647226830C28BAC490277C13CAAF1>] >> startxref 101204 %%EOF paexec-1.0.1/tests004075500017500000000000000000001237304661200133765ustar cheusovwheelpaexec-1.0.1/tests/Makefile010064400017500000000000000026261237304661200151200ustar cheusovwheelMKC_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_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.0.1/tests/Makefile.inc010064400017500000000000000000331237304661200156560ustar cheusovwheel.include "../Makefile.inc" paexec-1.0.1/tests/fakeflac004075500017500000000000000000001237304661200151325ustar cheusovwheelpaexec-1.0.1/tests/fakeflac/fake1.wav010064400017500000000000000000221237304661200167060ustar cheusovwheelThis is fake wav1 paexec-1.0.1/tests/fakeflac/fake2.wav010064400017500000000000000000221237304661200167070ustar cheusovwheelThis is fake wav2 paexec-1.0.1/tests/fakeflac/fake3.wav010064400017500000000000000000221237304661200167100ustar cheusovwheelThis is fake wav3 paexec-1.0.1/tests/fakeflac/fake4.wav010064400017500000000000000000221237304661200167110ustar cheusovwheelThis is fake wav4 paexec-1.0.1/tests/fakeflac/fake5.wav010064400017500000000000000000221237304661200167120ustar cheusovwheelThis is fake wav5 paexec-1.0.1/tests/fakeflac/flac010075500017500000000000000004401237304661200160370ustar cheusovwheel#!/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.0.1/tests/scripts004075500017500000000000000000001237304661200150655ustar cheusovwheelpaexec-1.0.1/tests/scripts/Makefile010064400017500000000000000002501237304661200165760ustar cheusovwheelINSCRIPTS = big_result_cmd transport_broken_rnd \ transport_broken_echo transport_broken_toupper SCRIPTS = paexec_notransport ${INSCRIPTS} .include paexec-1.0.1/tests/scripts/big_result_cmd.in010075500017500000000000000003541237304661200204600ustar cheusovwheel#!@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.0.1/tests/scripts/paexec_notransport010075500017500000000000000002221237304661200210010ustar cheusovwheel#!/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.0.1/tests/scripts/transport_broken_echo.in010075500017500000000000000010451237304661200220660ustar cheusovwheel#!@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.0.1/tests/scripts/transport_broken_echo2010075500017500000000000000007351237304661200215500ustar cheusovwheel#!/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.0.1/tests/scripts/transport_broken_rnd.in010075500017500000000000000012351237304661200217340ustar cheusovwheel#!@awk@ -f function sleep (secs){ if (!nosleep && 0 != system("sleep " secs)){ exit 10 } } function my_rnd (){ # FreeBSD's /usr/bin/awk generates very bad first random value. # This is why we run rand() twice. rand() if (rand() < threshold) return 0.0 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() # sleep(my_rnd()) } { if (my_rnd() == 0.0) { sleep(0.1) exit 1 } sleep(my_rnd()) print " " $0 if (!nopostfail && my_rnd() == 0.0) { sleep(0.1) exit 1 } print "success" print "" fflush() } paexec-1.0.1/tests/scripts/transport_broken_toupper.in010075500017500000000000000007221237304661200226470ustar cheusovwheel#!@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.0.1/tests/test.sh010075500017500000000000001567521237304661200150100ustar cheusovwheel#!/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 } cut_version (){ awk '$1 == "paexec" {$2 = "x.y.x"} {print}' } cut_help (){ awk 'NR <= 3' } 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 (){ 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] ' # bad -md= arg runtest -md= 2>&1 | cmp 'paexec -md= #1' 'paexec: bad argument for -md=. Exactly one character is allowed ' runtest -md=aa 2>&1 | cmp 'paexec -md= #2' 'paexec: bad argument for -md=. Exactly 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 ' # 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 ' # 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' \ '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.0.1/tests/transp_closed_stdin004075500017500000000000000000001237304661200174375ustar cheusovwheelpaexec-1.0.1/tests/transp_closed_stdin/Makefile010064400017500000000000000001071237304661200211510ustar cheusovwheelPROG = transp_closed_stdin WARNS = 4 .include paexec-1.0.1/tests/transp_closed_stdin/transp_closed_stdin.c010064400017500000000000000006731237304661200237260ustar cheusovwheel#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; }