From 343274cfafac25469755f033ff43382353bca636 Mon Sep 17 00:00:00 2001 From: Samuel Grayson Date: Mon, 18 Nov 2024 00:45:13 -0600 Subject: [PATCH 1/6] wip --- .github/workflows/ci.yml | 6 +- .gitignore | 3 +- Justfile | 45 +- Makefile | 25 - README.md | 28 - .../PROBE_small_bench.csv | 0 .../frontend => cli-wrapper}/Cargo.lock | 4 +- .../frontend => cli-wrapper}/Cargo.toml | 4 +- {probe_src/frontend => cli-wrapper}/LICENSE | 0 {probe_src/frontend => cli-wrapper}/README.md | 0 .../frontend => cli-wrapper}/cli/Cargo.toml | 2 +- .../frontend => cli-wrapper}/cli/src/dump.rs | 2 +- .../frontend => cli-wrapper}/cli/src/main.rs | 4 +- .../cli/src/record.rs | 0 .../cli/src/transcribe.rs | 2 +- .../frontend => cli-wrapper}/cli/src/util.rs | 0 {probe_src/frontend => cli-wrapper}/deny.toml | 0 cli-wrapper/frontend.nix | 135 + .../frontend => cli-wrapper}/lib/Cargo.toml | 4 +- .../frontend => cli-wrapper}/lib/build.rs | 0 .../frontend => cli-wrapper}/lib/src/error.rs | 0 .../frontend => cli-wrapper}/lib/src/lib.rs | 0 .../lib/src/metadata.rs | 0 .../frontend => cli-wrapper}/lib/src/ops.rs | 0 .../lib/src/transcribe.rs | 0 .../macros/Cargo.toml | 0 .../macros/src/lib.rs | 0 .../macros/src/pygen.rs | 0 .../python => cli-wrapper}/pyproject.toml | 0 .../README.md => docs/developers_readme.md | 6 + {probe_src => docs}/notes.md | 0 tasks.org => docs/old_tasks.org | 0 docs/{ => publications}/.gitignore | 0 docs/{ => publications}/acm-rep-pres.html | 0 docs/{ => publications}/acm-rep-pres.pdf | Bin docs/{ => publications}/acm-template.tex | 0 .../benchmark_suite/README.md | 0 .../benchmark_suite/README.pdf | Bin .../benchmark_suite/app-lvl-prov.dot | 0 .../benchmark_suite/generated/clustering2.svg | 0 .../benchmark_suite/generated/dendrogram.pdf | Bin .../benchmark_suite/generated/dendrogram.svg | 0 .../generated/dendrogram_full.pdf | Bin .../generated/log_overhead_hist.svg | 0 .../benchmark_suite/generated/pca0.pdf | Bin .../benchmark_suite/generated/pca1.pdf | Bin .../generated/predictive-performance.pdf | Bin .../generated/subsetting-accuracy.pdf | Bin .../generated/subsetting-dist.pdf | Bin .../benchmark_suite/generated/subsetting.pdf | Bin .../benchmark_suite/prov-example.dot | 0 .../benchmark_suite/prov-example.png | Bin .../benchmark_suite/simple-prov-example.dot | 0 .../benchmark_suite/simple-prov-example.png | Bin .../benchmark_suite/submitted.pdf | Bin .../benchmark_suite/sys-lvl-log.svg | 0 .../benchmark_suite/sys-lvl-prov.dot | 0 .../benchmark_suite/tech_report.md | 0 .../benchmark_suite/wf-lvl-prov.dot | 0 .../{ => publications}/citations-to-latex.lua | 0 docs/{ => publications}/dataflow-graph.png | Bin docs/{ => publications}/dataflow-graph.svg | Bin docs/{ => publications}/flake.lock | 0 docs/{ => publications}/flake.nix | 0 docs/{ => publications}/illinois.png | Bin .../lit_review/application-level.dot | 0 .../lit_review/datasets.org | 0 docs/{ => publications}/lit_review/flake.lock | 0 docs/{ => publications}/lit_review/flake.nix | 0 docs/{ => publications}/lit_review/index.pdf | Bin docs/{ => publications}/lit_review/index.tex | 0 .../lit_review/lit_review.md | 0 .../lit_review/lit_review.turtle | 0 docs/{ => publications}/lit_review/meat.tex | 0 docs/{ => publications}/lit_review/search.csv | 0 .../lit_review/system-level.dot | 0 .../lit_review/workflow-level.dot | 0 .../low_provenance_overhead/main.md | 0 docs/{ => publications}/poster/main.svg | 0 docs/{ => publications}/poster/poster.html | 0 docs/{ => publications}/poster/poster.pdf | Bin docs/{ => publications}/poster/poster.scrbl | 0 docs/{ => publications}/probe-qr.svg | 0 docs/{ => publications}/prov-example.svg | 0 docs/{ => publications}/prov_pres/main.md | 0 .../prov_pres/prov_example.dot | 0 .../prov_pres/prov_example.svg | 0 .../record_replay/.gitignore | 0 docs/{ => publications}/record_replay/main.md | 0 .../{ => publications}/record_replay/main.pdf | Bin .../record_replay/old-main.md | 0 .../record_replay/repro_comparison.ods | Bin .../record_replay/zotero.bib | 0 docs/{ => publications}/reed.bib | 0 docs/{ => publications}/sandia.svg | 0 docs/{ => publications}/script.sh | 0 docs/{ => publications}/supplemental.bib | 0 docs/{ => publications}/us-rse.html | 0 docs/{ => publications}/us-rse.pdf | Bin docs/{ => publications}/why_prov/main.md | 0 docs/{ => publications}/zotero.bib | 0 docs/publications_index.md | 15 + docs/research_reading_list.md | 27 + {probe_src => docs}/tasks.md | 68 +- {probe_src => docs}/threading.md | 0 flake.lock | 11 +- flake.nix | 116 +- libprobe/.gitignore | 3 + {probe_src/libprobe => libprobe}/Makefile | 2 +- {probe_src/libprobe => libprobe}/README.md | 0 .../libprobe => libprobe}/arena/.gitignore | 0 .../libprobe => libprobe}/arena/Makefile | 0 .../libprobe => libprobe}/arena/README.md | 0 .../arena/include/arena.h | 0 .../arena/parse_arena.py | 0 .../libprobe => libprobe}/arena/test_arena.c | 0 .../generator/dump_ast.py | 0 .../generator/gen_libc_hooks.py | 0 .../generator/libc_hooks_source.c | 0 .../include/libprobe/prov_ops.h | 0 .../libprobe => libprobe}/src/fd_table.c | 0 .../libprobe => libprobe}/src/global_state.c | 0 .../libprobe => libprobe}/src/inode_table.c | 0 {probe_src/libprobe => libprobe}/src/lib.c | 0 .../libprobe => libprobe}/src/prov_buffer.c | 0 .../libprobe => libprobe}/src/prov_enable.c | 0 .../libprobe => libprobe}/src/prov_ops.c | 0 {probe_src/libprobe => libprobe}/src/util.c | 0 output.png | Bin 1131078 -> 0 bytes probe_py/.gitignore | 2 + .../manual => probe_py/probe_py}/__init__.py | 0 .../manual => probe_py/probe_py}/analysis.py | 51 +- .../manual => probe_py/probe_py}/cli.py | 12 +- .../manual => probe_py/probe_py}/consts.py | 3 + .../probe_py}/file_closure.py | 4 +- probe_py/probe_py/graph_utils.py | 38 + .../generated => probe_py/probe_py}/parser.py | 54 +- probe_py/probe_py/ptypes.py | 60 + .../probe_py}/ssh_argparser.py | 1 - .../manual => probe_py/probe_py}/util.py | 0 .../manual => probe_py/probe_py}/workflows.py | 2 +- {probe_src/python => probe_py}/pyproject.toml | 9 +- {probe_src => probe_py}/tests/test_graph.py | 7 +- .../tests/test_workflow.py | 6 +- probe_src/.gitignore | 3 - probe_src/frontend/frontend.nix | 164 -- .../python/probe_py/generated/__init__.py | 7 - .../frontend/python/probe_py/generated/ops.py | 233 -- .../python/probe_py/generated/py.typed | 0 probe_src/libprobe/.gitignore | 1 - probe_src/libprobe/generated/libc_hooks.c | 2381 ----------------- probe_src/libprobe/generated/libc_hooks.h | 109 - probe_src/libprobe/src/lookup_on_path.c | 44 - probe_src/python/README.md | 5 - .../python/probe_py/manual/graph_utils.py | 13 - probe_src/tests/c/README.md | 0 reproducibility_tests/.gitignore | 1 - setup_devshell.sh | 26 +- {probe_src/tests => tests}/.gitignore | 0 .../tests => tests}/docker_os_matrix.py | 0 .../tests/c => tests/examples}/.gitignore | 0 .../tests/c => tests/examples}/Makefile | 0 .../tests/c => tests/examples}/createFile.c | 5 +- .../tests/c => tests/examples}/hello_world.c | 1 - {probe_src/tests/c => tests/examples}/mutex.c | 0 .../tests/c => tests/examples}/simple.c | 0 .../examples}/test_determinism.cxx | 0 .../examples/test_determinism.sh | 0 .../lightweight_env.sh | 0 {probe_src => tests}/performance_test.py | 36 +- .../ssh_wrapper_test/openssh-server.py | 0 .../openssh-server/docker-compose.yml | 0 .../ssh_wrapper_test/test_ssh_arg_parse.py | 0 .../tests => tests}/test_integration.py | 0 {probe_src/tests => tests}/test_path_stuff.py | 7 +- 175 files changed, 517 insertions(+), 3280 deletions(-) delete mode 100644 Makefile rename probe_src/benchmark_results.csv => benchmark/PROBE_small_bench.csv (100%) rename {probe_src/frontend => cli-wrapper}/Cargo.lock (99%) rename {probe_src/frontend => cli-wrapper}/Cargo.toml (94%) rename {probe_src/frontend => cli-wrapper}/LICENSE (100%) rename {probe_src/frontend => cli-wrapper}/README.md (100%) rename {probe_src/frontend => cli-wrapper}/cli/Cargo.toml (92%) rename {probe_src/frontend => cli-wrapper}/cli/src/dump.rs (99%) rename {probe_src/frontend => cli-wrapper}/cli/src/main.rs (98%) rename {probe_src/frontend => cli-wrapper}/cli/src/record.rs (100%) rename {probe_src/frontend => cli-wrapper}/cli/src/transcribe.rs (88%) rename {probe_src/frontend => cli-wrapper}/cli/src/util.rs (100%) rename {probe_src/frontend => cli-wrapper}/deny.toml (100%) create mode 100644 cli-wrapper/frontend.nix rename {probe_src/frontend => cli-wrapper}/lib/Cargo.toml (92%) rename {probe_src/frontend => cli-wrapper}/lib/build.rs (100%) rename {probe_src/frontend => cli-wrapper}/lib/src/error.rs (100%) rename {probe_src/frontend => cli-wrapper}/lib/src/lib.rs (100%) rename {probe_src/frontend => cli-wrapper}/lib/src/metadata.rs (100%) rename {probe_src/frontend => cli-wrapper}/lib/src/ops.rs (100%) rename {probe_src/frontend => cli-wrapper}/lib/src/transcribe.rs (100%) rename {probe_src/frontend => cli-wrapper}/macros/Cargo.toml (100%) rename {probe_src/frontend => cli-wrapper}/macros/src/lib.rs (100%) rename {probe_src/frontend => cli-wrapper}/macros/src/pygen.rs (100%) rename {probe_src/frontend/python => cli-wrapper}/pyproject.toml (100%) rename probe_src/README.md => docs/developers_readme.md (97%) rename {probe_src => docs}/notes.md (100%) rename tasks.org => docs/old_tasks.org (100%) rename docs/{ => publications}/.gitignore (100%) rename docs/{ => publications}/acm-rep-pres.html (100%) rename docs/{ => publications}/acm-rep-pres.pdf (100%) rename docs/{ => publications}/acm-template.tex (100%) rename docs/{ => publications}/benchmark_suite/README.md (100%) rename docs/{ => publications}/benchmark_suite/README.pdf (100%) rename docs/{ => publications}/benchmark_suite/app-lvl-prov.dot (100%) rename docs/{ => publications}/benchmark_suite/generated/clustering2.svg (100%) rename docs/{ => publications}/benchmark_suite/generated/dendrogram.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/dendrogram.svg (100%) rename docs/{ => publications}/benchmark_suite/generated/dendrogram_full.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/log_overhead_hist.svg (100%) rename docs/{ => publications}/benchmark_suite/generated/pca0.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/pca1.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/predictive-performance.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/subsetting-accuracy.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/subsetting-dist.pdf (100%) rename docs/{ => publications}/benchmark_suite/generated/subsetting.pdf (100%) rename docs/{ => publications}/benchmark_suite/prov-example.dot (100%) rename docs/{ => publications}/benchmark_suite/prov-example.png (100%) rename docs/{ => publications}/benchmark_suite/simple-prov-example.dot (100%) rename docs/{ => publications}/benchmark_suite/simple-prov-example.png (100%) rename docs/{ => publications}/benchmark_suite/submitted.pdf (100%) rename docs/{ => publications}/benchmark_suite/sys-lvl-log.svg (100%) rename docs/{ => publications}/benchmark_suite/sys-lvl-prov.dot (100%) rename docs/{ => publications}/benchmark_suite/tech_report.md (100%) rename docs/{ => publications}/benchmark_suite/wf-lvl-prov.dot (100%) rename docs/{ => publications}/citations-to-latex.lua (100%) rename docs/{ => publications}/dataflow-graph.png (100%) rename docs/{ => publications}/dataflow-graph.svg (100%) rename docs/{ => publications}/flake.lock (100%) rename docs/{ => publications}/flake.nix (100%) rename docs/{ => publications}/illinois.png (100%) rename docs/{ => publications}/lit_review/application-level.dot (100%) rename docs/{ => publications}/lit_review/datasets.org (100%) rename docs/{ => publications}/lit_review/flake.lock (100%) rename docs/{ => publications}/lit_review/flake.nix (100%) rename docs/{ => publications}/lit_review/index.pdf (100%) rename docs/{ => publications}/lit_review/index.tex (100%) rename docs/{ => publications}/lit_review/lit_review.md (100%) rename docs/{ => publications}/lit_review/lit_review.turtle (100%) rename docs/{ => publications}/lit_review/meat.tex (100%) rename docs/{ => publications}/lit_review/search.csv (100%) rename docs/{ => publications}/lit_review/system-level.dot (100%) rename docs/{ => publications}/lit_review/workflow-level.dot (100%) rename docs/{ => publications}/low_provenance_overhead/main.md (100%) rename docs/{ => publications}/poster/main.svg (100%) rename docs/{ => publications}/poster/poster.html (100%) rename docs/{ => publications}/poster/poster.pdf (100%) rename docs/{ => publications}/poster/poster.scrbl (100%) rename docs/{ => publications}/probe-qr.svg (100%) rename docs/{ => publications}/prov-example.svg (100%) rename docs/{ => publications}/prov_pres/main.md (100%) rename docs/{ => publications}/prov_pres/prov_example.dot (100%) rename docs/{ => publications}/prov_pres/prov_example.svg (100%) rename docs/{ => publications}/record_replay/.gitignore (100%) rename docs/{ => publications}/record_replay/main.md (100%) rename docs/{ => publications}/record_replay/main.pdf (100%) rename docs/{ => publications}/record_replay/old-main.md (100%) rename docs/{ => publications}/record_replay/repro_comparison.ods (100%) rename docs/{ => publications}/record_replay/zotero.bib (100%) rename docs/{ => publications}/reed.bib (100%) rename docs/{ => publications}/sandia.svg (100%) rename docs/{ => publications}/script.sh (100%) rename docs/{ => publications}/supplemental.bib (100%) rename docs/{ => publications}/us-rse.html (100%) rename docs/{ => publications}/us-rse.pdf (100%) rename docs/{ => publications}/why_prov/main.md (100%) rename docs/{ => publications}/zotero.bib (100%) create mode 100644 docs/publications_index.md create mode 100644 docs/research_reading_list.md rename {probe_src => docs}/tasks.md (84%) rename {probe_src => docs}/threading.md (100%) create mode 100644 libprobe/.gitignore rename {probe_src/libprobe => libprobe}/Makefile (96%) rename {probe_src/libprobe => libprobe}/README.md (100%) rename {probe_src/libprobe => libprobe}/arena/.gitignore (100%) rename {probe_src/libprobe => libprobe}/arena/Makefile (100%) rename {probe_src/libprobe => libprobe}/arena/README.md (100%) rename {probe_src/libprobe => libprobe}/arena/include/arena.h (100%) rename {probe_src/libprobe => libprobe}/arena/parse_arena.py (100%) rename {probe_src/libprobe => libprobe}/arena/test_arena.c (100%) rename {probe_src/libprobe => libprobe}/generator/dump_ast.py (100%) rename {probe_src/libprobe => libprobe}/generator/gen_libc_hooks.py (100%) rename {probe_src/libprobe => libprobe}/generator/libc_hooks_source.c (100%) rename {probe_src/libprobe => libprobe}/include/libprobe/prov_ops.h (100%) rename {probe_src/libprobe => libprobe}/src/fd_table.c (100%) rename {probe_src/libprobe => libprobe}/src/global_state.c (100%) rename {probe_src/libprobe => libprobe}/src/inode_table.c (100%) rename {probe_src/libprobe => libprobe}/src/lib.c (100%) rename {probe_src/libprobe => libprobe}/src/prov_buffer.c (100%) rename {probe_src/libprobe => libprobe}/src/prov_enable.c (100%) rename {probe_src/libprobe => libprobe}/src/prov_ops.c (100%) rename {probe_src/libprobe => libprobe}/src/util.c (100%) delete mode 100644 output.png create mode 100644 probe_py/.gitignore rename {probe_src/python/probe_py/manual => probe_py/probe_py}/__init__.py (100%) rename {probe_src/python/probe_py/manual => probe_py/probe_py}/analysis.py (92%) rename {probe_src/python/probe_py/manual => probe_py/probe_py}/cli.py (99%) rename {probe_src/python/probe_py/manual => probe_py/probe_py}/consts.py (73%) rename {probe_src/python/probe_py/manual => probe_py/probe_py}/file_closure.py (98%) create mode 100644 probe_py/probe_py/graph_utils.py rename {probe_src/frontend/python/probe_py/generated => probe_py/probe_py}/parser.py (70%) create mode 100644 probe_py/probe_py/ptypes.py rename {probe_src/python/probe_py/manual => probe_py/probe_py}/ssh_argparser.py (99%) rename {probe_src/python/probe_py/manual => probe_py/probe_py}/util.py (100%) rename {probe_src/python/probe_py/manual => probe_py/probe_py}/workflows.py (99%) rename {probe_src/python => probe_py}/pyproject.toml (71%) rename {probe_src => probe_py}/tests/test_graph.py (98%) rename {probe_src => probe_py}/tests/test_workflow.py (95%) delete mode 100644 probe_src/.gitignore delete mode 100644 probe_src/frontend/frontend.nix delete mode 100644 probe_src/frontend/python/probe_py/generated/__init__.py delete mode 100644 probe_src/frontend/python/probe_py/generated/ops.py delete mode 100644 probe_src/frontend/python/probe_py/generated/py.typed delete mode 100644 probe_src/libprobe/.gitignore delete mode 100644 probe_src/libprobe/generated/libc_hooks.c delete mode 100644 probe_src/libprobe/generated/libc_hooks.h delete mode 100644 probe_src/libprobe/src/lookup_on_path.c delete mode 100644 probe_src/python/README.md delete mode 100644 probe_src/python/probe_py/manual/graph_utils.py delete mode 100644 probe_src/tests/c/README.md delete mode 100644 reproducibility_tests/.gitignore rename {probe_src/tests => tests}/.gitignore (100%) rename {probe_src/tests => tests}/docker_os_matrix.py (100%) rename {probe_src/tests/c => tests/examples}/.gitignore (100%) rename {probe_src/tests/c => tests/examples}/Makefile (100%) rename {probe_src/tests/c => tests/examples}/createFile.c (98%) rename {probe_src/tests/c => tests/examples}/hello_world.c (99%) rename {probe_src/tests/c => tests/examples}/mutex.c (100%) rename {probe_src/tests/c => tests/examples}/simple.c (100%) rename {reproducibility_tests => tests/examples}/test_determinism.cxx (100%) rename reproducibility_tests/test.sh => tests/examples/test_determinism.sh (100%) rename lightweight_env.sh => tests/lightweight_env.sh (100%) rename {probe_src => tests}/performance_test.py (88%) rename {test => tests}/ssh_wrapper_test/openssh-server.py (100%) rename {test => tests}/ssh_wrapper_test/openssh-server/docker-compose.yml (100%) rename {test => tests}/ssh_wrapper_test/test_ssh_arg_parse.py (100%) rename {probe_src/tests => tests}/test_integration.py (100%) rename {probe_src/tests => tests}/test_path_stuff.py (85%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c405f757..ead74440 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,4 +43,8 @@ jobs: - run: nix flake check --all-systems --print-build-logs - - run: nix build --print-build-logs .#probe-bundled .#probe-py + - run: nix build --print-build-logs .#probe-bundled + + # The devshell uses slightly different build process than the Nix pkg + # Might as well test that too + - run: nix develop --command just compile fix check test diff --git a/.gitignore b/.gitignore index c5d4cd06..3d633267 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ **/.nextflow **/work **/.pytest_cache +**/__pycache__/ # build directories **/target @@ -21,4 +22,4 @@ **/desktop.ini probe_log -dataflow_graph.pkl +.dmypy.json diff --git a/Justfile b/Justfile index ffee3e47..8b33f2ac 100644 --- a/Justfile +++ b/Justfile @@ -1,34 +1,41 @@ -fix-format-nix: +fix-nix: alejandra . -fix-ruff: - #ruff format probe_src # TODO: uncomment - ruff check --fix probe_src +# fix-py depends on compile-cli for the autogen python code +fix-py: compile-cli + #ruff format probe_py/ tests/ libprobe/generator/ # TODO: uncomment + ruff check --fix probe_py probe_py/ tests/ libprobe/generator/ -fix-format-rust: - env --chdir probe_src/frontend cargo fmt +fix-cli: + # stage because cargo clippy fix may be destructive + env --chdir cli-wrapper git add -A + env --chdir cli-wrapper cargo clippy --fix --allow-staged -- --deny warnings + env --chdir cli-wrapper cargo fmt -fix-clippy: - git add -A - env --chdir probe_src/frontend cargo clippy --fix --allow-staged +fix: fix-nix fix-py fix-cli -check-mypy: - mypy --strict probe_src/libprobe - mypy --strict --package probe_py.generated - mypy --strict --package probe_py.manual +check-py: compile-cli + # dmypy == daemon mypy; much faster. + dmypy run -- --strict --no-namespace-packages --pretty probe_py/ tests/ libprobe/generator/ + +check-cli: + env --chdir cli-wrapper cargo doc --workspace + +check: check-py check-cli compile-lib: - make --directory=probe_src/libprobe all + make --directory=libprobe all compile-cli: - env --chdir=probe_src/frontend cargo build --release + env --chdir=cli-wrapper cargo build --release + env --chdir=cli-wrapper cargo build compile-tests: - make --directory=probe_src/tests/c all + make --directory=tests/examples all compile: compile-lib compile-cli compile-tests -test-dev: compile - pytest probe_src --failed-first --maxfail=1 +test: compile + python -m pytest tests/ -ra --failed-first --maxfail=1 -v -pre-commit: fix-format-nix fix-ruff fix-format-rust fix-clippy compile check-mypy test-dev +pre-commit: fix check compile test diff --git a/Makefile b/Makefile deleted file mode 100644 index 91e90242..00000000 --- a/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -all: - mkdir -p experiments - - # Process 14194128: bash -c cat flake.nix > test0; head test0 >tmp ; wc -l test0; head test0 >tmp ; wc -l process_14194128/output.log 2>&1 - # Process 14194128: cat flake.nix - mkdir -p process_14194128 - # Copy input files for process 14194128 - cp flake.nix_v0 process_14194128/ - # Run command for process 14194128 - (cd process_14194128 && cat flake.nix) - # Process 14194128: head test0 - mkdir -p process_14194128 - # Copy input files for process 14194128 - cp test0_v0 process_14194128/ - # Run command for process 14194128 - (cd process_14194128 && head test0) - # Process 14194128: wc -l - mkdir -p process_14194128 - # Copy input files for process 14194128 - cp tmp_v0 process_14194128/ - # Run command for process 14194128 - (wc -l) > process_14194128/output.log 2>&1 \ No newline at end of file diff --git a/README.md b/README.md index 5ab5439f..ce6726b2 100644 --- a/README.md +++ b/README.md @@ -108,31 +108,3 @@ probe export --help 6. Run `probe ` or `python -m probe_py.manual.cli ` to invoke the Rust or Python code respectively. 7. **Before submitting a PR**, run `just pre-commit` which will run pre-commit checks. - -## Resarch reading list - -- [_Provenance for Computational Tasks: A Survey_ by Freire, et al. in CiSE 2008](https://sci.utah.edu/~csilva/papers/cise2008a.pdf) for an overview of provenance in general. - -- [_Transparent Result Caching_ by Vahdat and Anderson in USENIX ATC 1998](https://www.usenix.org/legacy/publications/library/proceedings/usenix98/full_papers/vahdat/vahdat.pdf) for an early system-level provenance tracer in Solaris using the `/proc` fs. Linux's `/proc` fs doesn't have the same functionality. However, this paper discusses two interesting application of provenance: unmake (query lineage information) and transparent Make (more generally, incremental computation). - -- [_CDE: Using System Call Interposition to Automatically Create Portable Software Packages_ by Guo and Engler in USENIX ATC 2011](https://www.usenix.org/legacy/events/atc11/tech/final_files/GuoEngler.pdf) for an early system-level provenance tracer. Their only application is software execution replay, but replay is quite an important application. - -- [_Techniques for Preserving Scientific Software Executions: Preserve the Mess or Encourage Cleanliness?_ by Thain, Meng, and Ivie in 2015 ](https://curate.nd.edu/articles/journal_contribution/Techniques_for_Preserving_Scientific_Software_Executions_Preserve_the_Mess_or_Encourage_Cleanliness_/24824439?file=43664937) discusses whether enabling automatic-replay is actually a good idea. A cursory glance makes PROBE seem more like "preserving the mess", but I think, with some care in the design choices, it actually can be more like "encouraging cleanliness", for example, by having heuristics that help cull/simplify provenance and generating human readable/editable package-manager recipes. - -- [_SoK: History is a Vast Early Warning System: Auditing the Provenance of System Intrusions_ by Inam et al. in IEEE Symposium on Security and Privacy 2023](https://adambates.org/documents/Inam_Oakland23.pdf) see specifically Inam's survey of different possibilities for the "Capture layer", "Reduction layer", and "Infrastructure layer". Although provenance-for-security has different constraints than provenacne for other purposes, the taxonomy that Inam lays out is still useful. PROBE operates by intercepting libc calls, which is essentially a "middleware" in Table I (platform modification, no program modification, no config change, incomplete mediation, not tamperproof, inter-process tracing, etc.). - -- [_System-Level Provenance Tracers_ by me et al. in ACM REP 2023](./docs/acm-rep-pres.pdf) for a motivation of this work. It surveys prior work, identifies potential gaps, and explains why I think library interposition is a promising path for future research. - -- [_Computational Experiment Comprehension using Provenance Summarization_ by Bufford et al. in ACM REP 2023](https://dl.acm.org/doi/pdf/10.1145/3641525.3663617) discusses how to implement an interface for querying provenance information. They compare classical graph-based visualization with an interactive LLM in a user-study. - -## Prior art - -- [RR-debugger](https://github.com/rr-debugger/rr) which is much slower, but features more complete capturing, lets you replay but doesn't let you do any other analysis. - -- [Sciunits](https://github.com/depaul-dice/sciunit) which is much slower, more likely to crash, has less complete capturing, lets you replay but doesn't let you do other analysis. - -- [Reprozip](https://www.reprozip.org/) which is much slower and has less complete capturing. - -- [CARE](https://proot-me.github.io/care/) which is much slower, has less complete capturing, and lets you do containerized replay but not unpriveleged native replay and not other analysis. - -- [FSAtrace](https://github.com/jacereda/fsatrace) which is more likely to crash, has less complete capturing, and doesn't have replay or other analyses. diff --git a/probe_src/benchmark_results.csv b/benchmark/PROBE_small_bench.csv similarity index 100% rename from probe_src/benchmark_results.csv rename to benchmark/PROBE_small_bench.csv diff --git a/probe_src/frontend/Cargo.lock b/cli-wrapper/Cargo.lock similarity index 99% rename from probe_src/frontend/Cargo.lock rename to cli-wrapper/Cargo.lock index 04d1a6d1..b6fc69b4 100644 --- a/probe_src/frontend/Cargo.lock +++ b/cli-wrapper/Cargo.lock @@ -773,7 +773,7 @@ dependencies = [ "flate2", "libc", "log", - "probe_frontend", + "probe_lib", "rand", "serde", "serde_json", @@ -781,7 +781,7 @@ dependencies = [ ] [[package]] -name = "probe_frontend" +name = "probe_lib" version = "0.2.0" dependencies = [ "bindgen", diff --git a/probe_src/frontend/Cargo.toml b/cli-wrapper/Cargo.toml similarity index 94% rename from probe_src/frontend/Cargo.toml rename to cli-wrapper/Cargo.toml index 5b25b713..2c9072fc 100644 --- a/probe_src/frontend/Cargo.toml +++ b/cli-wrapper/Cargo.toml @@ -1,8 +1,8 @@ [workspace] resolver = "2" -members = [ +members = [ "cli", - "lib", + "lib", "macros", ] diff --git a/probe_src/frontend/LICENSE b/cli-wrapper/LICENSE similarity index 100% rename from probe_src/frontend/LICENSE rename to cli-wrapper/LICENSE diff --git a/probe_src/frontend/README.md b/cli-wrapper/README.md similarity index 100% rename from probe_src/frontend/README.md rename to cli-wrapper/README.md diff --git a/probe_src/frontend/cli/Cargo.toml b/cli-wrapper/cli/Cargo.toml similarity index 92% rename from probe_src/frontend/cli/Cargo.toml rename to cli-wrapper/cli/Cargo.toml index 4c1ebdc8..968d2dfd 100644 --- a/probe_src/frontend/cli/Cargo.toml +++ b/cli-wrapper/cli/Cargo.toml @@ -19,7 +19,7 @@ exec = "0.3.1" flate2 = "1.0.30" libc = "0.2.155" log = "0.4.21" -probe_frontend = { path = "../lib" } +probe_lib = { path = "../lib" } rand = "0.8.5" serde = "1.0.203" serde_json = "1.0.118" diff --git a/probe_src/frontend/cli/src/dump.rs b/cli-wrapper/cli/src/dump.rs similarity index 99% rename from probe_src/frontend/cli/src/dump.rs rename to cli-wrapper/cli/src/dump.rs index 92ae7861..d175df30 100644 --- a/probe_src/frontend/cli/src/dump.rs +++ b/cli-wrapper/cli/src/dump.rs @@ -7,7 +7,7 @@ use std::{ use chrono::{DateTime, SecondsFormat}; use color_eyre::eyre::{eyre, Result, WrapErr}; -use probe_frontend::ops; +use probe_lib::ops; use serde::{Deserialize, Serialize}; /// Print the ops from a probe log out for humans. diff --git a/probe_src/frontend/cli/src/main.rs b/cli-wrapper/cli/src/main.rs similarity index 98% rename from probe_src/frontend/cli/src/main.rs rename to cli-wrapper/cli/src/main.rs index 7466856f..b265ae72 100644 --- a/probe_src/frontend/cli/src/main.rs +++ b/cli-wrapper/cli/src/main.rs @@ -10,7 +10,7 @@ mod dump; /// Run commands under provenance and generate probe record directory. mod record; -/// Wrapper over [`probe_frontend::transcribe`]. +/// Wrapper over [`probe_lib::transcribe`]. mod transcribe; /// Utility code for creating temporary directories. @@ -137,7 +137,7 @@ fn main() -> Result<()> { let exit = std::process::Command::new("python3") .arg("-m") - .arg("probe_py.manual.cli") + .arg("probe_py.cli") .arg(subcommand) .args(&args) .spawn() diff --git a/probe_src/frontend/cli/src/record.rs b/cli-wrapper/cli/src/record.rs similarity index 100% rename from probe_src/frontend/cli/src/record.rs rename to cli-wrapper/cli/src/record.rs diff --git a/probe_src/frontend/cli/src/transcribe.rs b/cli-wrapper/cli/src/transcribe.rs similarity index 88% rename from probe_src/frontend/cli/src/transcribe.rs rename to cli-wrapper/cli/src/transcribe.rs index 799df9b1..d3364060 100644 --- a/probe_src/frontend/cli/src/transcribe.rs +++ b/cli-wrapper/cli/src/transcribe.rs @@ -10,7 +10,7 @@ pub fn transcribe, T: Write>( ) -> Result<()> { let log_dir = Dir::temp(true).wrap_err("Failed to create temp directory for transcription")?; - probe_frontend::transcribe::parse_top_level(record_dir, &log_dir) + probe_lib::transcribe::parse_top_level(record_dir, &log_dir) .wrap_err("Failed to transcribe record directory")?; tar.append_dir_all(".", &log_dir) diff --git a/probe_src/frontend/cli/src/util.rs b/cli-wrapper/cli/src/util.rs similarity index 100% rename from probe_src/frontend/cli/src/util.rs rename to cli-wrapper/cli/src/util.rs diff --git a/probe_src/frontend/deny.toml b/cli-wrapper/deny.toml similarity index 100% rename from probe_src/frontend/deny.toml rename to cli-wrapper/deny.toml diff --git a/cli-wrapper/frontend.nix b/cli-wrapper/frontend.nix new file mode 100644 index 00000000..7442d9af --- /dev/null +++ b/cli-wrapper/frontend.nix @@ -0,0 +1,135 @@ +{ + pkgs, + craneLib, + rust-target, + advisory-db, + system, + python, + lib, +}: rec { + # See https://crane.dev/examples/quick-start-workspace.html + + src = craneLib.cleanCargoSource ./.; + + # Common arguments can be set here to avoid repeating them later + commonArgs = { + inherit src; + strictDeps = true; + + # all the crates in this workspace either use rust-bindgen or depend + # on local crate that does. + nativeBuildInputs = [ + pkgs.rustPlatform.bindgenHook + ]; + + CARGO_BUILD_TARGET = rust-target; + CARGO_BUILD_RUSTFLAGS = "-C target-feature=+crt-static"; + CPATH = ../libprobe/include; + + # pygen needs to know where to write the python file + preConfigurePhases = [ + "pygenConfigPhase" + ]; + pygenConfigPhase = '' + export PYGEN_OUTFILE="$out/resources/ops.py" + mkdir --parents "$(dirname "$PYGEN_OUTFILE")" + echo "Sending python code to $PYGEN_OUTFILE" + ''; + }; + + # Build *just* the cargo dependencies (of the entire workspace), + # so we can reuse all of that work (e.g. via cachix) when running in CI + # It is *highly* recommended to use something like cargo-hakari to avoid + # cache misses when building individual top-level-crates + cargoArtifacts = craneLib.buildDepsOnly commonArgs; + + individualCrateArgs = + commonArgs + // { + inherit cargoArtifacts; + inherit (craneLib.crateNameFromCargoToml {inherit src;}) version; + # disable tests since we'll run them all via cargo-nextest + doCheck = false; + }; + + fileSetForCrate = crates: lib.fileset.toSource { + root = ./.; + fileset = lib.fileset.unions ([ + ./Cargo.toml + ./Cargo.lock + ] ++ (builtins.map craneLib.fileset.commonCargoSources crates)); + }; + + packages = rec { + inherit cargoArtifacts; + + # Prior to this version, the old code had one derivatino per crate (probe-cli, probe-lib, and probe-macros). + # What could go wrong? + # Since the old version used `src = ./.`, it would rebuild all three if any one changed. + + # craneLib's workspace example [1] says to use `src = fileSetForCrate ./path/to/crate`. + # However, when I tried doing that, it would say "failed to load manifest for workspace member lib" because "failed to read macros/Cargo.toml". + # Because `lib/Cargo.toml` has a dependency on `{path = "../macros"}`, + # I think the source code of both crates have to be present at build-time of lib. + # Which means no source filtering is possible. + # Indeed the exposed packages in craneLib's example (my-cli and my-server) [1] do not depend on each other. + # They depend on my-common, which is *not* filtered out (*is* included) in the `src` for those crates. + # If it's possible to simultaneously: + # - expose two Cargo crates A and B + # - where A depends on B + # - when A changes only A needs to be rebuilt + # then I don't know how to do it. + # Therefore, I will only offer one crate as a Nix package. + # + # https://crane.dev/examples/quick-start-workspace.html + + probe-cli = craneLib.buildPackage (individualCrateArgs + // { + pname = "probe-cli"; + cargoExtraArgs = "-p probe_cli"; + src = fileSetForCrate [ + ./cli + ./lib + ./macros + ]; + }); + + }; + checks = { + probe-workspace-clippy = craneLib.cargoClippy (commonArgs + // { + inherit (packages) cargoArtifacts; + cargoClippyExtraArgs = "--all-targets -- --deny warnings"; + }); + + probe-workspace-doc = craneLib.cargoDoc (commonArgs + // { + inherit (packages) cargoArtifacts; + }); + + # Check formatting + probe-workspace-fmt = craneLib.cargoFmt { + inherit src; + }; + + # Audit dependencies + probe-workspace-audit = craneLib.cargoAudit { + inherit src advisory-db; + }; + + # Audit licenses + probe-workspace-deny = craneLib.cargoDeny { + inherit src; + }; + + # Run tests with cargo-nextest + # this is why `doCheck = false` on the crate derivations, so as to not + # run the tests twice. + probe-workspace-nextest = craneLib.cargoNextest (commonArgs + // { + inherit (packages) cargoArtifacts; + partitions = 1; + partitionType = "count"; + }); + }; +} diff --git a/probe_src/frontend/lib/Cargo.toml b/cli-wrapper/lib/Cargo.toml similarity index 92% rename from probe_src/frontend/lib/Cargo.toml rename to cli-wrapper/lib/Cargo.toml index 90b871e2..692cf5d9 100644 --- a/probe_src/frontend/lib/Cargo.toml +++ b/cli-wrapper/lib/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "probe_frontend" +name = "probe_lib" version.workspace = true license.workspace = true authors.workspace = true @@ -10,7 +10,7 @@ edition.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [lib] -name = "probe_frontend" +name = "probe_lib" path = "src/lib.rs" [dependencies] diff --git a/probe_src/frontend/lib/build.rs b/cli-wrapper/lib/build.rs similarity index 100% rename from probe_src/frontend/lib/build.rs rename to cli-wrapper/lib/build.rs diff --git a/probe_src/frontend/lib/src/error.rs b/cli-wrapper/lib/src/error.rs similarity index 100% rename from probe_src/frontend/lib/src/error.rs rename to cli-wrapper/lib/src/error.rs diff --git a/probe_src/frontend/lib/src/lib.rs b/cli-wrapper/lib/src/lib.rs similarity index 100% rename from probe_src/frontend/lib/src/lib.rs rename to cli-wrapper/lib/src/lib.rs diff --git a/probe_src/frontend/lib/src/metadata.rs b/cli-wrapper/lib/src/metadata.rs similarity index 100% rename from probe_src/frontend/lib/src/metadata.rs rename to cli-wrapper/lib/src/metadata.rs diff --git a/probe_src/frontend/lib/src/ops.rs b/cli-wrapper/lib/src/ops.rs similarity index 100% rename from probe_src/frontend/lib/src/ops.rs rename to cli-wrapper/lib/src/ops.rs diff --git a/probe_src/frontend/lib/src/transcribe.rs b/cli-wrapper/lib/src/transcribe.rs similarity index 100% rename from probe_src/frontend/lib/src/transcribe.rs rename to cli-wrapper/lib/src/transcribe.rs diff --git a/probe_src/frontend/macros/Cargo.toml b/cli-wrapper/macros/Cargo.toml similarity index 100% rename from probe_src/frontend/macros/Cargo.toml rename to cli-wrapper/macros/Cargo.toml diff --git a/probe_src/frontend/macros/src/lib.rs b/cli-wrapper/macros/src/lib.rs similarity index 100% rename from probe_src/frontend/macros/src/lib.rs rename to cli-wrapper/macros/src/lib.rs diff --git a/probe_src/frontend/macros/src/pygen.rs b/cli-wrapper/macros/src/pygen.rs similarity index 100% rename from probe_src/frontend/macros/src/pygen.rs rename to cli-wrapper/macros/src/pygen.rs diff --git a/probe_src/frontend/python/pyproject.toml b/cli-wrapper/pyproject.toml similarity index 100% rename from probe_src/frontend/python/pyproject.toml rename to cli-wrapper/pyproject.toml diff --git a/probe_src/README.md b/docs/developers_readme.md similarity index 97% rename from probe_src/README.md rename to docs/developers_readme.md index fd0c9432..44913ee5 100644 --- a/probe_src/README.md +++ b/docs/developers_readme.md @@ -77,3 +77,9 @@ I don't like replaying libcalls by intercepting and copy/pasting contents of the The entire close of `temp_file` in PID 101 precedes waitpid 101 in fork-join order, waitpid 101 precedes fork 102 in program order, and fork 102 precedess the open of `temp_file` in PID 102, so we can conclude that information may flow from `foo` to `bar`. From which, we can deduce the provenance graph `input_file` -> `foo` -> `temp_file` -> `bar` -> `output_file` with only the open/close intervals and happens-before order. + +# Python package + +probe_py is a package that implements experimental, non-core CLI functions of PROBE and Python library functionality of PROBE. + +Required reading: diff --git a/probe_src/notes.md b/docs/notes.md similarity index 100% rename from probe_src/notes.md rename to docs/notes.md diff --git a/tasks.org b/docs/old_tasks.org similarity index 100% rename from tasks.org rename to docs/old_tasks.org diff --git a/docs/.gitignore b/docs/publications/.gitignore similarity index 100% rename from docs/.gitignore rename to docs/publications/.gitignore diff --git a/docs/acm-rep-pres.html b/docs/publications/acm-rep-pres.html similarity index 100% rename from docs/acm-rep-pres.html rename to docs/publications/acm-rep-pres.html diff --git a/docs/acm-rep-pres.pdf b/docs/publications/acm-rep-pres.pdf similarity index 100% rename from docs/acm-rep-pres.pdf rename to docs/publications/acm-rep-pres.pdf diff --git a/docs/acm-template.tex b/docs/publications/acm-template.tex similarity index 100% rename from docs/acm-template.tex rename to docs/publications/acm-template.tex diff --git a/docs/benchmark_suite/README.md b/docs/publications/benchmark_suite/README.md similarity index 100% rename from docs/benchmark_suite/README.md rename to docs/publications/benchmark_suite/README.md diff --git a/docs/benchmark_suite/README.pdf b/docs/publications/benchmark_suite/README.pdf similarity index 100% rename from docs/benchmark_suite/README.pdf rename to docs/publications/benchmark_suite/README.pdf diff --git a/docs/benchmark_suite/app-lvl-prov.dot b/docs/publications/benchmark_suite/app-lvl-prov.dot similarity index 100% rename from docs/benchmark_suite/app-lvl-prov.dot rename to docs/publications/benchmark_suite/app-lvl-prov.dot diff --git a/docs/benchmark_suite/generated/clustering2.svg b/docs/publications/benchmark_suite/generated/clustering2.svg similarity index 100% rename from docs/benchmark_suite/generated/clustering2.svg rename to docs/publications/benchmark_suite/generated/clustering2.svg diff --git a/docs/benchmark_suite/generated/dendrogram.pdf b/docs/publications/benchmark_suite/generated/dendrogram.pdf similarity index 100% rename from docs/benchmark_suite/generated/dendrogram.pdf rename to docs/publications/benchmark_suite/generated/dendrogram.pdf diff --git a/docs/benchmark_suite/generated/dendrogram.svg b/docs/publications/benchmark_suite/generated/dendrogram.svg similarity index 100% rename from docs/benchmark_suite/generated/dendrogram.svg rename to docs/publications/benchmark_suite/generated/dendrogram.svg diff --git a/docs/benchmark_suite/generated/dendrogram_full.pdf b/docs/publications/benchmark_suite/generated/dendrogram_full.pdf similarity index 100% rename from docs/benchmark_suite/generated/dendrogram_full.pdf rename to docs/publications/benchmark_suite/generated/dendrogram_full.pdf diff --git a/docs/benchmark_suite/generated/log_overhead_hist.svg b/docs/publications/benchmark_suite/generated/log_overhead_hist.svg similarity index 100% rename from docs/benchmark_suite/generated/log_overhead_hist.svg rename to docs/publications/benchmark_suite/generated/log_overhead_hist.svg diff --git a/docs/benchmark_suite/generated/pca0.pdf b/docs/publications/benchmark_suite/generated/pca0.pdf similarity index 100% rename from docs/benchmark_suite/generated/pca0.pdf rename to docs/publications/benchmark_suite/generated/pca0.pdf diff --git a/docs/benchmark_suite/generated/pca1.pdf b/docs/publications/benchmark_suite/generated/pca1.pdf similarity index 100% rename from docs/benchmark_suite/generated/pca1.pdf rename to docs/publications/benchmark_suite/generated/pca1.pdf diff --git a/docs/benchmark_suite/generated/predictive-performance.pdf b/docs/publications/benchmark_suite/generated/predictive-performance.pdf similarity index 100% rename from docs/benchmark_suite/generated/predictive-performance.pdf rename to docs/publications/benchmark_suite/generated/predictive-performance.pdf diff --git a/docs/benchmark_suite/generated/subsetting-accuracy.pdf b/docs/publications/benchmark_suite/generated/subsetting-accuracy.pdf similarity index 100% rename from docs/benchmark_suite/generated/subsetting-accuracy.pdf rename to docs/publications/benchmark_suite/generated/subsetting-accuracy.pdf diff --git a/docs/benchmark_suite/generated/subsetting-dist.pdf b/docs/publications/benchmark_suite/generated/subsetting-dist.pdf similarity index 100% rename from docs/benchmark_suite/generated/subsetting-dist.pdf rename to docs/publications/benchmark_suite/generated/subsetting-dist.pdf diff --git a/docs/benchmark_suite/generated/subsetting.pdf b/docs/publications/benchmark_suite/generated/subsetting.pdf similarity index 100% rename from docs/benchmark_suite/generated/subsetting.pdf rename to docs/publications/benchmark_suite/generated/subsetting.pdf diff --git a/docs/benchmark_suite/prov-example.dot b/docs/publications/benchmark_suite/prov-example.dot similarity index 100% rename from docs/benchmark_suite/prov-example.dot rename to docs/publications/benchmark_suite/prov-example.dot diff --git a/docs/benchmark_suite/prov-example.png b/docs/publications/benchmark_suite/prov-example.png similarity index 100% rename from docs/benchmark_suite/prov-example.png rename to docs/publications/benchmark_suite/prov-example.png diff --git a/docs/benchmark_suite/simple-prov-example.dot b/docs/publications/benchmark_suite/simple-prov-example.dot similarity index 100% rename from docs/benchmark_suite/simple-prov-example.dot rename to docs/publications/benchmark_suite/simple-prov-example.dot diff --git a/docs/benchmark_suite/simple-prov-example.png b/docs/publications/benchmark_suite/simple-prov-example.png similarity index 100% rename from docs/benchmark_suite/simple-prov-example.png rename to docs/publications/benchmark_suite/simple-prov-example.png diff --git a/docs/benchmark_suite/submitted.pdf b/docs/publications/benchmark_suite/submitted.pdf similarity index 100% rename from docs/benchmark_suite/submitted.pdf rename to docs/publications/benchmark_suite/submitted.pdf diff --git a/docs/benchmark_suite/sys-lvl-log.svg b/docs/publications/benchmark_suite/sys-lvl-log.svg similarity index 100% rename from docs/benchmark_suite/sys-lvl-log.svg rename to docs/publications/benchmark_suite/sys-lvl-log.svg diff --git a/docs/benchmark_suite/sys-lvl-prov.dot b/docs/publications/benchmark_suite/sys-lvl-prov.dot similarity index 100% rename from docs/benchmark_suite/sys-lvl-prov.dot rename to docs/publications/benchmark_suite/sys-lvl-prov.dot diff --git a/docs/benchmark_suite/tech_report.md b/docs/publications/benchmark_suite/tech_report.md similarity index 100% rename from docs/benchmark_suite/tech_report.md rename to docs/publications/benchmark_suite/tech_report.md diff --git a/docs/benchmark_suite/wf-lvl-prov.dot b/docs/publications/benchmark_suite/wf-lvl-prov.dot similarity index 100% rename from docs/benchmark_suite/wf-lvl-prov.dot rename to docs/publications/benchmark_suite/wf-lvl-prov.dot diff --git a/docs/citations-to-latex.lua b/docs/publications/citations-to-latex.lua similarity index 100% rename from docs/citations-to-latex.lua rename to docs/publications/citations-to-latex.lua diff --git a/docs/dataflow-graph.png b/docs/publications/dataflow-graph.png similarity index 100% rename from docs/dataflow-graph.png rename to docs/publications/dataflow-graph.png diff --git a/docs/dataflow-graph.svg b/docs/publications/dataflow-graph.svg similarity index 100% rename from docs/dataflow-graph.svg rename to docs/publications/dataflow-graph.svg diff --git a/docs/flake.lock b/docs/publications/flake.lock similarity index 100% rename from docs/flake.lock rename to docs/publications/flake.lock diff --git a/docs/flake.nix b/docs/publications/flake.nix similarity index 100% rename from docs/flake.nix rename to docs/publications/flake.nix diff --git a/docs/illinois.png b/docs/publications/illinois.png similarity index 100% rename from docs/illinois.png rename to docs/publications/illinois.png diff --git a/docs/lit_review/application-level.dot b/docs/publications/lit_review/application-level.dot similarity index 100% rename from docs/lit_review/application-level.dot rename to docs/publications/lit_review/application-level.dot diff --git a/docs/lit_review/datasets.org b/docs/publications/lit_review/datasets.org similarity index 100% rename from docs/lit_review/datasets.org rename to docs/publications/lit_review/datasets.org diff --git a/docs/lit_review/flake.lock b/docs/publications/lit_review/flake.lock similarity index 100% rename from docs/lit_review/flake.lock rename to docs/publications/lit_review/flake.lock diff --git a/docs/lit_review/flake.nix b/docs/publications/lit_review/flake.nix similarity index 100% rename from docs/lit_review/flake.nix rename to docs/publications/lit_review/flake.nix diff --git a/docs/lit_review/index.pdf b/docs/publications/lit_review/index.pdf similarity index 100% rename from docs/lit_review/index.pdf rename to docs/publications/lit_review/index.pdf diff --git a/docs/lit_review/index.tex b/docs/publications/lit_review/index.tex similarity index 100% rename from docs/lit_review/index.tex rename to docs/publications/lit_review/index.tex diff --git a/docs/lit_review/lit_review.md b/docs/publications/lit_review/lit_review.md similarity index 100% rename from docs/lit_review/lit_review.md rename to docs/publications/lit_review/lit_review.md diff --git a/docs/lit_review/lit_review.turtle b/docs/publications/lit_review/lit_review.turtle similarity index 100% rename from docs/lit_review/lit_review.turtle rename to docs/publications/lit_review/lit_review.turtle diff --git a/docs/lit_review/meat.tex b/docs/publications/lit_review/meat.tex similarity index 100% rename from docs/lit_review/meat.tex rename to docs/publications/lit_review/meat.tex diff --git a/docs/lit_review/search.csv b/docs/publications/lit_review/search.csv similarity index 100% rename from docs/lit_review/search.csv rename to docs/publications/lit_review/search.csv diff --git a/docs/lit_review/system-level.dot b/docs/publications/lit_review/system-level.dot similarity index 100% rename from docs/lit_review/system-level.dot rename to docs/publications/lit_review/system-level.dot diff --git a/docs/lit_review/workflow-level.dot b/docs/publications/lit_review/workflow-level.dot similarity index 100% rename from docs/lit_review/workflow-level.dot rename to docs/publications/lit_review/workflow-level.dot diff --git a/docs/low_provenance_overhead/main.md b/docs/publications/low_provenance_overhead/main.md similarity index 100% rename from docs/low_provenance_overhead/main.md rename to docs/publications/low_provenance_overhead/main.md diff --git a/docs/poster/main.svg b/docs/publications/poster/main.svg similarity index 100% rename from docs/poster/main.svg rename to docs/publications/poster/main.svg diff --git a/docs/poster/poster.html b/docs/publications/poster/poster.html similarity index 100% rename from docs/poster/poster.html rename to docs/publications/poster/poster.html diff --git a/docs/poster/poster.pdf b/docs/publications/poster/poster.pdf similarity index 100% rename from docs/poster/poster.pdf rename to docs/publications/poster/poster.pdf diff --git a/docs/poster/poster.scrbl b/docs/publications/poster/poster.scrbl similarity index 100% rename from docs/poster/poster.scrbl rename to docs/publications/poster/poster.scrbl diff --git a/docs/probe-qr.svg b/docs/publications/probe-qr.svg similarity index 100% rename from docs/probe-qr.svg rename to docs/publications/probe-qr.svg diff --git a/docs/prov-example.svg b/docs/publications/prov-example.svg similarity index 100% rename from docs/prov-example.svg rename to docs/publications/prov-example.svg diff --git a/docs/prov_pres/main.md b/docs/publications/prov_pres/main.md similarity index 100% rename from docs/prov_pres/main.md rename to docs/publications/prov_pres/main.md diff --git a/docs/prov_pres/prov_example.dot b/docs/publications/prov_pres/prov_example.dot similarity index 100% rename from docs/prov_pres/prov_example.dot rename to docs/publications/prov_pres/prov_example.dot diff --git a/docs/prov_pres/prov_example.svg b/docs/publications/prov_pres/prov_example.svg similarity index 100% rename from docs/prov_pres/prov_example.svg rename to docs/publications/prov_pres/prov_example.svg diff --git a/docs/record_replay/.gitignore b/docs/publications/record_replay/.gitignore similarity index 100% rename from docs/record_replay/.gitignore rename to docs/publications/record_replay/.gitignore diff --git a/docs/record_replay/main.md b/docs/publications/record_replay/main.md similarity index 100% rename from docs/record_replay/main.md rename to docs/publications/record_replay/main.md diff --git a/docs/record_replay/main.pdf b/docs/publications/record_replay/main.pdf similarity index 100% rename from docs/record_replay/main.pdf rename to docs/publications/record_replay/main.pdf diff --git a/docs/record_replay/old-main.md b/docs/publications/record_replay/old-main.md similarity index 100% rename from docs/record_replay/old-main.md rename to docs/publications/record_replay/old-main.md diff --git a/docs/record_replay/repro_comparison.ods b/docs/publications/record_replay/repro_comparison.ods similarity index 100% rename from docs/record_replay/repro_comparison.ods rename to docs/publications/record_replay/repro_comparison.ods diff --git a/docs/record_replay/zotero.bib b/docs/publications/record_replay/zotero.bib similarity index 100% rename from docs/record_replay/zotero.bib rename to docs/publications/record_replay/zotero.bib diff --git a/docs/reed.bib b/docs/publications/reed.bib similarity index 100% rename from docs/reed.bib rename to docs/publications/reed.bib diff --git a/docs/sandia.svg b/docs/publications/sandia.svg similarity index 100% rename from docs/sandia.svg rename to docs/publications/sandia.svg diff --git a/docs/script.sh b/docs/publications/script.sh similarity index 100% rename from docs/script.sh rename to docs/publications/script.sh diff --git a/docs/supplemental.bib b/docs/publications/supplemental.bib similarity index 100% rename from docs/supplemental.bib rename to docs/publications/supplemental.bib diff --git a/docs/us-rse.html b/docs/publications/us-rse.html similarity index 100% rename from docs/us-rse.html rename to docs/publications/us-rse.html diff --git a/docs/us-rse.pdf b/docs/publications/us-rse.pdf similarity index 100% rename from docs/us-rse.pdf rename to docs/publications/us-rse.pdf diff --git a/docs/why_prov/main.md b/docs/publications/why_prov/main.md similarity index 100% rename from docs/why_prov/main.md rename to docs/publications/why_prov/main.md diff --git a/docs/zotero.bib b/docs/publications/zotero.bib similarity index 100% rename from docs/zotero.bib rename to docs/publications/zotero.bib diff --git a/docs/publications_index.md b/docs/publications_index.md new file mode 100644 index 00000000..6e89e118 --- /dev/null +++ b/docs/publications_index.md @@ -0,0 +1,15 @@ +- Evaluating system-level provenance tools for practical use by Grayson, Milewicz + - 🔓 [fulltext](./publications/lit_review/index.pdf) + +- Trick or Research + - 🔓 [presentation](./publications/prov_pres/main.md) + +- How to collect computational provenance by Grayson, Milewicz, Katz, Marinov + - 🔓 [poster](./publications/poster/poster.pdf) + +- A benchmark suite and performance analysis of user-space provenance collectors by Grayson, Aguilar, Milewicz, Katz, Darko @ ACM REP '24 [10.1145/3641525.3663627](https://doi.org/10.1145/3641525.3663627) + - 🔓 [fulltext](./publications/benchmark_suite/README.pdf) + - 🔓 [slides](./publications/acm-rep-pres.pdf) + +- PROBE4RSE: Provenance Replay/Observation Engine for Research Software Engineers by Grayson, Milewicz, Katz, Marinov @ US-RSE '24 [10.1145/3641525.3663627](https://doi.org/10.1145/3641525.3663627) + - 🔓 [slides](./publications/us-rse.pdf) diff --git a/docs/research_reading_list.md b/docs/research_reading_list.md new file mode 100644 index 00000000..76fd74c1 --- /dev/null +++ b/docs/research_reading_list.md @@ -0,0 +1,27 @@ +## Research reading list + +- [_Provenance for Computational Tasks: A Survey_ by Freire et al. in CiSE '08](https://sci.utah.edu/~csilva/papers/cise2008a.pdf) for an overview of provenance in general. + +- [_Transparent Result Caching_ by Vahdat and Anderson @ USENIX ATC '98](https://www.usenix.org/legacy/publications/library/proceedings/usenix98/full_papers/vahdat/vahdat.pdf) for an early system-level provenance tracer in Solaris using the `/proc` fs. Linux's `/proc` fs doesn't have the same functionality. However, this paper discusses two interesting application of provenance: unmake (query lineage information) and transparent Make (more generally, incremental computation). + +- [_CDE: Using System Call Interposition to Automatically Create Portable Software Packages_ by Guo and Engler @ USENIX ATC '11](https://www.usenix.org/legacy/events/atc11/tech/final_files/GuoEngler.pdf) for an early system-level provenance tracer. Their only application is software execution replay, but replay is quite an important application. + +- [_Techniques for Preserving Scientific Software Executions: Preserve the Mess or Encourage Cleanliness?_ by Thain, Meng, and Ivie @ iPRES 2015 ](https://curate.nd.edu/articles/journal_contribution/Techniques_for_Preserving_Scientific_Software_Executions_Preserve_the_Mess_or_Encourage_Cleanliness_/24824439?file=43664937) discusses whether enabling automatic-replay is actually a good idea. A cursory glance makes PROBE seem more like "preserving the mess", but I think, with some care in the design choices, it actually can be more like "encouraging cleanliness", for example, by having heuristics that help cull/simplify provenance and generating human readable/editable package-manager recipes. + +- [_SoK: History is a Vast Early Warning System: Auditing the Provenance of System Intrusions_ by Inam et al. @ SOSP '23](https://adambates.org/documents/Inam_Oakland23.pdf) see specifically Inam's survey of different possibilities for the "Capture layer", "Reduction layer", and "Infrastructure layer". Although provenance-for-security has different constraints than provenacne for other purposes, the taxonomy that Inam lays out is still useful. PROBE operates by intercepting libc calls, which is essentially a "middleware" in Table I (platform modification, no program modification, no config change, incomplete mediation, not tamperproof, inter-process tracing, etc.). + +- [_System-Level Provenance Tracers_ by me et al. @ ACM REP 2023](./docs/acm-rep-pres.pdf) for a motivation of this work. It surveys prior work, identifies potential gaps, and explains why I think library interposition is a promising path for future research. + +- [_Computational Experiment Comprehension using Provenance Summarization_ by Bufford et al. @ ACM REP 2023](https://dl.acm.org/doi/pdf/10.1145/3641525.3663617) discusses how to implement an interface for querying provenance information. They compare classical graph-based visualization with an interactive LLM in a user-study. + +## Prior art + +- [RR-debugger](https://github.com/rr-debugger/rr) which is much slower, but features more complete capturing, lets you replay but doesn't let you do any other analysis. + +- [Sciunits](https://github.com/depaul-dice/sciunit) which is much slower, more likely to crash, has less complete capturing, lets you replay but doesn't let you do other analysis. + +- [Reprozip](https://www.reprozip.org/) which is much slower and has less complete capturing. + +- [CARE](https://proot-me.github.io/care/) which is much slower, has less complete capturing, and lets you do containerized replay but not unpriveleged native replay and not other analysis. + +- [FSAtrace](https://github.com/jacereda/fsatrace) which is more likely to crash, has less complete capturing, and doesn't have replay or other analyses. diff --git a/probe_src/tasks.md b/docs/tasks.md similarity index 84% rename from probe_src/tasks.md rename to docs/tasks.md index 4bdec56e..95e82366 100644 --- a/probe_src/tasks.md +++ b/docs/tasks.md @@ -26,6 +26,20 @@ Core functionality: - Provenance graph should get stored in user-wide directory. - It should be SQLite. +- [ ] We should record rusage of each process. + - Include: + - Time of start + - Time of stop + - Compute time + - IO + - MaxRSS + - [ ] Render that information somewhere? Maybe generated Makefile or Workflow should print wall time estimate, based on the planned computational steps. + +- [ ] Discuss Windows and MacOS implementation?? + - https://en.wikipedia.org/wiki/DLL_injection#Approaches_on_Microsoft_Windows + - MacOS: `DYLD_INSERT_LIBRARIES="./test.dylib" DYLD_FORCE_FLAT_NAMESPACE=1 prog` + - [Detours: Binary interception of Win32 functions ](https://www.usenix.org/legacy/publications/library/proceedings/usenix-nt99/full_papers/hunt/hunt.pdf) + Core tests: - [x] Write end-to-end-tests. End-to-end test should verify properties of the NetworkX graph returned by `provlog_to_digraph`. - [x] Check generic properties Shofiya and Sam finished this. @@ -59,9 +73,9 @@ Core tests: - [x] Write a CI script that uses Nix to install dependencies and run the Justfiles. - [x] Check (not format) code in Alejandra and Black. - [x] Figure out why tests don't work. - - [ ] Run tests in an Ubuntu Docker container. - - [ ] Run tests in a really old Ubuntu Docker container. - - [ ] Figure out how to intelligently combine Nix checks, Just checks, and GitHub CI checks, so we aren't duplicating checks. + - [x] Run tests in an Ubuntu Docker container. + - [x] Run tests in a really old Ubuntu Docker container. + - [x] Figure out how to intelligently combine Nix checks, Just checks, and GitHub CI checks, so we aren't duplicating checks. - [ ] Clang-analyzer - [x] Write microbenchmarking - [x] Run performance test-cases in two steps: one with just libprobe record and one with just transcription. (3 new CLI entrypoints, described in comments in CLI.py) @@ -69,13 +83,11 @@ Core tests: Downstream applications: - [ ] Should export the PROBE log to the following formats: - - [ ] [OCI image](https://opencontainers.org/) (runnable with Docker) + - [x] [OCI image](https://opencontainers.org/) (runnable with Docker) - [ ] Test that executing this image produces the same stdout, stderr, and files for the tests we already have. - - [ ] Tar-ball intended for chroot - - [ ] Directory - [ ] VM image. - [ ] Test execution again. - - [ ] Research ways to speed up the recording phase. + - [ ] Commented script. Comments would include files in, out, and time taken - [ ] SSH wrapper - [ ] There should be a shell script named `ssh` that calls `./PROBE ssh `. @@ -119,7 +131,6 @@ Design issues: - [ ] Think about in situ transcription and analysis - Think about assumptions in analysis - - Think about front-end and UI/UX Performance issues: - [ ] Have better benchmarks @@ -130,18 +141,22 @@ Performance issues: - [ ] Test high mem - [ ] Put magic bytes in arena - - [ ] Use lock-free implementation of InodeTable -Documentation: -- [ ] Make the CLI better. You shouldn't need to give `-f` to make repeated applications work. You shouldn't need to give `--input`. +- [ ] Put rdtsc performance counters in libprobe to instrument startup and re-exec cost. Write them to disk somehow. Look at the results. + + +Better UI/UX: + +- [ ] Probe -o should support formatted-strings, including: %pid, %iso_datetime, %exe, %host, syntax subject to change. + - PROBE should default to `recording_%exe_%iso_datetime.tar.gz`; that way, you can run probe twice in a row with no error without needing `-f`. It's currently an unexpected pain-point, I think. CARE does something like `something.%pid`, I think. + +- [ ] Make the CLI better. You shouldn't need to give `--input`. - [ ] Document CLI tool. - [ ] Do we need to have a file-extension for probe_log? -- [ ] Combine Python and Rust CLIs. - - [ ] Improve the README. - [ ] Style output with Rich. @@ -149,13 +164,10 @@ Documentation: - [ ] Style output of Rust tool. - [ ] Package for the following platforms: - - [ ] It should be obvious how to build libprobe and probe cli (Rust) with Nix from the README. - - [ ] The repository should be an installable Python package, using the PEP 518 (pyproject.toml). Consider having one Python package with bundled binaries and one without. + - [x] Nix - [ ] PyPI - - [ ] Nix - [ ] Spack - [ ] Guix - - [ ] Docker image (consider whether to publish DockerHub, Quay, GHCR, or somewhere else). - [ ] Statically linked, downloadable binary - Built in CI on each "release" and downloadable from GitHub. @@ -164,10 +176,6 @@ Documentation: - [ ] Explain design decisions Nice to have: -- [ ] Make it easier to get to the debug build of probe cli. - - Build both versions, called `probe` and `probe_dbg`. - - `probe_dbg` should use `libprobe_dbg` - - Get rid of `--debug` - [ ] Don't check in generated code to VCS @@ -176,28 +184,22 @@ Nice to have: - [ ] Add more syscalls - [ ] Add Dup ops and debug `bash -c 'head foo > bar'` (branch add-new-ops). Sam is working on this -- [ ] Add more Ops (see branch add-new-ops) - - [ ] Libprobe should identify which was the "root" process. - [ ] Sort readdir order in record and replay phases. - [ ] Re-enable some of the tests I disabled. -- [ ] Write a FUSE that maps inodes (underlying fs) to inodes (of our choosing). Write an option for replay to use this FUSE. - -- [ ] Link with libbacktrace on `--debug` runs. - - [ ] Refactor some identifiers in codebase. - [ ] `prov_log_process_tree` -> `process_tree` - [ ] `prov_log` -> `probe_log` - [ ] `(pid, ex_id, tid, op_id)` -> `dataclass` - [ ] `digraph`, `process_graph` -> `hb_graph` - - [ ] Format Python with Ruff - - [ ] Use Clang's non-null attribute. - - [ ] Having fewer Python imports (e.g., generated.parser, generated.ops. Maybe we should re-export stuff in `__init__.py` of generated). - [ ] Reformat repository layout + +- [ ] Have `probe` and `probe-dbg`; `probe` load `libprobe.so`; `probe-dbg` loads `libprobe-dbg.so` and possibly `libbacktrace.so`. + +- [ ] Reformat repository layout - [ ] Probably have 1 top-level folder for each language, but make sure all the pieces compose nicely. - [ ] `reproducibility_tests` -> `tests`? - [ ] Move tests to root level? @@ -206,6 +208,10 @@ Nice to have: - [ ] Run pre-commit in GitHub Actions, committing fixes to PR branch +- [ ] We currently assume that coreutils will exist on the local and remote hosts. They might not. In that case, we should excise all invocations of coreutils. We could replace them with subcommands of PROBE, which _are_ guaranteed to exist on hosts that have PROBE. However, that doesn't feel necessary, since ost people _do_ have coreutils. So we will record this issue and do nothing until/unless someone complains. + +- [ ] Write a FUSE that maps inodes (underlying fs) to inodes (of our choosing). Write an option for replay to use this FUSE. + Research tasks: - [ ] Develop user study diff --git a/probe_src/threading.md b/docs/threading.md similarity index 100% rename from probe_src/threading.md rename to docs/threading.md diff --git a/flake.lock b/flake.lock index 4728dbc9..93e064e0 100644 --- a/flake.lock +++ b/flake.lock @@ -17,17 +17,12 @@ } }, "crane": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, "locked": { - "lastModified": 1721842668, - "narHash": "sha256-k3oiD2z2AAwBFLa4+xfU+7G5fisRXfkvrMTCJrjZzXo=", + "lastModified": 1731098351, + "narHash": "sha256-HQkYvKvaLQqNa10KEFGgWHfMAbWBfFp+4cAgkut+NNE=", "owner": "ipetkov", "repo": "crane", - "rev": "529c1a0b1f29f0d78fa3086b8f6a134c71ef3aaf", + "rev": "ef80ead953c1b28316cc3f8613904edc2eb90c28", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index a23e277d..6e380c76 100644 --- a/flake.nix +++ b/flake.nix @@ -58,7 +58,7 @@ p.rust-bin.stable.latest.default.override { targets = [rust-target]; }); - frontend = (import ./probe_src/frontend/frontend.nix) { + frontend = (import ./cli-wrapper/frontend.nix) { inherit system pkgs @@ -71,11 +71,11 @@ }; in rec { packages = rec { - inherit (frontend.packages) cargoArtifacts; + inherit (frontend.packages) cargoArtifacts probe-cli; libprobe = pkgs.stdenv.mkDerivation rec { pname = "libprobe"; version = "0.1.0"; - src = ./probe_src/libprobe; + src = ./libprobe; makeFlags = ["INSTALL_PREFIX=$(out)" "SOURCE_VERSION=${version}"]; buildInputs = [ (pkgs.python312.withPackages (pypkgs: [ @@ -83,57 +83,63 @@ ])) ]; }; - probe-bundled = pkgs.stdenv.mkDerivation rec { - pname = "probe-bundled"; + # probe-bundled = pkgs.stdenv.mkDerivation rec { + # pname = "probe-bundled"; + # version = "0.1.0"; + # dontUnpack = true; + # dontBuild = true; + # nativeBuildInputs = [pkgs.makeWrapper]; + # installPhase = '' + # mkdir $out $out/bin + # makeWrapper \ + # ${frontend.packages.probe-cli}/bin/probe \ + # $out/bin/probe \ + # --set __PROBE_LIB ${libprobe}/lib \ + # --prefix PATH : ${probe-py}/bin \ + # --prefix PATH : ${pkgs.buildah}/bin + # ''; + # }; + probe-py = python.pkgs.buildPythonPackage rec { + pname = "probe_py"; version = "0.1.0"; - dontUnpack = true; - dontBuild = true; - nativeBuildInputs = [pkgs.makeWrapper]; - installPhase = '' - mkdir $out $out/bin - makeWrapper \ - ${frontend.packages.probe-cli}/bin/probe \ - $out/bin/probe \ - --set __PROBE_LIB ${libprobe}/lib \ - --prefix PATH : ${probe-py}/bin \ - --prefix PATH : ${pkgs.buildah}/bin - ''; - }; - probe-py-generated = frontend.packages.probe-py-generated; - probe-py = let - probe-py-manual = python.pkgs.buildPythonPackage rec { - pname = "probe_py.manual"; + pyproject = true; + build-system = [ + python.pkgs.flit-core + ]; + src = pkgs.stdenv.mkDerivation { + src = ./probe_py; + pname = "probe-py-with-pygen-code"; version = "0.1.0"; - pyproject = true; - build-system = [ - python.pkgs.flit-core - ]; - src = ./probe_src/python; - propagatedBuildInputs = [ - frontend.packages.probe-py-generated - python.pkgs.networkx - python.pkgs.pygraphviz - python.pkgs.pydot - python.pkgs.rich - python.pkgs.typer - ]; - nativeCheckInputs = [ - frontend.packages.probe-py-generated - python.pkgs.mypy - pkgs.ruff - ]; - checkPhase = '' - runHook preCheck - #ruff format --check probe_src # TODO: uncomment - ruff check . - python -c 'import probe_py.manual' - mypy --strict --package probe_py.manual - runHook postCheck + buildPhase = "true"; + installPhase = '' + mkdir $out/ + cp --recursive $src/* $out/ + chmod 755 $out/probe_py + cp ${probe-cli}/resources/ops.py $out/probe_py/ ''; }; - in - python.withPackages (pypkgs: [probe-py-manual]); - default = probe-bundled; + propagatedBuildInputs = [ + python.pkgs.networkx + python.pkgs.pygraphviz + python.pkgs.pydot + python.pkgs.rich + python.pkgs.typer + python.pkgs.xdg-base-dirs + ]; + nativeCheckInputs = [ + python.pkgs.mypy + pkgs.ruff + ]; + checkPhase = '' + runHook preCheck + #ruff format --check probe_src # TODO: uncomment + ruff check . + python -c 'import probe_py' + MYPYPATH=$src/mypy_stubs:$MYPYPATH mypy --strict --package probe_py + runHook postCheck + ''; + }; + # default = probe-bundled; }; checks = { inherit @@ -160,7 +166,7 @@ name = "probe-integration-tests"; src = ./probe_src/tests; nativeBuildInputs = [ - packages.probe-bundled + # packages.probe-bundled packages.probe-py pkgs.podman pkgs.docker @@ -179,9 +185,7 @@ popd ''; inputsFrom = [ - frontend.packages.probe-frontend frontend.packages.probe-cli - frontend.packages.probe-macros ]; packages = [ @@ -204,6 +208,7 @@ pypkgs.pytest pypkgs.mypy pypkgs.ipython + pypkgs.xdg-base-dirs # libprobe build time requirement pypkgs.pycparser @@ -231,8 +236,9 @@ ++ pkgs.lib.lists.optional (system != "aarch64-darwin") pkgs.gdb # while xdot isn't marked as linux only, it has a dependency (xvfb-run) that is ++ pkgs.lib.lists.optional (builtins.elem system pkgs.lib.platforms.linux) pkgs.xdot; - }; + }; }; } - ); + ) + ; } diff --git a/libprobe/.gitignore b/libprobe/.gitignore new file mode 100644 index 00000000..3227224f --- /dev/null +++ b/libprobe/.gitignore @@ -0,0 +1,3 @@ +# generated files +build/ +generated/ diff --git a/probe_src/libprobe/Makefile b/libprobe/Makefile similarity index 96% rename from probe_src/libprobe/Makefile rename to libprobe/Makefile index 68b4daeb..58366fb3 100644 --- a/probe_src/libprobe/Makefile +++ b/libprobe/Makefile @@ -19,7 +19,7 @@ build/lib%-dbg.so: $(SOURCE_FILES) $(GENERATED_FILES) gcc $(CFLAGS) $(DBGCFLAGS) -o $@ src/lib.c $(GENERATED_FILES): $(wildcard generator/*) - ./generator/gen_libc_hooks.py + python3 ./generator/gen_libc_hooks.py install: install -D --target-directory $(INSTALL_PREFIX)/lib/ build/lib*.so diff --git a/probe_src/libprobe/README.md b/libprobe/README.md similarity index 100% rename from probe_src/libprobe/README.md rename to libprobe/README.md diff --git a/probe_src/libprobe/arena/.gitignore b/libprobe/arena/.gitignore similarity index 100% rename from probe_src/libprobe/arena/.gitignore rename to libprobe/arena/.gitignore diff --git a/probe_src/libprobe/arena/Makefile b/libprobe/arena/Makefile similarity index 100% rename from probe_src/libprobe/arena/Makefile rename to libprobe/arena/Makefile diff --git a/probe_src/libprobe/arena/README.md b/libprobe/arena/README.md similarity index 100% rename from probe_src/libprobe/arena/README.md rename to libprobe/arena/README.md diff --git a/probe_src/libprobe/arena/include/arena.h b/libprobe/arena/include/arena.h similarity index 100% rename from probe_src/libprobe/arena/include/arena.h rename to libprobe/arena/include/arena.h diff --git a/probe_src/libprobe/arena/parse_arena.py b/libprobe/arena/parse_arena.py similarity index 100% rename from probe_src/libprobe/arena/parse_arena.py rename to libprobe/arena/parse_arena.py diff --git a/probe_src/libprobe/arena/test_arena.c b/libprobe/arena/test_arena.c similarity index 100% rename from probe_src/libprobe/arena/test_arena.c rename to libprobe/arena/test_arena.c diff --git a/probe_src/libprobe/generator/dump_ast.py b/libprobe/generator/dump_ast.py similarity index 100% rename from probe_src/libprobe/generator/dump_ast.py rename to libprobe/generator/dump_ast.py diff --git a/probe_src/libprobe/generator/gen_libc_hooks.py b/libprobe/generator/gen_libc_hooks.py similarity index 100% rename from probe_src/libprobe/generator/gen_libc_hooks.py rename to libprobe/generator/gen_libc_hooks.py diff --git a/probe_src/libprobe/generator/libc_hooks_source.c b/libprobe/generator/libc_hooks_source.c similarity index 100% rename from probe_src/libprobe/generator/libc_hooks_source.c rename to libprobe/generator/libc_hooks_source.c diff --git a/probe_src/libprobe/include/libprobe/prov_ops.h b/libprobe/include/libprobe/prov_ops.h similarity index 100% rename from probe_src/libprobe/include/libprobe/prov_ops.h rename to libprobe/include/libprobe/prov_ops.h diff --git a/probe_src/libprobe/src/fd_table.c b/libprobe/src/fd_table.c similarity index 100% rename from probe_src/libprobe/src/fd_table.c rename to libprobe/src/fd_table.c diff --git a/probe_src/libprobe/src/global_state.c b/libprobe/src/global_state.c similarity index 100% rename from probe_src/libprobe/src/global_state.c rename to libprobe/src/global_state.c diff --git a/probe_src/libprobe/src/inode_table.c b/libprobe/src/inode_table.c similarity index 100% rename from probe_src/libprobe/src/inode_table.c rename to libprobe/src/inode_table.c diff --git a/probe_src/libprobe/src/lib.c b/libprobe/src/lib.c similarity index 100% rename from probe_src/libprobe/src/lib.c rename to libprobe/src/lib.c diff --git a/probe_src/libprobe/src/prov_buffer.c b/libprobe/src/prov_buffer.c similarity index 100% rename from probe_src/libprobe/src/prov_buffer.c rename to libprobe/src/prov_buffer.c diff --git a/probe_src/libprobe/src/prov_enable.c b/libprobe/src/prov_enable.c similarity index 100% rename from probe_src/libprobe/src/prov_enable.c rename to libprobe/src/prov_enable.c diff --git a/probe_src/libprobe/src/prov_ops.c b/libprobe/src/prov_ops.c similarity index 100% rename from probe_src/libprobe/src/prov_ops.c rename to libprobe/src/prov_ops.c diff --git a/probe_src/libprobe/src/util.c b/libprobe/src/util.c similarity index 100% rename from probe_src/libprobe/src/util.c rename to libprobe/src/util.c diff --git a/output.png b/output.png deleted file mode 100644 index ab90c424196afa877dbe41a450cbba1da8d7bf0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1131078 zcmeFZc|4Zi_da@4B+5{x2%%(%Qj`XTL`8)Z2^kttW-FZ@4fa~*SglV_EoLJ>dTq=m??@{eqg_< z4n-}#K~ZbHnHcejlIVmw{$MoIP*T@Y(x0N{&l3I63!g zX>rpj3*7KhEZI{yI=zE+O~;>A-^YK;UXL8z?&#|CW7GBfpSwM4)zz7Vl~n)x(JgT> z%9C0n^54%u6?HY}zaPHJ|I^>&*SpY>uS_Ptc(LNlnKR!xwS4(69_Sut z^DRH1yu6%Ih}=<9QsvO0<-x(hT1G~pw{ESt6A=*`6GLBFS(%WScu6Nw)!JGbUsyLO zA%8U>fMING%;d}&1}`tK$b0w7zI@?TQ&ZctWs6^N@$To(pFer_YzYesOXU6gD(NTF7;dmX1IYT|Y zXR>!QGBP-?MMg%J*3>XF2hiWWdw0{OO}>eViJaMy4<2YJYwq>Z)h&DX2&3s=eoD8y z%`0r(x^;YB$ApiYdmWQ{bnxIoyv{cZ@u&Sq_4R|An+-U*xS}&Nb=^NmN=nLEX^C@M zUAmQ(mDTLHbLY-4EiDyIP26E&Vd*bl`aOE|sA~HP4h{}^havA)ukE~v$q5M- zPK{09gpEv1h5!8dbK~*jG>+Y0o0|`s-inPCymC@DK*4o+G z-RQdjd)Ut+tAzEk(vXyrvLEk1_Wk?!HJGx#zP@_V_3M|cTD1!15I)1dYE@ZtGvDFE zhwYr4E{vU1S6A=t?S1WfQTOqmKMvyI2fzRLA+mn`v$DsIj*g8Jmo{T2Lqb?q3kY<6 z|Gt=wjm_27b^nK=q9V6d0vsILEoH?1dhKU3vHk`}>*Us&Qg|M-cS&wNF-?))Y zLPBEyp+l9GAw2P=;);q!`7HN}iWGM#D&mQZdU|@f`S~$>16k`Myw0CLfA7O(gINA; zHv6M>)YPtU%A7fSwyQo~LtI>(vYVB0dbGp&7X3O~TU%ETj|w~&E4BGC16k*lv}Lwl z=U>|MHiAP)==!Tys)o6C%FH3UE`nROZTmdsFgP%U> z_*2W!aG8;jkyC%e(&FM`zU1u>A3ppp^C;oXi8|GB;R*cy{WRr^wf#FcSC@5O&#AATVSawTw>58zle6=g)cgB)!Z!Cm zz84p__ElwNXL$fiLUQu$-FxO{#`oIUZHjX3TFT4ES7Wpp!|e{HjoQx%7X7NKs_Xlk z+d-kB`wR_N!^}<1&HYMCl@>2vyhdD{3C}2G*rCmWz1um~_o@EehOJw*@J;$BU#;~tp^VzK`W*E=pgURY9+Igm|AO;dB(<}F*IwZuQBoZObR@kLu(n?uCG zG5r-Pc)@+lHs)q#Hy%E`hWW}ZC=kUHO-)VVD18eG3R-(Gw^_%R-N3)^cmH_*K*6b( zJtiiGT|gjoY|IHBuItVE$EsRd?DUHk)jc~Rlqw@~t1jhaj$MC)#H&}YI`Cc!7k~5C z)YNqJ^1C-zv~027Z}LgtobrmDPS<8Z0GOqZ#TpxB7Jf4=hSd#1-r_yqo%5AgA;9JgBM4C9Qxf>#NU!*Tisa^sBK^n zeE89h#1zBy?CiS*nj%)wWJ5?Tg-f^Vso{dpHti_A#4B&b8Rhn4RqA1wsZKT7@Jtjl zGjqD*&%+nmiv< zXo=aoNLk+9o(j!5wi_J-@R~2oi6L2k9{=@ufN5a7-Gf5K#Q<{X@Yj_ri;Jzca1k3-L!f0 zEex^V0dZ2nu7k?H@b$8y$Ar?6BW&i?VU?MdpV(KgUM3(Qkf#BU2=%LBZF9kqT%`3 zAyH}R(})v82$&)SFE z6@2DBi_!$PoLzSILsUv#)U8{Wv(A4O!Ht}qori~qOB)i8)?qQ-t1WF7u3#~`AJ`U` zU0u0e>*UFhVz1e*_y}W_f{O$9$0C8|MN40t$BQN zdZ~sIh(1g#EGuDNFTZ44KajH>p9}jjVY}bPCUyAFpB0aGx^O?(YQ5rQjty6l`}hik zX}odDn{K;egU_CC;`8$jo}Vf)b{c3t*4y77tR1U%6}~X zrtjGZh9(Ld#9P*T{6OS8a^whHTC3wS-%*Cl)ahF%jf?~?4z-0|-#x>Gh*FIuAL$Gf zI`|Xs*-&%m*Bc``ESO_>M1=WBSEYXTg;j=zhUspjXRitD%x+w)E@@jhqIP@o%x1vV zhzK5FQMoX$iLd9Fn3;80MDOpMf5g2(pW^4|hi6&jgIy5oHHXks;4oo4J*}i=hzI5KXlf(CH0K?Iznq~RUzvPQl=#{2ir+l`cOM~6wMIU?pF3eI&Xs+)Sa zF}!K>sb&>DJ)WC4Z|*;EpbUX^r0?0|7}$V<=Tv%YJV7rk1Z7xp0dL8gS1ns6xQiDS zs^Z|V89{3aaC)A`?M6ToZEfvKb+PL0llnb9J&`+{C5dxDtdQ@MPjchkdV%)}n@|`7 z3-=nptk}oTo~;+tjPwPz>im4lC%hSvk_3lkd~!^5bac{#?d*+D>kt$g6n+d2vUW`L z-%}45ZB(#+khbK_$B*o`#nWQ9Zrvi0k8Tm83ET$!`i%lPxN))0br)1sv}@=B)F8kL};z(v{5g zOA(w20A}@Im)mAfFE3f=eqC5C4X=_D|1_@QA8i%N-ig z(9j5Y_UxHHe5S$d%=j<U#L5?~+8_lEl*qE6(B`tpR7l*<0bWZCmg&&7s(KJlJAcP=Y@ zLy|i76J4wENVL_Kty>wX-|ZzrX@!3d7Ii1u91&cxLL|%0!(&lyk?_nnUF)RX(tYhW zg!f)~;x#+*<>k5SRT&5gr40>Zms&YeWFMwA$)9q#zsF~Ho7+!;!r^k3snHL6dSn8T zojxjz_=us+Jw{|<;o;$tb@;wNPs8o|{g=;bn^H~&T)lc#OER48jAwY&M8k=fXG1@J z`n2+7_66*n!cmB3EdVQ)zkh!S%ta6^G$+?bS@{z0 zCKF#0p^+3>$$L$HbD{Tz3kaynlQzoNO|doaZoN7hFEBc;kd%_b<;S>u1%h4|hT#x_ zoH9;_MzCa7J>2f-fBW|BT>I`Tt?|27tUnUP3Ai94C#Q>tF;VrSm<9Q%{2Mpe;Y+Ut zZk>l=?z6B+7#<(zqWqB-FfCusl~yvJ-|!Q^>4Ib8-nw;bd1d9kv4Ivn1qB5rQBl#6 za+ZxjF)<>c_U7j1l`D_z5(c_Jvh=dIDdho~gm3xID}lNS)8-ExI6&`9tpON}mTkgP z27rEbjC%3BQUp z8bzRrli0FlB@!IW%D&q+lXD7qNk(kQQ$w;sLP82Vc35Sy2ovAtG}yWdxi6ciCj}&s z;!<+|;y`oRhYv?mQUD0HZ{Pm9w)V=+n;dXirl(IgSQvdyHL5^jEbQ-_oGgX#HCRx> zP7ik%$W9N+V%#R*_{0fBQqaA75n2OyI59Cn zTMXS=0=zTJ3I1{Z)g-K_C@?cKLw>b38H9yX??<|{q6xk>&(TA9Z;^XQ{uFD*>v3U} z0SI7Qb|CIRE~l-JBB)gSH_l)&7eC0Ra>Re|S$ySfpOCsi}$b zMP#TkTnb|+p|+krso-eO&!2Dc$;}DEUQwlGWy(Je!rc=5ev{kI-u{wGw33xo5?Lk7 zPy_*9kTh*=#)CTlbJ1V$B*-4F!QkE)F>~B(`cmMsk&$&ZlcJ(xo(4&|7S3Z;4NSkk zzB$$5$EKyP&m<)!mG{;%i{M^BMT3<0px>6TuD+3VVijo}Qi>@>vMsk~;nx zL*n3|l)zbjm$@7iln@uU7zu{!NF~omox0E)qr=JYZ2_5?a)py^9t!qdi;07TogrJz zv?%mj!e-V}6F&8K^g~_Z(P!MB0R$53Y+JIea~*nuo1X7FPsZ5y=@}tg5YxNfZ)<B0)0vbQcauzAGiZ?}-^K-T9?2=ZW1yDNE4dEQueRCL9P6~lPB z4uo_QSF)ad9>heNT*n*rkR`bQ5OZ^Jal!hj-E(6{!Je4b#~rX5IC0{Hg2Q*FI|t8% zR10o7d+oRpW0P)5)?k73i5H7W6sQ*RdCno2=n1$E=R|@+mW-T-Vffvdz{5Njiy!7+2k0AVvLqx-mRlK}U^wNykoZjW;D(ss5{Sv0DJURGH zsP_xo(eo(T>7i?00#^N#Is?)OLbWcDT9G*bRNH^IV$oiu7P?;H%hJ3Ia>Fs*oo87bH$aFWKJ zBm1)6*6}q*y1l+34DZB16;3pt2baM}kxUsdc=Gw)L|u`sTaTwm%gC_8QQS9ZsS4${ z2M_Y@-WGK${(p(7wBm=_+A5#U3R-iE}LVu$YggIx-3e*j{VBvnBnA;`3r z@3{Co2!^(6^xc+^pFi7be=8lBj4do&O$`I`R{+lPZ@qvB&Wh}ElV$x{LJfpA9W^#) zb#ZaICaA~Gzk6w)UM! z4M2Sy`0%UX_j}L*LY~8P#$Myc9x8fp!`g`tFgbhn3U)xJAKUIywmp9-uoHdqC36$} zAXt`zCVuyLj}T%K(qsP1moEWG;VSoHt|G^(9g9q^&8hed9oV`N9EBYiUHW< ztl(vCU;gx?DGCf(PMf>N{T7mXty!aFZS(2VCprq8{dm-;N4j1zr;1y#usURdW9!=?I-}8|yS>yVdw|B3y3hZc@y$`b7 z^xV1ipu_h8bmqE^J|!`qjEcy6Sstc=>I_Wv+H2vocosu|bF!!U4@-o}D>4DKv z&$MkfUcK|8Ce3Z~=~O9_@OOTns%pp7NcZcS8WjM1@{(_j>di%W?J^vwUw`VP zMS-XxEL3QZAebV!^P&d5L|sB2T1f>{CZGhr-`iw8`zyX(r*} zPe=AxHkgBonV3N;K}R*E8ntva4@I2>nNRgQCg*=@#Y7Cc9p1NZA4Q!!*+Sm(cj=`? zaPR90y|{9vpZDC%8yd>@qs8dsFf4wcO+Q~>3ZS0kVm}0$1u0a6vVJDn#Uv&5M=#j; z_$;VZ1ON?sPWMD8xcym+Y7fx%hS1%XmX?$+!dz0oE^x+EW1o)DQGne?fBow3Pm&EQ zF801%lG&bYLt!_3wm3Rx+-USpcRV*Q&vNWoR^m)%+(g08rqWW%ccyis@6!^>4ym77 zEu)o}u7~iqM2Vjo_dy(QvTfV7jDPDggklA+nat*%dvL7HLH{Di%k1nbO!+V(Hb22j z*|zOrjmdiEpm)IoN}E_)r({3V@k%w!qetR`;)6+LFjwR@+o)#yV;x-F+)W)--;&-( zgJ`0oP&;EQ8U!i`%_fzC9l8t0v)T`2iS!N@PoA9pw!^8{7n1;6S!Qo{%%O#W-)<_~{YI%;i*l z)$7p4Q3T9{N9}&8bB7=M%x_<|eEA5R=Uygl+s8l-f3bkQcz{|cU%Y)GraveC*)#Lj zTzlRfPU16TeSUzqSJc4?O$+)SqbaCt|WU+2%Cfgp|(2b>!oj#~c$buwHdmG%VaUcqH>HKEnXj2+5fB#7vB z{H7a^EoOx~`T28B&}^K@E>QkGShz4h+XXJcA!1$fWAB**{#UL91Awwn0kSuc}ges9+yc#s_C3FG%vH-Me?=GHiR2xTR-ga10I(cFj$;^QbUom{l@&_Vlcy znAWdfFKbdt^%=q|pH+<0_#Z7mB^eN)xj!I6Z%a;EdR7+KrAwDYgoTv{yb==<*a_lj zn7q0^iv7orA7+THF$f5i&dCXb2eG7^Wlz6m@BH;kD&MJ31huh!N=m-_j~ubhi~_&T zj9|{e&b|iB*8?LD$Db32mo8n}b?;mhM^#l-3=o6JrcGMlyOw%*cn~@@7}-#0$;%&6 zwkH88*SERB) zL+L0LCXg@D>FMk!QPvl$jyHZ}U%7H6V#g978K8du2AlKeL$C?Dx++6*-N%y}Qe$Id z?bWlf`eer^B{8E&9Gd!@jOCQiTmTjrrb)Pl`i#2`DKE}{mbtci`w9>kWyn}iTE2?R z3~6*}MMZbiINrMA+cyDlC(=npd5#{F-`ag!W(hI3G(J8awfemv_4|#So%Z}};XZx( zv5XWkEiTNu^!y;qi%VIoj$lX0;e zi!9iw<<^>&HEJCUKuo;;mqNEKm~qFyQRc7*B6jhLv zUurAz=*H&t=x}*~s#OZAR_)%i(trQ{{fHfBh{2QkkBm{iKfbyd*=$TTvmU7&nM=c_ zPkD`V!IiUuq$0Ti5cS>?@44?Xp@J(hRORExxe2cdP9A0c)w^8TQPLQ!7Yxq6SnRS= zr2{ByYOr7^-D~zDlkg_*zpn416#21D93tSn#?psZY=uMSw`nW98p^-T47&xuXG39O zA*px~Bn#&FR>3Z-N_eI#5KUxdfBg87agxnypt*UPK4)(%(h75AabNPCr2x3D?e?1K zK+&k$f9XmSOG^ottJs-r{4_q=16H14TER%li3HsT1}-6mI?yT|*gUS!OPE$_e*$A5 zjCaNzEAT{;o4}Ks0ue-lG6kD1M!Vzn6|_6H;KkFOe;p^D2W0pqkP(EuFIkuy0x{$V zzNdBFiaJppJ-tALATtDbQUXjhE(*rIyAURKlAC2ZduTd*hG(lz@6c(nYtINr{TEQ2NG8+HqMWz9&x+0v&T5@O{ zancbpGm(qGzg&W?bD?grq`$v^IHzQ8IU+bhpE_331hLEIo@#?8Sa=2RzY3(JjOwSq z|Ki@hKH)WMD1eG8)F3C^j@c~}K^1)-E! zT3gEsM^_(5TrJSCEfzr+1Wb!oPvU^fE9Tf>tIla z2&Cfpb{%zel5L^#ez!Os?okEFqN4kll8MP0dU|?xPELQUM2(S5o%v7r3sUvJaACvY zs9jePfg2hcO22+R!R&;3BZLm_O1S%=12TC7DUuwivKbIfhgc;P1HZq%Oh`?=;^(&r zca7sZNFISS3o3wwMxc5nBp>sCM@hwM4U7xHbCaB$YMOBoJAAKKRc<*lf!<61v<~Sg zQHjdP95xV+Hi%zL$;ik+Xh9Q2O#EKDXU`r`_gy?^`@^gp0yP<>TGlJXG}4dP`Hty|L{WEvn>hp6OcR8$zg1Gg*+#tk%TuIKb- ze|E?bR6y``4h@kkG6ooJcycljyhdx!N-QevWdh)Im4H!x@AZ zLrDU7NRq{=sj1SI7Jg8WsF+@U@PL0C>r?fZ>}>9P_wFH;--n?iyu_6>zI&&MjjxQd z7J>u0HYaDBr>AE}cefvr(A3pw4<22E_r5~gQ&uUu$vXy(>u%n;vvz zTkE|&UKvT{*yuNFAf$w(Bpr`|M^Zt9h8Y)sI>HpKj?%WL_8cx!o6>6k;9{H~XLkDZ z;`8T!i7CR1G|ueYu|oy%BKOJLcYDxz_Q~$&XWw-)(1XQ;! zL%gGT=#Z(22_adLlDf|(5TzfWp7jM7KUj*ytiIk}NdJ=B49J*I9yoASO(~YyRTnuC zw#ZfFC~y}_iMqtPa%{e-z_a03al6UiF<%CcXCOBs5Y!!fLb77X%lA;`VYP_7FEsQ} zQ8z4`L;jy}-#T*Q#67iiT?2z8?tI+#Np7w_vjwWD+Q*IsfW;>tA%uenBjQUpx9#w$ zaU;jd-o-v)&d}90y$diuHa;Hz9MQ79)=Q>c{jC{0Z@bXbMqoiZi7X^Pbkf={r`Xee_$T0o0y;b)*3DR zE|k%5`yX07Xg_P->i`x*t-yS>**;}9x7T|;GJRCT$+}pEJEYPU zed}9}FeYUtPA$1F>U0c@rtB36#v)dq{_V;K+*e<#U1wp^top95OK`%?i(RBZuG;XF zD~A1I`d;~@Uy3$Ndkw3dBg=ks=n=3HCr_(Xa%5Q_PcJuFc13Uu1!843QQ2FaA@Z>6ku6{;sN z$|W03$(zw@`SE=zV?8KNM`fq)lW~alRe^2^Kc}nz-PpIq#n6NMLwSeKf@T>fNvl;= z7b-|mD5%#*%!EE^ev)nDDRQfsJ%#?Ew2%9>mYh?lU{cGy_Lf#eQjL?Y8ULQ@i(l?P z*{i~HbQ6Qvrkk`1k4Q>67eNeTUyv%QSXw5kd1z~M0Esm;Lt&_W{P-2l+nl_OtD^Vr zTSA1&V1!d1t3>;Pq^gP>9|xcjao4nC058k&CieOBW%!)$IuS2$5RAhvywxPMJW2jkFJPOrjb)e*8Fic)z^7?bohdLk(*g zd_?cBUmDfOSWMs$Q3XY{qXLer8+c*EWFp3(&Hsw_I!>o>XQHTu$L)(|_Csl)NLU-H zV!WkXRsHABfrzsP=`mX31d20AA*UqX77A>GO^)ZLVq%h$S>SL(+dnmg?+Z=Q&2RbU z^^2tp&_o;hR18;FS68lCo$JQ8_a8r|x0xIm2km|(Je=$Iz<}xb^DJP-P(&<$_wMxx07ShY*Gk&Xf+KyfR)_&W;K8mA_{wYGM2bgUUYp>6w{#isNRdruLs|Dk>}lvoABcO6#PKuI}17uO#|IjiU(F6xmq@3E%%y zNLN<}Cf~)j&HM+Ht+k=g$Bj|>5{9A*1#tz(AIoaqzD3E24J%22EI?^*b5?TZ`a=+i z5(3<1S~XNhGMv}~#A~;1-;STlA^$D0CpdI=HWukwZ+$!qn7c(FQ}Q%O45nG@bz^K% z4BvjRb^EL8>Taa|`vJcJp-2&z4oYjn86#Kk`1x}Q(4x)ZL)YW``>g<*H6AZ&-0Qsk zVRCZv*mf;1F{I788+nko$I?1BdQGJyCCkArUPVn6IRz^!ns4+XW-&!2f9%z}VU1<$C9*WiJm;kD6b?PP5LCd}`{ z-ChPWp7C*UO6uxMK#?&qG12leh?jA3st)mbcK_vZ!NJU{_js>H9!FBY5fp1;kO>05 z5k_q6%vR((D2qEpXpDWygOY+%?A!FJ%=C06C`Z|$*&rM&O3PQST)`y>WCs6mJge|x zR6|L!3;i(Rk^wbgbSnQO)Eu0guNv7@Hzz{VLd1N3z8{d#1q$=KdUa`(=br;`=*S7^ zL0NSFAaaL8G}UsiF_M-mvFg`Fkn<9yD)txAkdqk)MOUH|Lt1%JL)=^_p{^o?+q?)7}Gym$=wsgV<##*Q{eYt zN(@*+q*z@@gn#x}LS0R|D^NELL@uU+;u4CIk%}H5y+m>)fiDF0$as23j_T_ABT$(& zCLJR_#MM>7*n9d6Cgjd+1bf}0qd@-O3S7+bYX#4#O~_3*K|QDWXa^VSpZ}<||3ua# zKN^8t$(-=5@RCql$eycRO|;sB^?V=~0`b~Hh#?@^O^UpT$N<&3!a93WQy{X%echkW z_0`9JDe>7uIlvEG8c}^CS^m89 zFm!HlP@K1WjxL9c=n^6zq)0p)i^f(!koNhxJyrWTHge;Wo*_R&q~Ga~rjk3Msp{p~ z_vO&J*2R>_Vt%A`S(RZ(HL%-5?;h>cLrTVk$t6lNcxdte7c|zckS+v-g&i&`iOrki zzxCjO6g;Xb7O?W^p$D%Z-P#Av#{cEZm-{s|&i_$(n5Mqv)a2-H3qR=1La-TwAqZLu z?ej<#zikjcduzlEXFMm_O{+R(!FObMPCINknY|23I@h`J&$5m`H1S%mjSOyU-rLLo zQV()RdDto`Ti(Ba-+k5_bzTS+7R^t8@UdDA4^22el$BWa>?z?6^?3%zIM(0D0#As# z$(~_|uDgpS+dg40p4tO5EU&Is?~V)!327D>NIg};3OydUY=R=-3n`nSqm3`m9f3Hx z6YLkb8Vl`(s$FwqpQccpKtz|czW7{Mvh)8Yx88Ms+Ny8%i8a9A2#S`LQbrHX(*&$0c|X2^Ux-9tv)ditA%Z|-FN^{O zGY1t3SP%o8i5pYJ3ARqGnsj(`7Diq`!2eguMmXrk=h?X?31 zx&Xj|&POh7mNezH*MX?bXP99v&+3fPV1TN3CmIa$(?*V&nVAif8AHhU*yv@q@Svls zi=HCVzbe^dEsyAqV9?*uq(Mh5Ub5u;YFLmEWdhGMxq3;5XX37R)AR-tyDdl>?+Kj( zA-%3FTXh)$(fs2RlGN_)0;TPZ&)duTNXL(H80A3Se z$E4zMa0q1kqNyzwQkp~VhfwH*csCHOHm0b95}5?JDES#TcXu;rc}U}t_uRN%q9Ppp zPM5(~Pn7*YWq$0MU#@M<_btO*J=7ckl(I>Sa?@2fWgP)x6lyF#_;z97ayYVTyyenC zG3@UY23n4m5&?b;dY+Ci8Rq(huChca4uP)A2?J9s7`zVSvSrH#J)Xmp@_-U|MIGe9 z-}_Kr5NQ^SOzGmqt;e71Uy9d==z>6?8dj9t?r-b63+<3!UY_~0^ zT+Y9lZEZ#dB#Tj+q6KAQsC}c$c0|8U^;LevTd3QLn;eRHsev zwT9k3P;O9KEl&Ax?J>=>=;b`p4Nc$YhM8TO57VB$*E6(m#ac8!+Kpve_fvAIWT;^3C*;EDshmg-0KXv0$ejvSg8HhAj~P> zsVUdc`J}DK9^W0ah4gJN0cfamsCR!s;n>8=YDQ@=sEM~$?-R@p8tPS5*M+W=Mkycy z8XppOxJ{!MJ9GYsn_C`{Btijr9f9Ij!9(?=?H)xJzU3byAw6DaTB}OW^1_ivm`tKI z&4A<}YrM=JAoTywvGpstDrHtAZ_k~s7_}V$=|xx)>gEeU4jtBDP)$1lQRg7 z9Yi&UxN zxM-F&q^r4|nlG<^pl_kWsVX5Nsb9=Bl`Ax^$ME+9i3a0614`d%+UHd>e5Rgi{^sRnp{bA zt&At@(^*`IXIM~ z<#7b!)BOU^3{Iar*NyI>9veq!lQBC61#6gyz!c*FT{K-)y~G!s#GL};L)g$nty}*T z4Kyf+K-Gp!l59IHM)(gv3KatbzQxMEplp8s{%u@Pf*T>iFIHAUab(TyHw`n;Kax}) z5EJzsa8T}v_O69VKV6IZXSF^N6rHS>Rt4Zpypi*2jCVT=@k1OW2D**@fFS&lo}p-r z!BCms5{uScS;QPabZ#9KAYBKw`!cTv?H7fkAi~uR(4Ta^S@r@2LlbON9d#m{E=^7c zYr**X!v~^6M5ZR}3@JFRSc(!RXuSOb0hlrdWKXw@(bSF-*271S;=@!_<7Dq|wGIZ? z*IMME*DsETY#?ggvH9trLX;A+$+d@Z(RQ$P6otI#wgSE^t)IJIU$|OC*XpL~|d9K5U#FpebNTpT--5qU-LfH+HN@4;emJk^|sMI(}xX@2W z>vfYh@JGka!5dL+caS=$L~9Kztl+p=WkQFnQ0_A7Y7l7!F3eAsOntw7B=<)kBXoO# zI1|Cuxe&cbPXH^^cC`TtXPo;W=!tGiNrtsOn$HN(hWnQMAiH&|8esI4zT0+3EMz!I z*kohFYFp-h9)eB`&Hjdi*{~}h&F;U`qmY%Wzr8DcEc-g2JTuhkDi8&Hci0Yrgpt6_ zzU8C?iuC?^LfHB65cqaJzw^Wns|Yf~Vg#b;8n3WlAh0bRNdO^)V4FIYCCDc{X7)+#mD;-sUId8&R9LgGkI1%`;Y&qVXhsz_wl~rm5ua?mo^K_ZeHB zosW+hX&>Osfqn(pzX&%Gg_k9^?M>^Hm zx+{thysri&R9UuUOCL`&4nwNB$kR1_=tXed?;dYm%P z%}Vj)45BlWXdNkZeXi(lN@1ahB_QuG-g(Z!;g3eopOKNWU@j@Ufo6F)sAxEk$W5m7 z)EZIIMZ_PW8G-QNkcgWA-a}G<%j9v+FU)(&& zTjk_l!8#$FqgQ4plmW@{k&5g?<6Ps+o}%3GZS9_ZhaPM-o&M89;EaB&y_1vYz%{~` zAia|QaUXhJ5FL{5j^PLabSH{}eZ=0Xc#eihoYX+kYC`tgEDQ$z-BhMi%3{W4DY#eg4OJKY)eLhjf&vzhk z1>g=uGcff8IT)DHQcx$d=yT7SKSGq5NMtDr!hGEmytB@V58h%5AdXDg^cgkzn~22T zwFWsh%kvDwP-`F#6Ol6L>eWjq^H3y6x&ED!C5Z=oa4^d?kOJMv$I3ur(e08DcXM+i zeK^qI)3P)Qy6bY_x4I|Fiy&YL3Wz6aGDz~ZS{@Trd*m>Kr(n-+@y9FK*?pmv%NT%G z+e|zAREf7md$Ho#_xA%33k!!W{l?Dj^8U+kHSLpnB^#Rqzn@>CWNUY7kc1rhI z@CIoS1FJxC8`E$zVKr%U50Rrf`umwX-h{`+ja^8^9qAGj^k65)g6|+JvuMtgKujAR z?%WG1L}P=X#5mpdB@)l)M>Pu%e zeMhgt1HEYRv&$(|s3-~5P^%SYyvu!c}ZfH#FpVC>qd;3^l}sR8j>kLsO4fo*XmSb z!jd>?8+imsgJ`MXZp_iy^(E7CCHPvgT5;i|gEg1+wY0PXSUjY7vWgvgn6Vw7#K!u8 zN)2S}5oMUqXV*%4(mH9X_{DO^seD&y9td zxuN;aDkL6Kt8cdv!4Q%7LAeyU)tc|@yGXiwnqtlyQ0MvCC4q|b*zu2zjiix?j1Q*e z>h9jvVp}3T`F2y0(VZ=RfPNH3Y63tY;%C-!p<#J3^}5GlF#|(lD-J;!L1$=4h&54f z1Ak6UwAhliAVP)yPEJXgIj0AFNKsI1>Ug{lKK$7bAOO0Fku;w~p+%4bpHD#>OazD-b8yn2P3-edkX44bb2(Ibyt`aC zp+u;gt-fy`aZg~$UqQnBRkLwZC_}g%o|xd~le3^DBhp6zCK*r#qw_@yN{(D$2KRQXZ}df8%`YKA!PJRnRKrP{ z!2s`$UQlKDpdu3#y{2YnnBg*3&f;JVQ*c<9;cm6kj1|kkkfKD%1sZQ1Nk_q_tC*NP zVdv+UV!FI$m+P?7)NlnGgS51C*_$^9Fom4pL;^@kL@h?jMEJ*Cm!YVGQP8$6MGw;@ zBB#u>s8b;gx_nzNh=U+nilDRNyF*^{ZWst&TF84!8Rs?>z^h5-78I~FH#d`Rz#I4P z&o~INC+VV+pN>dg2HhEs9bktPegm>44FO22dygqLt?+05u?K>jqIJLkr1|47`UW5i zue>91lr%vFpa1YNInVjm-CW*JB0;tof;N~EUeNwFp3)ooEYCVegm=6q5EZps}YJJJD*8L?4(isjt2Z_%l+5u2HMCs2BjdjA)8;;A7pe4!j$y@o8 zV*)T$q=yK-KP(8LB+P>GO0=sp6^YRUcV{=;p*%MDjUV^d&$8ko8>cnjnMLaOb6UKx z;;cm~7Q=`0*qDgin1D$55mXw`{LKknAL+nq7zs)`gl%X4t4SI(eKeZZ(LbOJ9c>yl z5lmFmgkMCt5IO`@bF0B66G=DDAUP;-9b=Xp=0vF}Nr3R;L;(z0ttu+ZILIa#8@027 zZI3Fl>$os=RlY$~C`pfNw#~QTl7)GGlqiS;LF{5gQ(+3PaZpyrCI%YbMV)+9YkuFYh3D6AD zx9z|IN;f%a=^uTRp}Pl?R-(1WnKL6(Bj&(_!U_t!km)PK!A7UNKYxV1Q4YNah^?y7 zP!nd4oZo~a0PQKT(IXvYi%`XQ0w3J_tza7}p!ARxCYqDd?g}!cK~d_{ zXGT%>Bxf1ijEGo*W)R%(L}6pfNj(ff_Yx#FC}@V1RO1W-5Ez#qKYl#5^LI}VaZHJ^ zLeVt(JJ~lO}VQSGpL*xVSgE4@VI_m3^vNmtt3_lkFrjHzZ zhMsix#dJs>iB5rx5da4Y@B;$jcz5eEdOW1=SFX>(Zcs$_Q^Tf29|53>StOEEXowNR zpqO0*!Gm$e)dXf>XmUmx$t+QeCK}-Pm);vs!BZ{HpRYiC-5{Qqn;SIAFK@LN;B8z+OIio% z8vIPqz8ItsA&Xq3SzdpTL&Z=Sm246JU25-5Bo@3E*8PG@C)3iSvaPSJhvx9dZv3Gah zflx$8!3miukM_}@1DBz2p0vmeR1gc+K7^)dQSRGBaD(rUXe{8Xl*2BZAt_sFGC8%}x@hhQ6K-1ktW@>eJI$s<1EZa1?)ki|^TkrlziU zBDG=!U2D_cE6Liy!GW-rD3c-4J60&sg5Zbf@M<15ZSf^t7)`TUPzf`WSF3>3yIe8$ z9F)slNH}n+XBiS8eEme{-1Fxf!n=)gY{>aTWe_$%2|*4HsX-X#ceKV6W19Vl@rmfH zi+GFvsZ01mYl)8#NC2{FQJN3L7!q1PAmY2FLL!XbS0ayU12vKSCpX3#<5@9~arXAx z9sq#o8tL`x)l&xgCXhj*Fp?-B1pW$6jGX?6&_G5`B!b}NAby9KkerK(WNeopcEOk& z&1!lZ-}E>TaRvdv)*GPlBC5jIubEJ|2Jx71^cgGI8=^miG?B2o4Go;w zDVw%!3k(ZmMg6B?M!YfcsJivtYk0M0zFn{)^n^&b2#x;v)9?oaQjv*B&V*vA6ICfI zFLcEc?gYv>(xd{60kH|7PN1O-1W=}VOnqacmyL2QdQDTbPFq;$m)#_@ z_%AzB)t$qwq&CO^Vd%%-&_OR7YK9qKVm9p@TFZ${u6FS!sEZ6|1Unk011muAhcj2x5^EkSE_7KT~+fc z`$6tfYl{lji)Ig&ZT1XJlcg5L1(9mvT6tP=K~?vB{2B%uI}e*Z(iXy8i5AzYjtS8g za`d$uGfs}-Xf#N*+sBgW%bh9tJC;E@bMH=WK)RrW<1{o9WR)e%OTX$gm(AxZTd$bx zmnTj~q<+_~03uJe%F;Yt&U%quYyPq7=GS)oIi?KBR)R{j7ebR$|MyGEw~Tig17}zF<~yeBj0Yl# z)$Dhqp;R21!yvA-NKQ$ZnT}H1q_XveDYfY8Z8E9@Vb9XZpLD*m*G6`?1r9FE|GGX; zN-a3;iH(LER2Q}|`Dq2~+K>Tnlc=rb) z$;Mp}dt;BgCZ5bmHHZdy-SM%>+u<8KfFyi!NXzNXtKe^6RfB;?M>8V@$wVx2{MNe< z9vAg!o8;+rfe~z}R8)ZL-5aXI`(saYaqnAt0PYM9dh~x~8mJagn@L3dX(GSIL zOXlvFW-ZMF72U;=G31~nBB0jLs2~A+Vcx5?z=aL%eq2LR=NRaYFmFQ`$5%-|Q;pY| zk?(!?cGi5|Mds_%r`vY6?GMongYkvDe0pc!Qw)KeM~!o+!G9s%2oia8c=$T*<|yxt zIJ!YMSd-i?Gt(b(6ri2DTzhjln^wZ(t{9YtxfJ!#99&Ed7i!6sIGbB8LqD!i5fs4h z^C-Q8At*zTL#&b9a)umrp>h*4V%L10qScre?pt^Ey2^Sf9%7{;saeU|L8IGJsvO?8{;-d2cw)8S6eEh#RGDD1pfFnL*?UIFA6e zJ@g4dslf`S52sW=)mf|4_LKgDyatT%;H3l8TefdMF|Z|igSfnH+iDa@L5G|%g-1`A zpcSJM#L%Qr0bz|D6v{|KuWq5Ktzp@yr4Wb-sgIeq@5@8Imf&6priAeM*zUbZ<5#k1 z5ZZv{AX)+c5BAEk@3w37tN$r5!4C^toEAI5`%qL5W-^y$3>{MqRmfQ zC3&x~#XtxG-1+3^SDStJ(Pk-|OdtV!Cfw+sKwx;?!)>b*q`%47URl@!K`Y}4q!;8N!?xO0KKUOm02KXmR?gpc zxyEcvo4nZFZT9T;`p&d_R5O9zsgp^-kdE^A+tZ6=CA=+teeZ0bHBp&PW z+o4Xy5U3NMLeGyLI-KeHv;Xvlx!=ahX%+G7Kjb-^sN{g+pr_1VNr=M>>XWAhecUmm4Izml6v`^@{HhhwmB!6nCB zi;GArx7e$qUD;nBo~bt3+r!h-g1}5)CC3Cwqzk)89O!91N$l79Yf*$>k(B~9NG1&4 zZg84wbeLVz&(BZfTKWSE1Q&6|Ae?<Yc1s9m^#_RqSUXS-%r5*qXI=-GFwzlAOT&Xv4dCwPk{@! zG;+kmNPRF-X#lopP_s~Z&*3G={e{l;nl?4cxnSgKPGzXxkA%yDx-2aV(t6BnWXJcb zl2@UP6i=4Nyle1*^1v-rMV`Tf;PXuT)MnYw|hL|j5b#GHXT6=I5+YrQqv@ zh7KO|v>?}WZa^sJxyi;B^y>(XUY7q+nh&(ePu(l$)Oh%qF^eD`WYBYv;}pwRZih*y zPnW<`ZegdeWd>3Y8D8pjZofL_nweMq#FQy`xUpC zpKWco_~m|6C~rCO<|5PpJL*tRxY+7BMfU#)MfXC&^r=hX5D+r?GDmsU8StT|wXnF@ zG1@KuC}CT!@3J5V<>Xk9dDs5(xM`=?8(cseU0MuLasaw;*fbsb{L)t1YV#7NUq8GY z^5vOF?opUJ<;=~8Oxy%mH99sgW zY~lfUEd8O?FVRM~zQJ!!F%1oX6^7 z)4Cwf-RwEwOQ&Cd{max*T@nR=9d#CS6a_%va3c6s2K*@WXV3n_?ih^*D|q_XM#r@M z_BR}p+8`YGom4Q*UZwbV%!3p@ZU z?Czc1Z~N44!J$$4iuIR`{o;X3i_&kaXevtVsSIPL_B6$)sO&$QYb|sQJ^et2TNoae z;Ye)cwx=j&KfBXn`@y~_2%>!qA5Jw1@yiU~vuDrEL+UrPT3&6+{nBm1AV6y2$qbQ5 zx^(I7suO;0;F@s6xs4@2cVdh{zCP&Ifkz8xF$urZ3F|g&Fek-HPSMGyIVLc^LAn+- z?+%|zn~r|t;6z`S^_AZ9mM=kyl^Kz&KnR^V8=)VT1i-<8Z^p~2rjROq-la68+W>xo zL}gQt&!8A`nv^33NAmQSGn_ZTTn({4l#`#PRnEh8lU`vMJob1`y3ygSdhV_>Ex-O{ z0%&qoTkl3S+WPoo=QjLH&TF#$Rc%(Uh3+g@nSf7b)vATDVjeVk(++$rP= z*?tzUaUskD22=$RwR-XF#fu=gKW%?MBQTLFf*zKY$8OHZ*XL}rj4eO);nD#^eXf10 z)SXDe83CKavT}%NGvQHzNeOVE zv|j6vjuR_-!n!H9*0RRh|6bic#c_vK$Qq4`sb2lmEwYKiSQ!Ud)o4KKB^yI!zHQsK zRXQN68uS!&cBtou8{y7OG9AS(4sUXRqHKa<)F#d;QBzoj0?yIEyuCgg)QWg;4;vS2 zal$&C@BYg#CveZ4gHwx$_u@Q(AEtk5ZEGtw`4RlAg5cXMdVv=i2VzIgZWN1ePkn6| zKDfnox_A=?fzst``)9kpLwpk4&%*nnFkFDz=J~3W$kK=;CA*T*JCu&iY*Ralf_xAyt*gMt9 zrH8_f(;+Df9~wC@7zRdX>BNV#3Qs#f%$kM3%j&O53P>q!uMuq~V;7!Ajz8ho_i5J-(uk_-?gX1JqK{^){?h-2-1@ok6 z4q_asO@wsWt#Qew+U@a5V?DLcJ_ul&vXtEVP2+#KI0kGw*;Rkf!{Nh^`_MFit8 zoo!X)t(t$n&v@l>sG38Ih6>?hkH9jAU$E6;d684944*wvDVbDbbgEEEIwYKBr9m+k zz#Z}503r&#y1(+c>kE%^bh6~pWbB)7Im1^?IFGFMRr=fJKCMUp>LTrTnX&4- z;0hlVpS*>QpagUi$M+8hwjSV^In}fBgR^jFl2%k}bE+j^w=qqH-tgNgDYhv4OmY$( zPsUo!ltH)2>nr!#KIYf=6HNogV>xa%_2_7+N zWM2YDal1;dcye_+vU3!adkvDg`|;sQJsmP< zeSWb|T`N&ic5F#-qBgu&WjJbreEvB;aQrK^x8}j(%C$2NXXMugZ$q>XQ&H-O%5a4O zpic(QqHdW_Br49STb4R_KI^{(!s5ByNK?$@v1fCgaFe!V7$Cy`ALRK@nePY$fiEiE z^6HVVd)b1+5YvfA=~f$!y+Z-G9tG_pcVEL5+}?T|HOr%9&Gv(z{yeE4swcu| zpO-D^_R*Y)j4v_QpP-U-_UwxTB}yDVm182?UNz;)&K<5XHRw6ITqhNR<3NNRJI4V}P(TIgS8piSyw5V9} zM;58qMZy;iWRhhhhgesG>H8p$DtU>epGs+>6dSHvRD6k16`anx(q$y6xl1N3t6ZN4 zZK&l+Sv>N{1mj-L$=Vz>!Z40qP-3T`ZLrpKwo>oFE?#Eb&w-pOtwH40vj99vNRjju z0xnVP?DqifdzhG*IDc}sS?o@?l4wxKLboQQH1qG!q?w`aGd$pgaj4fDY0_S^|gTLW3QKW9lSl zI9Q0w)0`YEpxPXPK_<5@`dFNIN9n`^DfsOi6_LL3Ypo{|eQSOWK_QRi|EoAJ7b`M) zO}1ea;{0)WAnz2+(ZvuDXh80BT!KDwaUGcG^9JmjxFN0Crk&fK7wInbkbpIgvAj!~ zE-Y_jBJ^mgOc{Q7%%yEXX-<)AFw;$1WhZq`q`CpJ&;W6o|vR;GJ0?Hn^pB84E9% zO`nW8Abf52#C#rodR;4Xu_Q;ZrrFJ$nP9vUQ{F4-7}iH4(?lTC-Bn_U7qzAsi6k&q z&$qLr==*B67ZZij|9F+0#sfUd@oT^s-+K?Cr!oD;GgYFXX%(YJks;C_fIZaM*eV_) z=QLy8m@Z(v4sp@cd$(HztYFZ9TF@1UJXKqaDXS4p@slBIh!nQI{VX%mnlTr*79+PW z2!t5hoBH6tY6`4NV@I4UFBbT@bEV1k7wp@&Z|i3}n@#`xW6SrS$9p$O1Z2Qotwlky zIQf-zjPLKeXO8RVM-BQf>v`5H#Y2-xLT-U4Ab%vBW3F%T5aKiMr$7gdVCm^`U_?XmN(pn#CIL!_cE}DlHgpThJ={@Gc z=6wD?cJbyqJ0|Oec5ectZ}OS`)-94Qf{B5iA8sB(5@&V3SkaK7`f?9e!jS^jjn%AGT{iF%cLoiIiuvX$6qBSC0e?qaU%fC=}BRdqX;WtBSd{u>Fl(0C+e7?4z}!4qGaN+qK$0JKE!L4duv%%hXt^UKBS) z!t*mpVSX1%hpP^U?Ui4)(4%hEElhemU1Lv#TX2XH60k4ziT-QJ}a zg_8#TIk^B@%?!%R5w-wLkpIC{bhS=?%jw|79s{(5!#_ITj@66}>WVzc<-09uk0~FUT?< z?B&W;Iml;+HA;`I*>5T$j7dHW9vGm0ZqSjw*oQd`m%Ru$b|vc}z3lt_aO=>lAIPJR zK=G8&&fe0XoNsLgBjdu>?iB=6(Ir~Zru5kTAU~N1rUlLt>W1Rx0!9f8w_{7<%C&Jd zvmc5^N=n5jk>WDmQ~6cUG{wkFw+J|vj7C!9%MrDGuhSyN@@w10%2lflxZ9@l+9-~* z#A+ZI=tGY%6w#u|ee%7n`HVKgS!cLOm=58LUjvoxaxxdE_@@{G$z=ujIieQYc1V*PJ-{dGwEVOIDYEY;_}S1wqKF&vKRRa@$owi@Xx( zHL8x6e>`r_2>B=@8yP+HwGC)?Pq@Cv4!Y>Ch@9c*I8ebw_E3A6DxBzxaZq(w#1X+< z@;|?IlJ+$Z*^bl!kiNmR^={g*T8b!GPTl%OK__D#aRJ$?Hrr>+Zr^}3AOoVOJ=Jp$ zbiY>8M*o&|d&tZzPNTGq9;>omP>UUpZFsQPpFeeZe%Skk8z!({gGOzBL+cyZHFZy9 z{J8ZE%uN(>qMxzBE8bu@!eZ1B%9_~O-RLUl?&2*f^oh@!Kr55bVf7-Dv;Ouz+Sc@M zkp5ta`=#sO%c3+@gza;bBLLpAk;Yp}pnJddqT_Pa4l zUKmJO)OjH)8T^Vo0?|bu8aSPah|0NPEM%ZbSlz}sh*#E*PULVZ8s}~eT&I5wuF-A@ z2yXFBZxdcjI!d;%gq%REQ>)}UraaSF4zls%C^c6-Y!I@1c{xd6iDdB;*od;gH3}FF zXhENlA)gRpm`&a2cJir#Q=g9@lI)+aK;F6?Y_t<@7w7ys3b$G_Z-z3+hBKB&J6QuO ziq7?C{dqjC|KMWUOpz1|K*6gVtp>#;`?7Ffm=K8I=E5c*H(p-i+#x%GjrbS{sf+E^WX*78APF+>Xh?2Knr1S>6ptkB8i=*k9&YC9Thj-thi*^wB~6tmomX+YGj8Sj2O zM5QC)kO-f@-ktmN-(BmisNJT`!HX~Wlw0oj2d+O2D&o7wm%Q>TYJ_l~xh#&Xk`?qLd!>(*w zLN*{NmE8Mv265sIFqk&hOVtGP-6`k<_Qd1#omJEUri4Cn`EviK112TH%gyAFLj|<< zs;IN%_G&~i!Ez3Jh;6UAR2a9#H=}rzlukawfBZbzLOlZDtBel0AIoSOBPpstJoMQT z^KqV0%$J@#%Y4Fw31hOEvy9Qb}w~9#HllqI5 z<7&O((Z`J`k6Lg4^FaGUcd}slm*VBb0>NRJfKdBcg!>?q{M-xLjcFRP63dS*C;pms z_rF|#3DntwoPM84rkT&wtXZ?5gEi8v5t8yM_fLIP8i0dtNMmo_LwJ=sWS;RIiE&5S zECs0|1*gSao$QuCOe`zb@8s@orui*2ddMbrPM*pC<~PA0FJ%)< z2NXqDakBn(&#&s_GL_}U_Z$A4lcyj|j@rzphUOW>E+KwCDkFGOuxMlgprjGOklg6FD zw01+=>CR$Jslfqw(D^wqg1vQSu@7o&Rvybbq@NE#R?|&iX%LO?^fKuJ#*LAb-XF#ch|l({89A2+fkEm(pRM_PGOs~+sc^a*d@&bK_=|P(sgvQ zN>kYT@7?=;>f6Mq)>9uQfufu%N&Fa>wmpmk%rxf9(waM}%$ne_P@54D%%)||w}!C3 zaD+xYx_{tL@ht%wH6a(W_7ZlW+~G)%E7%J6cf4!(;>WgV(E=rWKDr~r(7ZF~xUD8# zpi^389^GZRgXPaO!&#AaZ2M#I3F~VM^$gsoo$uBwXW<--OW{+r0^kNQaPzraCiYde zmpdReVJyucme)OSx#aDeW-pXAge=(z1@CXp>=niZg^Y0OxYjuaD`2GKrHzy# z16Rk!x@X6)@;cRS8Q8>pemMinn)8YMr%kiLSjg<%=Zm@WX1{&=wgc@G0+!c{6-@F; zyZD#!h9(j9+aKgxNJ|cjpiA!kovSTqXi&CMs;@Hd%NN7s3cHRzz?EfZQI8WIk87B|az?F>IXRmt-7u=~`V~m58Vl}u`zIf<*fCBIJ_<5g zN5nUd@U6Wn4Unp6r-oFCPhT@PrwCFY=}45m94D_#4zBk>t^gn|N6(%6#k(h}CK^td zn#i~x3fYK9P^-}EI%k@(kH~A2U>`BEy%ijb!zVsM0K&kl2w>R?^Gm6zN9gHGiOqD8 z{7?~&(e*c5)w_p_OZ~0EB0!Qt8yy754anoO>v0JHf)SjbYk*%HPa{v7=7B(k?Z$IMfLc8;u4e1QE|}E5?BpB>|j_JRQ50Wm5!Fn7SEpiGh~oi%A8= zQcOR1PK_cKXePc{M@R%lq^t-HeMK8{C~#5y>=3kG?EGSqWz*oH-*NfzOcS{9Qofu_ zZ>g}4lIx}ND!Xo4GpbLYKK{&Ymcoeqy45|G8E~wM0|j&=CEK#8Ktj&A8!LGa3-EI2 z+IUCk?KNArWR5$VcJTo-Q^0SiRpzW-Ew2L6CH|sp2=5;t$KCiga9uh%I26Ulrw{-a zdyhJA;kxlxd%htrK>-DD!TbJES*wQPFomAwsgWS~u5 z5FC7NYKl9DEp}nj%&mAdrWA`ZmKFeCRXqq*4oa76 zt;z=YIrL4 z{QOxCsYfuodx^QEf(K%CYV2(cAClC0E;clX$Td6(qpkhP=WEptU*qcT9?VB+GPB@j zA`nJc9-89j*$omv`4T0_ewg9};Z1&=C=QkDij#l|hg7@XEiAn1{r>Xi5yFzN8-P38oNwsHD&q_P7N)WJ1{=25c4N=C~D9p zA0Z1F^mL02ikiDlL5nCymcX~Sn{qQafRD;4mH-Dhj9~inftr55*uTk=D)aBrWi;EK z>RgEc1(grJi8(t&9mJ2AF7eLIX-8V>h;)E=XT+0VO*9zS6gSGE3pTS%o6%UinrQtu2e@ zmtaf+b7uI|NBF{4fJ9UXW&s}Li_K{*M%EoFntb+8+Sf`dAkeZCQ7s;&-vi@Atnk&{ z?Jdd|%*TI;R|;sYK^MvcD8&(3-+!2+bS_v6K6U33UYQ1G3d+Z_NCgCYOM*SLM_lP_ zM~mgPU=l*hIYPvk3{OlXMc8FrYCip%tL6B9Za-dXc=s7Bd-XvyP7M`P7*p0U6)CPt0jHN(5#Qn~D;_LzUqi~A$%2!GFAZ z%05l`6DUR50}<}zA%=J*2Y0vpol;25VwntJdy8XE8`A8NBcF=|f*v(i^3r&3;|A9b z>e8iE^Z7gbU62$t@!3_rMoon$`=FZy~w*6ppm1XHUJHZNAwscAa^oIu@noRd39Auay(P&@x4wA*Y`>@ zlO-xD&6YPZuSM9AxMBob6FG+rA+N=-$oi0Y+O~;rs)jGxXL{|=uW%OA#VTL|yc^dj zzPgQ9MZpPEycFoV80*JvC%Fh<&Xt^bvpqd6$Z(37`Y_dM$Bwblo;wh1tdC7Q(cMyA zrz<%Jx^rP@+KMJ7D2P8wwL&lCbL*dw^C52dSIW}IHb#_4y9|I>r$K`q{bPS)+nRa@ z*2N%&)@>M9jkA6-oWY#Sv;5a~;-?5iL8EsDkV#+;hgskx^f zf_-m*h<}SmAn!E`=rnQS?(yqs_62!9iK*KcE@zj75}{Un;NR6lXX8}h(6YaWM@^o6 zXyQVZd{~)MVVWvasvz`HkPbglze$sce=WriU`0?m!xHAqkxht9%CBV}JmlK9Z-v*p z-8K?p)eD6<#Wa9l67O{Id9}H#T^g84VaLO8B^LR(>J8=3yQZrv7RC)%s1=X#DJ>;o zHsJO29p{)i?KNR+!` zv%uOw!@7u6{8}b3i7;7Q1wv|e*zHmpU2XdQ)e9CB{w_P`2nu7T#=Y4M!#!@~!kZYx z5yHwDr=wT<-W%IeC6rmVVZ)HoC$oV+busXKE+%<3OX_LDYCedax)~FNhO1iG*kFKP zK&36N<4ktqW=Mhxn>04vfDASq4F2kZ3FP?Rn-2!_Ziv>K!^88_#Y9;^OknHna;l2L za{ui+ov9X9dwkj%7B(z;io>TwTmwc!9w_HD)!4Z9Z=&H5!sFt1R<3fqc&!beJMCOX zzK!RWL@|sCC&%Y?9zL_$y7fUwzXxeOHka?ydb@?~`|-u3X{eZl0%lZ88{<9&O*gZx7U^1~0dKkrCp`wL4vE;$#2PS3|yf(rJf`T_s|P=Z}Pq zynj9#ho_z)2kCJgqkJGwJiyeH9>^wKsFC)Y(}7;i z`w7>ppRubH^|YPG;vQ#?tRKbv18%@?zcC8t`kvzbHaBmxrD&IF8?VeMJ!M&ekrU0O z^qf#-&0ku&H?|dbIdi;cWT*IZQ{OfXdBC4B5yuFuOvDMg7TK{&bY`VU{~z0SQG#M` z>GA!-ZHrkxp4;SKyI+Dbhon~eeR7rJeabd4w3dT2gb!I*bgA#za@3UpC-?-PW9y77 zm&^O*qNa>u=gm%E-9J-$(8u5J^>OaIu9HSsR4@%KIee>y%YA*E{ggR*Q*gFE99E;> zw_Ly5uPWPW&n>^1QBo;$cc7Tv}y6rb0|wk-f^@n z&pG>V4cGqt;WZCzgNua7~xiE!IA}iTwGRdxRjPQKkiNLx0k)h+LtWpy>CT7 zYJO6O=j#c*ib6Yg-q_R1kl2-BT|UH?yVQ@$;s!>&vBF{zOk`s(SkVlKjZEI0tb#gfW=Xhds4F^%a*7K{rUw! zGuLx=eA#TPpCx8kp?LPeBGVln_un{3>7d5QK#MwQ6?_TdMFMp))zLENthJa}#*tJYB zGQJp-hCTZGcMojxBo@OBw=REVKa1hQn&d;jl$!VSlDhm0v&b|FQ4&x3<&}o&{q$P2 zZcGKT?LcPc9;fuBpXrp@5XFvUTy(mffMPORlin;KChN=U{QJOhZWH|M@#8&DB0Mfm zks_9fZ}0}~kkbTZMI;aAM8l=itE~r9PUuaFiL6OOjI97nJbeh3qSNpO67o9L$vYXZ zbHt$ZxaIa>S@vhz!zbTYV}PdSl#J}s1(}wVd0^JRy}0hu(zYva@%}$v8%Rq>{GG5h z`65U7xQa7rrUHKydiC3%7$)2r5pdDNaT~qj^gm*aW8GM{69(aWPKQA9KNJNB8*Ag! zO?eUb)sG2lUS~b0zjuUQbN`>sCm4yddtX`dD0}KPQ%90%@M7Uo^7TZ4TeAAkW%=Zo z*cMvi*DL0I0F9YHchz44?twuPydatQu&C6p0qtC|su1~D+}wZ3YoF(&m88!yBEZ?x zGyM7Jh(nvoaaC->J;AXXX*P{p2jiO2y?CCO+DPC+$)`K!yE5lt_1PxNSDP+cpKB8K zi6OOh$N~G;?>>6xt%T`)`!{-rL<~;?k%^!u2ZJ)n56rV0*1X}{jwxV9)@4>qCz3;5 z9AXOW&k>_WoniQf+<@W6w07d*XPvyFCxSR~648u)M=0WtR_rs#W zXBa{}#Z3XE2g=-`&k#FQgVcqD(9y@|XBAp>QCU&U;gV>`n0OjKKD|wZ@j5IiHJ$*CPuIoGa)!^oR-rO(t=|h&(IKV&*i(KyLv*^`t#U8c!=Er$%8yi^loUny~qZ9QJ;pd)&vkEgLaCQT|svPLBvKY%nA-2BA%dR#-G;mN2TNAIEfln0qt@z%?$c(Ivlpg9>p zwyKaxHmg$Dfc`d}_Ou@axIpvek?F*Hc=aaX!Z@x94&svo7A`CTySt2yjZI#W|C@0| zcXc)(+nR_8Lf}c1=ioTa$2T2*qNKvn^F{U(z(RkQrL6>RbTQ1#%p|UZU;!ZT@5qU~ zcucKN1i4!eKu@kd`7$ZP8qtWZb>ZGtHwoH~#$2;hIFmqjUmf z^(SbDulcl2(fm~BqPAwTY$@iCfC0zC)Dpu8?8+Ut3lUv}NO3H{W>dG+ zado33%m_ZtXW3iE7@Oy-3-~=y+CsX47HnwbIs=e(VBcAYe4B6RRG|Tj9n@TNR;k!a znzblOC*}D1)>HStZpoVKW!%x$iFXbKaUdO|6~bzes!Z%xA(30krH*?K>?P|kwVjbI z31w63f)HcCexXH-iy-w2##ZzQ&@R+LAK2nzNy=mE`561OGm=BlDVEZeLT3SdFuB7S zeKyi3ho0Xv{_>7QNUb4esw4Uy%Av%xo)m2FPrO+a8T3=rrb)0U1!b`e$bjU+E3S$9 zn0#SU(FJ;8@vS*rMQa5B5Ll(rQ=kI+W}FXtUsE=#?}i_xjty1_`)oK^gJdv_=eqiu z6Jf2nvP-9Rn!H9YCh5+dnlQhQL!-HS@1BKsBU49E1nNt)i+{8^KYHZI+BP=vN5+X; zM}0SY$FnOBsN?rDNQv|K0?Xg+(Qr>s`Y3%KO{GU0jJz~``fe&e4wz*QmNFe%y}JLr z*6zQ}oW(FS9h)?dIHSS=U9G2?`)9d!UiY}uFDZC_qY@~c2w zv0&Z05xyxeuEusYUC6isS=#;6CqI||{p)c8_c7HPfAz1hbIkyc-;El0V9Lno*SaE` zuMpe+2pvLn998HY3azYNr%vXolvX1EaOc8|(VjU1)#3sjmT#{^{1PtM6r7WF<=O1R zl4XKQ7w1)0B<*2F?YJ;1=eY#Jzka>jiGe0DsWB&?SuA&$&vqz58c>Co7=VRxZ!*5H ztFcN0_x*V4tW#etfG{S|BScN%Jpsc8u&y&{InRxYoB8EY7GSZKW-~$*OqyC;`p9d| z<2`U-`i4jBO1ucOT@QZyTYW~>`lH|Cv0r#Z@&KPjr)sC~^z|Ev}yPF;jeX;EE|{cD|V0 zuLnWDG{Qx$wtVQauYZ4{W1m4oqcbEZLigJ*Rqoq3_vw=)jQ8Qg1vE4=PFo*7j&fLr z$_a1J+4cbxvZ+amIj+vcIlT95Uyjyd^s~zIX5~5E8$h|dt#e~W)*X;amg-ml-tmqp(Ri>M! zq8vjrpS*qtueY2|Qb4o)ms`_~v%|cCJaueZyH{U*pH4gEfzFfPThWI!_t{`NaNJv= zFiu#f4;Kb=PRvJ7RE&h7f`Tvdz$J!$X`0W`Ubz29x}1a&PXmvWQ|18{&6<^itv81t zbT!rM8na43Sj}v_(eEKH<6XieEl$T4R^PXX7;6@AVg3t#Q0(n?lij;=bop=pd&;*S zzPq+=y&sWsg;@>Fp^XRZ+&M0KD#V*^L{>2KA0`)>d3dY)qtBY+1YsuZ+@C#Y<54H9 zTvu(rvw54}6plz0=FwU?0yv4rwj1W6S5p-~Dhl!Ovf+>nM7eX9ZSu2kc71*_eXCz& z+0(aC+qMalTYbu(Gux)^w=Q+-)w8g%sl*nHU(#y& zFyy_k8t?Jpva{rv62zU?ajK?_A?==c_$cKSKIyHNt69@yoZp|9y;!&q`{tvHYUuF{ zDxI7pX`q2i1$1rq2tFJW#HE^;(|tufW?dBFz_KH=4Vug?ss%y$Da8un+q)clQVFn| zHO>X5V?uV$C!oy&CLlEDXX~>+a)f%NCAKVd$RlVC!CpQiJ7W&vDqEo`cC4J2j{
L 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