diff --git a/README.md b/README.md index ced77cb..c976dc3 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,90 @@ -# Evil nKode +# Evilnkode Project -Simulated nKode Cracker +This README provides instructions for setting up and running the `evilnkode` project using Conda, activating the environment, and executing the provided CLI scripts. It also covers how to access help for command-line options. -## Installation +## Prerequisites -- Python version 3.10 or greater is required -- Install anaconda (or your preferred tool for environment management) +- **Conda**: Ensure you have Conda installed (Miniconda or Anaconda). Download from [conda.io](https://conda.io). + +## Setting Up the Environment + +To set up the project environment using the provided `environment.yaml` file, follow these steps: + +1. **Install the environment**: + - Ensure you are in the project root directory where `environment.yaml` is located. + - Run the following command to create the `evilnkode` environment: + ```bash + conda env create -f environment.yaml + ``` + - This will install all dependencies specified in `environment.yaml`. + +## Activating the Environment + +To activate the `evilnkode` environment, run: -### Using conda ```bash -conda env create -f environment.yml -conda activate pynkode +conda activate evilnkode ``` -## Starting a Jupyter Notebook +Once activated, your terminal prompt should change to include `(evilnkode)`, indicating the environment is active. + +## Running CLI Scripts + +The project includes two main CLI scripts: `cli.visualnkode` and `cli.benchmark_histogram`. Below are instructions to run each. + +### Running `cli.visualnkode` + +To execute the `visualnkode` CLI script: -### Option 1: Using classic Jupyter Notebook ```bash -# Ensure your environment is activated -# For conda: conda activate pynkode -# For pyenv: (should be automatic if in the directory) - -# Start the Jupyter Notebook server -jupyter notebook +python -m cli.visualnkode ``` -### Option 2: Using JupyterLab +- This command runs the `visualnkode` module from the `cli` package. +- To view available options and arguments, use the `-help` flag: + ```bash + python -m cli.visualnkode -help + ``` + +### Running `cli.benchmark_histogram` + +To execute the `benchmark_histogram` CLI script: + ```bash -# Ensure your environment is activated -# Start JupyterLab -jupyter lab +python -m cli.benchmark_histogram ``` -## Notebooks -- [evilnkode](notebooks/evilnkode.ipynb) +- This command runs the `benchmark_histogram` module, which may generate output such as benchmark results or histograms. For example, it might produce output like: + ``` + File exists: output/slidingtowershufflekeypad-6-8-4-5-4-4-10000/benchmark/slidingtowershufflekeypad-6-8-4-5-4-4-10000.pkl + Bench SlidingTowerShuffle Break 5 + Bench SlidingTowerShuffle Replay 5 + ``` +- To view available options and arguments, use the `-help` flag: + ```bash + python -m cli.benchmark_histogram -help + ``` + +## Using the `-help` Flag + +Both CLI scripts (`cli.visualnkode` and `cli.benchmark_histogram`) support a `-help` flag to display available command-line options and their descriptions. Run the following to explore options for each script: + +```bash +python -m cli.visualnkode -help +python -m cli.benchmark_histogram -help +``` + +This will provide detailed information about parameters, flags, and usage for each script. + +## Project Structure + +Key files and directories in the project: + +- `environment.yaml`: Conda environment configuration file. +- `cli/`: Contains CLI scripts (`visualnkode` and `benchmark_histogram`). +- `output/`: Directory where script outputs, such as benchmark results, are stored. +- `src/`: Source code for the project. +- `tests/`: Test scripts for the project. +- `requirements.txt`: Additional dependencies (if needed outside Conda). + +For further details, explore the project documentation in the `docs/` directory. diff --git a/cli/__init__.py b/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli/benchmark_histogram.py b/cli/benchmark_histogram.py new file mode 100644 index 0000000..2c1c5f7 --- /dev/null +++ b/cli/benchmark_histogram.py @@ -0,0 +1,115 @@ +import argparse +from src.benchmark import benchmark +import matplotlib.pyplot as plt +from pathlib import Path +from statistics import mean +from src.keypad.keypad import ( + RandomSplitShuffleKeypad, + RandomShuffleKeypad, + SlidingSplitShuffleKeypad, + SlidingTowerShuffleKeypad, +) + + +def bench_histogram(data, title, number_of_keys, properties_per_key, passcode_len, max_tries_before_lockout, complexity, + disparity, run_count, save_path: Path = None): + min_val = min(data) + max_val = max(data) + bins = range(min_val, max_val + 2) + plt.hist(data, bins=bins, edgecolor='black') + plt.title(title) + plt.xlabel('# of Login Observations') + plt.ylabel('Simulations') + text = (f"number_of_keys={number_of_keys}\n" + f"properties_per_key={properties_per_key}\n" + f"passcode_len={passcode_len}\n" + f"max_tries_before_lockout={max_tries_before_lockout}\n" + f"complexity={complexity}\n" + f"disparity={disparity}\n" + f"run_count={run_count}") + plt.text(0.95, 0.95, text, transform=plt.gca().transAxes, fontsize=10, + verticalalignment='top', horizontalalignment='right', bbox=dict(facecolor='white', alpha=0.5)) + if save_path: + save_path = save_path / "histogram" + save_path.mkdir(parents=True, exist_ok=True) + filename = (f"{title.replace(' ', '_')}_keys{number_of_keys}_" + f"props{properties_per_key}_pass{passcode_len}_tries{max_tries_before_lockout}_" + f"comp{complexity}_disp{disparity}_runs{run_count}.png") + plt.savefig(save_path / filename, bbox_inches='tight', dpi=300) + plt.close() + + +def main(): + parser = argparse.ArgumentParser(description='Benchmark Keypad Shuffle') + parser.add_argument('--shuffle_type', type=str, + choices=['RandomSplitShuffle', 'RandomShuffle', 'SlidingSplitShuffle', 'SlidingTowerShuffle'], + default='SlidingTowerShuffle', help='Type of keypad shuffle') + parser.add_argument('--number_of_keys', type=int, default=6, help='Number of keys') + parser.add_argument('--properties_per_key', type=int, default=8, help='Properties per key') + parser.add_argument('--passcode_len', type=int, default=4, help='Passcode length') + parser.add_argument('--max_tries_before_lockout', type=int, default=5, help='Max tries before lockout') + parser.add_argument('--complexity', type=int, default=4, help='Complexity') + parser.add_argument('--disparity', type=int, default=4, help='Disparity') + parser.add_argument('--run_count', type=int, default=10000, help='Number of runs') + parser.add_argument('--output_dir', type=str, default='./output', + help='Output directory for histograms') + + args = parser.parse_args() + + shuffle_classes = { + 'RandomSplitShuffle': RandomSplitShuffleKeypad, + 'RandomShuffle': RandomShuffleKeypad, + 'SlidingSplitShuffle': SlidingSplitShuffleKeypad, + 'SlidingTowerShuffle': SlidingTowerShuffleKeypad + } + + keypad_class = shuffle_classes[args.shuffle_type] + keypad = keypad_class.new_keypad(args.number_of_keys, args.properties_per_key) + + shuffle_type = str(type(keypad)).lower().split('.')[-1].replace("'>", "") + run_name = f"{shuffle_type}-{args.number_of_keys}-{args.properties_per_key}-{args.passcode_len}-{args.max_tries_before_lockout}-{args.complexity}-{args.disparity}-{args.run_count}" + save_path = Path(args.output_dir) / run_name + bench_result = benchmark( + number_of_keys=args.number_of_keys, + properties_per_key=args.properties_per_key, + passcode_len=args.passcode_len, + max_tries_before_lockout=args.max_tries_before_lockout, + run_count=args.run_count, + complexity=args.complexity, + disparity=args.disparity, + keypad=keypad, + file_path=save_path, + ) + + print(f"Bench {args.shuffle_type} Break {mean(bench_result.iterations_to_break)}") + print(f"Bench {args.shuffle_type} Replay {mean(bench_result.iterations_to_replay)}") + + bench_histogram( + bench_result.iterations_to_break, + f"{args.shuffle_type} Break", + args.number_of_keys, + args.properties_per_key, + args.passcode_len, + args.max_tries_before_lockout, + args.complexity, + args.disparity, + args.run_count, + save_path + ) + + bench_histogram( + bench_result.iterations_to_replay, + f"{args.shuffle_type} Replay", + args.number_of_keys, + args.properties_per_key, + args.passcode_len, + args.max_tries_before_lockout, + args.complexity, + args.disparity, + args.run_count, + save_path, + ) + + +if __name__ == "__main__": + main() diff --git a/src/visualnkode.py b/cli/visualnkode.py similarity index 74% rename from src/visualnkode.py rename to cli/visualnkode.py index 2385f3f..334f3c6 100644 --- a/src/visualnkode.py +++ b/cli/visualnkode.py @@ -1,16 +1,18 @@ import json from typing import Iterable from dataclasses import dataclass, asdict -from evilnkode import Observation -from utils import observations, passcode_generator +from src.evilnkode import Observation +from src.utils import observations, passcode_generator from pathlib import Path from PIL import Image, ImageDraw, ImageFont -from src.keypad.keypad import BaseKeypad, SlidingTowerShuffleKeypad - -# Project root = parent of *this* file's directory -PROJECT_ROOT = Path(__file__).resolve().parent.parent -BASE_DIR = PROJECT_ROOT / "output" -PNG_DIR = PROJECT_ROOT / "output" / "obs_png" +from src.keypad.keypad import ( + BaseKeypad, + SlidingSplitShuffleKeypad, + SlidingTowerShuffleKeypad, + RandomShuffleKeypad, + RandomSplitShuffleKeypad, +) +import argparse @dataclass @@ -46,19 +48,8 @@ def _next_json_filename(base_dir: Path) -> Path: def save_observation_sequence_to_json(seq: ObservationSequence, - shuffle_name: str, - filename: Path | None = None) -> None: - """ - Save ObservationSequence to JSON. - - If filename is None, put it under PROJECT_ROOT/output/obs_json/ as observation_{n}.json - - Creates directory if needed - """ - if filename is None: - base_dir = BASE_DIR / shuffle_name / "obs_json" - base_dir.mkdir(parents=True, exist_ok=True) - filename = _next_json_filename(base_dir) - else: - filename.parent.mkdir(parents=True, exist_ok=True) + filename: Path) -> None: + filename.parent.mkdir(parents=True, exist_ok=True) with filename.open("w", encoding="utf-8") as f: json.dump(asdict(seq), f, indent=4) @@ -227,25 +218,36 @@ def _next_run_dir(base_dir: Path) -> Path: counter += 1 -def render_sequence_to_pngs(seq: ObservationSequence, shuffle_name: str, out_dir: Path | None = None) -> None: - """ - Render each observation to its own PNG inside a fresh run directory. - Default: PROJECT_ROOT/output/obs_png/run_XXX/observation_001.png - """ - base_dir = BASE_DIR / shuffle_name / "obs_png" if out_dir is None else out_dir - base_dir.mkdir(parents=True, exist_ok=True) - - # Create a fresh run dir - run_dir = _next_run_dir(base_dir) - +def render_sequence_to_pngs(seq: ObservationSequence, out_dir: Path) -> None: + out_dir.mkdir(parents=True, exist_ok=True) + run_dir = _next_run_dir(out_dir) for i, obs in enumerate(seq.observations, start=1): filename = run_dir / f"observation_{i:03d}.png" render_observation_to_png(seq.target_passcode, obs, filename) if __name__ == "__main__": - shuffle_name = "tower_shuffle" - keypad = SlidingTowerShuffleKeypad.new_keypad(6, 9) + shuffle_classes = { + 'RandomSplitShuffle': RandomSplitShuffleKeypad, + 'RandomShuffle': RandomShuffleKeypad, + 'SlidingSplitShuffle': SlidingSplitShuffleKeypad, + 'SlidingTowerShuffle': SlidingTowerShuffleKeypad + } + parser = argparse.ArgumentParser(description="Generate and save observation sequences with optional PNG rendering.") + parser.add_argument("--number-of-keys", type=int, default=6, help="Number of keys in the keypad (default: 6)") + parser.add_argument("--properties-per-key", type=int, default=9, help="Properties per key (default: 9)") + parser.add_argument("--passcode-length", type=int, default=4, help="Length of the passcode (default: 4)") + parser.add_argument("--complexity", type=int, default=0, help="Complexity of the passcode (default: 0)") + parser.add_argument("--disparity", type=int, default=0, help="Disparity of the passcode (default: 0)") + parser.add_argument("--num-runs", type=int, default=50, help="Number of observations to generate (default: 50)") + parser.add_argument("--shuffle-type", type=str, default="SlidingTowerShuffle", choices=list(shuffle_classes.keys()), + help="Keypad shuffle type: 'RandomShuffle' or 'SlidingTowerShuffle' (default: SlidingTowerShuffle)") + parser.add_argument("--output-dir", type=str, default="./output", + help="Custom output directory for JSON and PNG files") + args = parser.parse_args() + keypad = shuffle_classes[args.shuffle_type].new_keypad(6, 9) obs_seq = new_observation_sequence(keypad, 4, 0, 0, numb_runs=50) - save_observation_sequence_to_json(obs_seq, shuffle_name) - render_sequence_to_pngs(obs_seq, shuffle_name) + shuffle_type = str(type(keypad)).lower().split('.')[-1].replace("'>", "") + output_dir = Path(args.output_dir) + save_observation_sequence_to_json(obs_seq, output_dir / "obs.json") + render_sequence_to_pngs(obs_seq, output_dir / "obs_png") diff --git a/environment.yaml b/environment.yaml new file mode 100644 index 0000000..9a21d44 --- /dev/null +++ b/environment.yaml @@ -0,0 +1,544 @@ +name: base +channels: + - defaults +dependencies: + - _anaconda_depends=2024.10=py312_openblas_0 + - aiobotocore=2.12.3=py312hca03da5_0 + - aiohappyeyeballs=2.4.3=py312hca03da5_0 + - aiohttp=3.10.5=py312h80987f9_0 + - aioitertools=0.7.1=pyhd3eb1b0_0 + - aiosignal=1.2.0=pyhd3eb1b0_0 + - alabaster=0.7.16=py312hca03da5_0 + - altair=5.0.1=py312hca03da5_0 + - anaconda-anon-usage=0.5.0=py312hd6b623d_100 + - anaconda-catalogs=0.2.0=py312hca03da5_1 + - anaconda-cli-base=0.4.1=py312hca03da5_1 + - anaconda-client=1.13.0=py312hca03da5_0 + - anaconda-cloud-auth=0.7.2=py312hca03da5_0 + - anaconda-navigator=2.6.4=py312hca03da5_0 + - anaconda-project=0.11.1=py312hca03da5_0 + - annotated-types=0.6.0=py312hca03da5_0 + - anyio=4.6.2=py312hca03da5_0 + - aom=3.6.0=h313beb8_0 + - appdirs=1.4.4=pyhd3eb1b0_0 + - applaunchservices=0.3.0=py312hca03da5_0 + - appnope=0.1.3=py312hca03da5_1001 + - appscript=1.2.5=py312h80987f9_0 + - archspec=0.2.3=pyhd3eb1b0_0 + - argon2-cffi=21.3.0=pyhd3eb1b0_0 + - argon2-cffi-bindings=21.2.0=py312h80987f9_0 + - arrow=1.3.0=py312hca03da5_0 + - arrow-cpp=16.1.0=hbc20fb2_0 + - astroid=3.2.4=py312hca03da5_0 + - astropy=6.1.3=py312h80987f9_0 + - astropy-iers-data=0.2024.9.2.0.33.23=py312hca03da5_0 + - asttokens=2.0.5=pyhd3eb1b0_0 + - async-lru=2.0.4=py312hca03da5_0 + - asyncssh=2.17.0=py312hca03da5_0 + - atomicwrites=1.4.0=py_0 + - attrs=24.2.0=py312hca03da5_0 + - automat=20.2.0=py_0 + - autopep8=2.0.4=pyhd3eb1b0_0 + - aws-c-auth=0.6.19=h80987f9_0 + - aws-c-cal=0.5.20=h80987f9_0 + - aws-c-common=0.8.5=h80987f9_0 + - aws-c-compression=0.2.16=h80987f9_0 + - aws-c-event-stream=0.2.15=h313beb8_0 + - aws-c-http=0.6.25=h80987f9_0 + - aws-c-io=0.13.10=h80987f9_0 + - aws-c-mqtt=0.7.13=h80987f9_0 + - aws-c-s3=0.1.51=h80987f9_0 + - aws-c-sdkutils=0.1.6=h80987f9_0 + - aws-checksums=0.1.13=h80987f9_0 + - aws-crt-cpp=0.18.16=h313beb8_0 + - aws-sdk-cpp=1.10.55=h313beb8_0 + - babel=2.11.0=py312hca03da5_0 + - backports=1.1=pyhd3eb1b0_1 + - backports.functools_lru_cache=1.6.4=pyhd3eb1b0_0 + - backports.tempfile=1.0=pyhd3eb1b0_1 + - backports.weakref=1.0.post1=py_1 + - bcrypt=3.2.0=py312h80987f9_1 + - beautifulsoup4=4.12.3=py312hca03da5_0 + - binaryornot=0.4.4=pyhd3eb1b0_1 + - black=24.8.0=py312hca03da5_0 + - blas=1.0=openblas + - bleach=6.2.0=py312hca03da5_0 + - blinker=1.6.2=py312hca03da5_0 + - blosc=1.21.3=h313beb8_0 + - bokeh=3.6.0=py312hca03da5_0 + - boltons=23.0.0=py312hca03da5_0 + - boost-cpp=1.82.0=h48ca7d4_2 + - botocore=1.34.69=py312hca03da5_0 + - bottleneck=1.4.2=py312ha86b861_0 + - brotli=1.0.9=h80987f9_8 + - brotli-bin=1.0.9=h80987f9_8 + - brotli-python=1.0.9=py312h313beb8_8 + - brunsli=0.1=hc377ac9_1 + - bzip2=1.0.8=h80987f9_6 + - c-ares=1.19.1=h80987f9_0 + - c-blosc2=2.12.0=h7df6c2f_0 + - ca-certificates=2024.11.26=hca03da5_0 + - cachetools=5.3.3=py312hca03da5_0 + - cctools=949.0.1=hc179dcd_25 + - cctools_osx-arm64=949.0.1=h332cad3_25 + - certifi=2024.8.30=py312hca03da5_0 + - cffi=1.17.1=py312h3eb5a62_0 + - cfitsio=3.470=h7f6438f_7 + - chardet=4.0.0=py312hca03da5_1003 + - charls=2.2.0=hc377ac9_0 + - charset-normalizer=3.3.2=pyhd3eb1b0_0 + - click=8.1.7=py312hca03da5_0 + - cloudpickle=3.0.0=py312hca03da5_0 + - colorama=0.4.6=py312hca03da5_0 + - colorcet=3.1.0=py312hca03da5_0 + - comm=0.2.1=py312hca03da5_0 + - conda=24.11.0=py312hca03da5_0 + - conda-build=24.11.2=py312hca03da5_0 + - conda-content-trust=0.2.0=py312hca03da5_1 + - conda-index=0.5.0=py312hca03da5_0 + - conda-libmamba-solver=24.9.0=pyhd3eb1b0_0 + - conda-pack=0.6.0=pyhd3eb1b0_0 + - conda-package-handling=2.4.0=py312hca03da5_0 + - conda-package-streaming=0.11.0=py312hca03da5_0 + - conda-repo-cli=1.0.114=py312hca03da5_0 + - conda-token=0.4.0=pyhd3eb1b0_0 + - conda-verify=3.4.2=py_1 + - constantly=23.10.4=py312hca03da5_0 + - contourpy=1.3.1=py312h48ca7d4_0 + - cookiecutter=2.6.0=py312hca03da5_0 + - cryptography=43.0.3=py312h8026fc7_1 + - cssselect=1.2.0=py312hca03da5_0 + - curl=8.9.1=h02f6b3c_0 + - cycler=0.11.0=pyhd3eb1b0_0 + - cyrus-sasl=2.1.28=h9131b1a_1 + - cytoolz=0.12.2=py312h80987f9_0 + - dask=2024.8.2=py312hca03da5_0 + - dask-core=2024.8.2=py312hca03da5_0 + - dask-expr=1.1.13=py312hca03da5_0 + - datasets=2.19.1=py312hca03da5_0 + - datashader=0.16.3=py312hca03da5_0 + - dav1d=1.2.1=h80987f9_0 + - debugpy=1.6.7=py312h313beb8_0 + - decorator=5.1.1=pyhd3eb1b0_0 + - defusedxml=0.7.1=pyhd3eb1b0_0 + - deprecated=1.2.13=py312hca03da5_0 + - diff-match-patch=20200713=pyhd3eb1b0_0 + - dill=0.3.8=py312hca03da5_0 + - distributed=2024.8.2=py312hca03da5_0 + - distro=1.9.0=py312hca03da5_0 + - dmglib=0.9.5=py312hca03da5_0 + - docstring-to-markdown=0.11=py312hca03da5_0 + - docutils=0.18.1=py312hca03da5_3 + - et_xmlfile=1.1.0=py312hca03da5_1 + - executing=0.8.3=pyhd3eb1b0_0 + - expat=2.6.3=h313beb8_0 + - filelock=3.13.1=py312hca03da5_0 + - flake8=7.1.1=py312hca03da5_0 + - flask=3.0.3=py312hca03da5_0 + - fmt=9.1.0=h48ca7d4_1 + - fonttools=4.51.0=py312h80987f9_0 + - freetype=2.12.1=h1192e45_0 + - frozendict=2.4.2=py312hca03da5_0 + - frozenlist=1.5.0=py312h80987f9_0 + - fsspec=2024.3.1=py312hca03da5_0 + - future=1.0.0=py312hca03da5_0 + - gensim=4.3.3=py312hd77ebd4_0 + - gettext=0.21.0=hbdbcc25_2 + - gflags=2.2.2=h313beb8_1 + - giflib=5.2.2=h80987f9_0 + - gitdb=4.0.7=pyhd3eb1b0_0 + - gitpython=3.1.43=py312hca03da5_0 + - glib=2.78.4=h313beb8_0 + - glib-tools=2.78.4=h313beb8_0 + - glog=0.5.0=h313beb8_1 + - gmp=6.2.1=hc377ac9_3 + - greenlet=3.0.1=py312h313beb8_0 + - gst-plugins-base=1.14.1=h313beb8_1 + - gstreamer=1.14.1=h80987f9_1 + - h11=0.14.0=py312hca03da5_0 + - h5py=3.12.1=py312h8456320_0 + - hdf5=1.12.1=h05c076b_3 + - heapdict=1.0.1=pyhd3eb1b0_0 + - holoviews=1.20.0=py312hca03da5_0 + - httpcore=1.0.2=py312hca03da5_0 + - httpx=0.27.0=py312hca03da5_0 + - huggingface_hub=0.24.6=py312hca03da5_0 + - hvplot=0.11.1=py312hca03da5_0 + - hyperlink=21.0.0=pyhd3eb1b0_0 + - icu=73.1=h313beb8_0 + - idna=3.7=py312hca03da5_0 + - imagecodecs=2023.1.23=py312h75b721f_1 + - imageio=2.33.1=py312hca03da5_0 + - imagesize=1.4.1=py312hca03da5_0 + - imbalanced-learn=0.12.3=py312hca03da5_1 + - importlib-metadata=8.5.0=py312hca03da5_0 + - importlib_metadata=8.5.0=hd3eb1b0_0 + - incremental=22.10.0=pyhd3eb1b0_0 + - inflection=0.5.1=py312hca03da5_1 + - iniconfig=1.1.1=pyhd3eb1b0_0 + - intake=2.0.7=py312hca03da5_0 + - intervaltree=3.1.0=pyhd3eb1b0_0 + - ipykernel=6.29.5=py312hca03da5_0 + - ipython=8.27.0=py312hca03da5_0 + - ipython_genutils=0.2.0=pyhd3eb1b0_1 + - ipywidgets=7.8.1=py312hca03da5_0 + - isort=5.13.2=py312hca03da5_0 + - itemadapter=0.3.0=pyhd3eb1b0_0 + - itemloaders=1.1.0=py312hca03da5_0 + - itsdangerous=2.2.0=py312hca03da5_0 + - jaraco.classes=3.2.1=pyhd3eb1b0_0 + - jedi=0.19.1=py312hca03da5_0 + - jellyfish=1.0.1=py312h1bd1ac0_1 + - jinja2=3.1.4=py312hca03da5_1 + - jmespath=1.0.1=py312hca03da5_0 + - joblib=1.4.2=py312hca03da5_0 + - jpeg=9e=h80987f9_3 + - jq=1.7.1=h80987f9_0 + - json5=0.9.25=py312hca03da5_0 + - jsonpatch=1.33=py312hca03da5_1 + - jsonpointer=2.1=pyhd3eb1b0_0 + - jsonschema=4.23.0=py312hca03da5_0 + - jsonschema-specifications=2023.7.1=py312hca03da5_0 + - jupyter=1.0.0=py312hca03da5_9 + - jupyter-lsp=2.2.0=py312hca03da5_0 + - jupyter_client=8.6.0=py312hca03da5_0 + - jupyter_console=6.6.3=py312hca03da5_1 + - jupyter_core=5.7.2=py312hca03da5_0 + - jupyter_events=0.10.0=py312hca03da5_0 + - jupyter_server=2.14.1=py312hca03da5_0 + - jupyter_server_terminals=0.4.4=py312hca03da5_1 + - jupyterlab=4.2.5=py312hca03da5_0 + - jupyterlab-variableinspector=3.1.0=py312hca03da5_0 + - jupyterlab_pygments=0.1.2=py_0 + - jupyterlab_server=2.27.3=py312hca03da5_0 + - jupyterlab_widgets=1.0.0=pyhd3eb1b0_1 + - jxrlib=1.1=h1a28f6b_2 + - keyring=24.3.1=py312hca03da5_0 + - kiwisolver=1.4.4=py312h313beb8_0 + - krb5=1.20.1=hf3e1bf2_1 + - lazy_loader=0.4=py312hca03da5_0 + - lcms2=2.12=hba8e193_0 + - ld64=530=hb29bf3f_25 + - ld64_osx-arm64=530=h001ce53_25 + - ldid=2.1.5=h20b2a84_3 + - lerc=3.0=hc377ac9_0 + - libabseil=20240116.2=cxx17_h313beb8_0 + - libaec=1.0.4=hc377ac9_1 + - libarchive=3.7.4=h8f13d7a_0 + - libavif=0.11.1=h80987f9_0 + - libboost=1.82.0=h0bc93f9_2 + - libbrotlicommon=1.0.9=h80987f9_8 + - libbrotlidec=1.0.9=h80987f9_8 + - libbrotlienc=1.0.9=h80987f9_8 + - libclang=14.0.6=default_h1b80db6_1 + - libclang13=14.0.6=default_h24352ff_1 + - libcurl=8.9.1=h3e2b118_0 + - libcxx=14.0.6=h848a8c0_0 + - libdeflate=1.17=h80987f9_1 + - libedit=3.1.20230828=h80987f9_0 + - libev=4.33=h1a28f6b_1 + - libevent=2.1.12=h02f6b3c_1 + - libffi=3.4.4=hca03da5_1 + - libgfortran=5.0.0=11_3_0_hca03da5_28 + - libgfortran5=11.3.0=h009349e_28 + - libglib=2.78.4=h0a96307_0 + - libgrpc=1.62.2=h62f6fdd_0 + - libiconv=1.16=h80987f9_3 + - liblief=0.12.3=h313beb8_0 + - libllvm14=14.0.6=h19fdd8a_4 + - libmamba=1.5.11=haeffa04_0 + - libmambapy=1.5.11=py312h15e39b3_0 + - libnghttp2=1.57.0=h62f6fdd_0 + - libopenblas=0.3.21=h269037a_0 + - libpng=1.6.39=h80987f9_0 + - libpq=17.0=h02f6b3c_0 + - libprotobuf=4.25.3=h514c7bf_0 + - libsodium=1.0.18=h1a28f6b_0 + - libsolv=0.7.24=h514c7bf_1 + - libspatialindex=1.9.3=hc377ac9_0 + - libssh2=1.11.1=h3e2b118_0 + - libthrift=0.15.0=h73c2103_2 + - libtiff=4.5.1=h313beb8_0 + - libwebp-base=1.3.2=h80987f9_1 + - libxml2=2.13.5=h0b34f26_0 + - libxslt=1.1.41=hf4d3faa_0 + - libzopfli=1.0.3=hc377ac9_0 + - linkify-it-py=2.0.0=py312hca03da5_0 + - llvm-openmp=14.0.6=hc6e5704_0 + - llvmlite=0.43.0=py312h313beb8_0 + - locket=1.0.0=py312hca03da5_0 + - lxml=5.3.0=py312h1d4350b_0 + - lz4=4.3.2=py312h80987f9_0 + - lz4-c=1.9.4=h313beb8_1 + - lzo=2.10=h1a28f6b_2 + - markdown=3.4.1=py312hca03da5_0 + - markdown-it-py=2.2.0=py312hca03da5_1 + - markupsafe=2.1.3=py312h80987f9_0 + - matplotlib=3.9.2=py312hca03da5_1 + - matplotlib-base=3.9.2=py312h7ef442a_1 + - matplotlib-inline=0.1.6=py312hca03da5_0 + - mccabe=0.7.0=pyhd3eb1b0_0 + - mdit-py-plugins=0.3.0=py312hca03da5_0 + - mdurl=0.1.0=py312hca03da5_0 + - menuinst=2.2.0=py312hca03da5_0 + - mistune=2.0.4=py312hca03da5_0 + - more-itertools=10.3.0=py312hca03da5_0 + - mpc=1.1.0=h8c48613_1 + - mpfr=4.0.2=h695f6f0_1 + - mpmath=1.3.0=py312hca03da5_0 + - msgpack-python=1.0.3=py312h48ca7d4_0 + - multidict=6.1.0=py312h80987f9_0 + - multipledispatch=0.6.0=py312hca03da5_0 + - multiprocess=0.70.15=py312hca03da5_0 + - mypy=1.11.2=py312h80987f9_0 + - mypy_extensions=1.0.0=py312hca03da5_0 + - mysql=8.4.0=h3a6587f_1 + - navigator-updater=0.5.1=py312hca03da5_0 + - nbclassic=1.1.0=py312hca03da5_0 + - nbclient=0.8.0=py312hca03da5_0 + - nbconvert=7.16.4=py312hca03da5_0 + - nbformat=5.10.4=py312hca03da5_0 + - ncurses=6.4=h313beb8_0 + - nest-asyncio=1.6.0=py312hca03da5_0 + - networkx=3.3=py312hca03da5_0 + - nltk=3.9.1=py312hca03da5_0 + - notebook=7.2.2=py312hca03da5_1 + - notebook-shim=0.2.3=py312hca03da5_0 + - numba=0.60.0=py312hd77ebd4_0 + - numexpr=2.10.1=py312h5d9532f_0 + - numpy=1.26.4=py312h7f4fdc5_0 + - numpy-base=1.26.4=py312he047099_0 + - numpydoc=1.7.0=py312hca03da5_0 + - oniguruma=6.9.7.1=h1a28f6b_0 + - openjpeg=2.5.2=h54b8e55_0 + - openldap=2.6.4=he7ef289_0 + - openpyxl=3.1.5=py312h80987f9_0 + - openssl=3.0.15=h80987f9_0 + - orc=2.0.1=h937ddfc_0 + - overrides=7.4.0=py312hca03da5_0 + - packaging=24.1=py312hca03da5_0 + - pandas=2.2.3=py312hcf29cfe_0 + - pandocfilters=1.5.0=pyhd3eb1b0_0 + - panel=1.5.3=py312hca03da5_0 + - param=2.1.1=py312hca03da5_0 + - parsel=1.8.1=py312hca03da5_0 + - parso=0.8.3=pyhd3eb1b0_0 + - partd=1.4.1=py312hca03da5_0 + - patch=2.7.6=h1a28f6b_1001 + - pathspec=0.10.3=py312hca03da5_0 + - patsy=0.5.6=py312hca03da5_0 + - pcre2=10.42=hb066dcc_1 + - pexpect=4.8.0=pyhd3eb1b0_3 + - pickleshare=0.7.5=pyhd3eb1b0_1003 + - pillow=11.0.0=py312hfaf4e14_0 + - pip=24.2=py312hca03da5_0 + - pkce=1.0.3=py312hca03da5_0 + - pkginfo=1.11.2=py312hca03da5_0 + - platformdirs=3.10.0=py312hca03da5_0 + - plotly=5.24.1=py312h989b03a_0 + - pluggy=1.5.0=py312hca03da5_0 + - ply=3.11=py312hca03da5_1 + - prometheus_client=0.21.0=py312hca03da5_0 + - prompt-toolkit=3.0.43=py312hca03da5_0 + - prompt_toolkit=3.0.43=hd3eb1b0_0 + - propcache=0.2.0=py312h80987f9_0 + - protego=0.1.16=py_0 + - protobuf=4.25.3=py312h8472c4a_0 + - psutil=5.9.0=py312h80987f9_0 + - ptyprocess=0.7.0=pyhd3eb1b0_2 + - pure_eval=0.2.2=pyhd3eb1b0_0 + - py-cpuinfo=9.0.0=py312hca03da5_0 + - py-lief=0.12.3=py312h313beb8_0 + - pyarrow=16.1.0=py312hd77ebd4_0 + - pyasn1=0.4.8=pyhd3eb1b0_0 + - pyasn1-modules=0.2.8=py_0 + - pybind11-abi=5=hd3eb1b0_0 + - pycodestyle=2.12.1=py312hca03da5_0 + - pycosat=0.6.6=py312h80987f9_1 + - pycparser=2.21=pyhd3eb1b0_0 + - pyct=0.5.0=py312hca03da5_0 + - pycurl=7.45.3=py312h02f6b3c_0 + - pydantic=2.8.2=py312hca03da5_0 + - pydantic-core=2.20.1=py312hf0e4da2_0 + - pydantic-settings=2.6.1=py312hca03da5_0 + - pydeck=0.8.0=py312hca03da5_2 + - pydispatcher=2.0.5=py312hca03da5_3 + - pydocstyle=6.3.0=py312hca03da5_0 + - pyerfa=2.0.1.4=py312ha86b861_0 + - pyflakes=3.2.0=py312hca03da5_0 + - pygithub=2.4.0=py312hca03da5_0 + - pygments=2.15.1=py312hca03da5_1 + - pyjwt=2.9.0=py312hca03da5_0 + - pylint=3.2.7=py312hca03da5_0 + - pylint-venv=3.0.3=py312hca03da5_0 + - pyls-spyder=0.4.0=pyhd3eb1b0_0 + - pynacl=1.5.0=py312h80987f9_0 + - pyobjc-core=10.1=py312h80987f9_0 + - pyobjc-framework-cocoa=10.1=py312hb094c41_0 + - pyobjc-framework-coreservices=10.1=py312hdd8dd1f_0 + - pyobjc-framework-fsevents=10.1=py312hca03da5_0 + - pyodbc=5.1.0=py312h313beb8_0 + - pyopenssl=24.2.1=py312hca03da5_0 + - pyparsing=3.2.0=py312hca03da5_0 + - pyqt=5.15.10=py312h313beb8_0 + - pyqt5-sip=12.13.0=py312h80987f9_0 + - pyqtwebengine=5.15.10=py312h313beb8_0 + - pysocks=1.7.1=py312hca03da5_0 + - pytables=3.10.1=py312h905a39b_0 + - pytest=7.4.4=py312hca03da5_0 + - python=3.12.7=h99e199e_0 + - python-dateutil=2.9.0post0=py312hca03da5_2 + - python-dotenv=0.21.0=py312hca03da5_0 + - python-fastjsonschema=2.20.0=py312hca03da5_0 + - python-json-logger=2.0.7=py312hca03da5_0 + - python-libarchive-c=5.1=pyhd3eb1b0_0 + - python-lmdb=1.4.1=py312h313beb8_0 + - python-lsp-black=2.0.0=py312hca03da5_0 + - python-lsp-jsonrpc=1.1.2=pyhd3eb1b0_0 + - python-lsp-server=1.12.0=py312h989b03a_0 + - python-slugify=5.0.2=pyhd3eb1b0_0 + - python-tzdata=2023.3=pyhd3eb1b0_0 + - python-xxhash=2.0.2=py312h80987f9_1 + - python.app=3=py312h80987f9_1 + - pytoolconfig=1.2.6=py312hca03da5_0 + - pytz=2024.1=py312hca03da5_0 + - pyuca=1.2=py312hca03da5_1 + - pyviz_comms=3.0.2=py312hca03da5_0 + - pywavelets=1.7.0=py312h80987f9_0 + - pyyaml=6.0.2=py312h80987f9_0 + - pyzmq=25.1.2=py312h313beb8_0 + - qdarkstyle=3.2.3=pyhd3eb1b0_0 + - qstylizer=0.2.2=py312hca03da5_0 + - qt-main=5.15.2=h0917680_11 + - qt-webengine=5.15.9=h2903aaf_7 + - qtawesome=1.3.1=py312hca03da5_0 + - qtconsole=5.6.0=py312hca03da5_0 + - qtpy=2.4.1=py312hca03da5_0 + - queuelib=1.6.2=py312hca03da5_0 + - re2=2022.04.01=hc377ac9_0 + - readchar=4.0.5=py312hca03da5_0 + - readline=8.2=h1a28f6b_0 + - referencing=0.30.2=py312hca03da5_0 + - regex=2024.9.11=py312h80987f9_0 + - reproc=14.2.4=h313beb8_2 + - reproc-cpp=14.2.4=h313beb8_2 + - requests=2.32.3=py312hca03da5_1 + - requests-file=1.5.1=pyhd3eb1b0_0 + - requests-toolbelt=1.0.0=py312hca03da5_0 + - responses=0.13.3=pyhd3eb1b0_0 + - rfc3339-validator=0.1.4=py312hca03da5_0 + - rfc3986-validator=0.1.1=py312hca03da5_0 + - rich=13.9.4=py312hca03da5_0 + - rope=1.12.0=py312hca03da5_0 + - rpds-py=0.10.6=py312h2aea54e_1 + - rtree=1.0.1=py312hca03da5_0 + - ruamel.yaml=0.18.6=py312h80987f9_0 + - ruamel.yaml.clib=0.2.8=py312h80987f9_0 + - ruamel_yaml=0.17.21=py312h80987f9_0 + - s3fs=2024.3.1=py312hca03da5_0 + - safetensors=0.4.5=py312h7805bc0_1 + - scikit-image=0.24.0=py312hd77ebd4_0 + - scikit-learn=1.5.1=py312hd77ebd4_0 + - scipy=1.13.1=py312ha409365_0 + - scrapy=2.12.0=py312hca03da5_0 + - seaborn=0.13.2=py312hca03da5_0 + - semver=3.0.2=py312hca03da5_0 + - send2trash=1.8.2=py312hca03da5_0 + - service_identity=18.1.0=pyhd3eb1b0_1 + - setuptools=75.1.0=py312hca03da5_0 + - shellingham=1.5.0=py312hca03da5_0 + - sip=6.7.12=py312h313beb8_0 + - six=1.16.0=pyhd3eb1b0_1 + - smart_open=5.2.1=py312hca03da5_0 + - smmap=4.0.0=pyhd3eb1b0_0 + - snappy=1.2.1=h313beb8_0 + - sniffio=1.3.0=py312hca03da5_0 + - snowballstemmer=2.2.0=pyhd3eb1b0_0 + - sortedcontainers=2.4.0=pyhd3eb1b0_0 + - soupsieve=2.5=py312hca03da5_0 + - sphinx=7.3.7=py312hca03da5_0 + - sphinxcontrib-applehelp=1.0.2=pyhd3eb1b0_0 + - sphinxcontrib-devhelp=1.0.2=pyhd3eb1b0_0 + - sphinxcontrib-htmlhelp=2.0.0=pyhd3eb1b0_0 + - sphinxcontrib-jsmath=1.0.1=pyhd3eb1b0_0 + - sphinxcontrib-qthelp=1.0.3=pyhd3eb1b0_0 + - sphinxcontrib-serializinghtml=1.1.10=py312hca03da5_0 + - spyder=6.0.1=py312hca03da5_0 + - spyder-kernels=3.0.0=py312h989b03a_0 + - sqlalchemy=2.0.34=py312hbe2cdee_0 + - sqlite=3.45.3=h80987f9_0 + - stack_data=0.2.0=pyhd3eb1b0_0 + - statsmodels=0.14.2=py312ha86b861_0 + - streamlit=1.40.1=py312hca03da5_0 + - superqt=0.6.7=py312h989b03a_0 + - sympy=1.13.2=py312hca03da5_0 + - tabulate=0.9.0=py312hca03da5_0 + - tapi=1100.0.11=h8754e6a_1 + - tbb=2021.8.0=h48ca7d4_0 + - tblib=1.7.0=pyhd3eb1b0_0 + - tenacity=9.0.0=py312hca03da5_0 + - terminado=0.17.1=py312hca03da5_0 + - text-unidecode=1.3=pyhd3eb1b0_0 + - textdistance=4.6.3=py312h989b03a_0 + - threadpoolctl=3.5.0=py312h989b03a_0 + - three-merge=0.1.1=pyhd3eb1b0_0 + - tifffile=2023.4.12=py312hca03da5_0 + - tinycss2=1.2.1=py312hca03da5_0 + - tk=8.6.14=h6ba3021_0 + - tldextract=5.1.2=py312hca03da5_0 + - tokenizers=0.20.1=py312he2d9c3e_1 + - toml=0.10.2=pyhd3eb1b0_0 + - tomli=2.0.1=py312hca03da5_1 + - tomlkit=0.13.2=py312hca03da5_0 + - toolz=0.12.0=py312hca03da5_0 + - tornado=6.4.1=py312h80987f9_0 + - tqdm=4.66.5=py312h989b03a_0 + - traitlets=5.14.3=py312hca03da5_0 + - transformers=4.45.2=py312hca03da5_0 + - truststore=0.8.0=py312hca03da5_0 + - twisted=23.10.0=py312hca03da5_0 + - typer=0.9.0=py312hca03da5_0 + - typing-extensions=4.11.0=py312hca03da5_0 + - typing_extensions=4.11.0=py312hca03da5_0 + - tzdata=2024b=h04d1e81_0 + - uc-micro-py=1.0.1=py312hca03da5_0 + - ujson=5.10.0=py312h313beb8_0 + - unicodedata2=15.1.0=py312h80987f9_0 + - unidecode=1.3.8=py312hca03da5_0 + - unixodbc=2.3.11=h1a28f6b_0 + - urllib3=2.2.3=py312hca03da5_0 + - utf8proc=2.6.1=h80987f9_1 + - w3lib=2.1.2=py312hca03da5_0 + - watchdog=4.0.1=py312h80987f9_0 + - wcwidth=0.2.5=pyhd3eb1b0_0 + - webencodings=0.5.1=py312hca03da5_2 + - websocket-client=1.8.0=py312hca03da5_0 + - werkzeug=3.0.6=py312hca03da5_0 + - whatthepatch=1.0.2=py312hca03da5_0 + - wheel=0.44.0=py312hca03da5_0 + - widgetsnbextension=3.6.6=py312hca03da5_0 + - wrapt=1.14.1=py312h80987f9_0 + - wurlitzer=3.0.2=py312hca03da5_0 + - xarray=2023.6.0=py312hca03da5_0 + - xlwings=0.32.1=py312hca03da5_0 + - xxhash=0.8.0=h1a28f6b_3 + - xyzservices=2022.9.0=py312hca03da5_1 + - xz=5.4.6=h80987f9_1 + - yaml=0.2.5=h1a28f6b_0 + - yaml-cpp=0.8.0=h313beb8_1 + - yapf=0.40.2=py312hca03da5_0 + - yarl=1.18.0=py312h80987f9_0 + - zeromq=4.3.5=h313beb8_0 + - zfp=1.0.0=h313beb8_0 + - zict=3.0.0=py312hca03da5_0 + - zipp=3.21.0=py312hca03da5_0 + - zlib=1.2.13=h18a0788_1 + - zlib-ng=2.0.7=h80987f9_0 + - zope=1.0=py312hca03da5_1 + - zope.interface=7.1.1=py312h80987f9_0 + - zstandard=0.23.0=py312h1a4646a_1 + - zstd=1.5.6=hfb09047_0 + - pip: + - svgpathtools==1.7.0 + - svgwrite==1.4.3 +prefix: /opt/homebrew/anaconda3 diff --git a/environment.yml b/environment.yml deleted file mode 100644 index e55411a..0000000 --- a/environment.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: evilnkode -channels: - - defaults -dependencies: - - anyio=4.6.2=py312hca03da5_0 - - appnope=0.1.3=py312hca03da5_1001 - - argon2-cffi=21.3.0=pyhd3eb1b0_0 - - argon2-cffi-bindings=21.2.0=py312h80987f9_0 - - asttokens=2.0.5=pyhd3eb1b0_0 - - async-lru=2.0.4=py312hca03da5_0 - - attrs=24.2.0=py312hca03da5_0 - - babel=2.11.0=py312hca03da5_0 - - beautifulsoup4=4.12.3=py312hca03da5_0 - - bleach=6.2.0=py312hca03da5_0 - - brotli-python=1.0.9=py312h313beb8_8 - - bzip2=1.0.8=h80987f9_6 - - ca-certificates=2024.12.31=hca03da5_0 - - certifi=2024.12.14=py312hca03da5_0 - - cffi=1.17.1=py312h3eb5a62_0 - - charset-normalizer=3.3.2=pyhd3eb1b0_0 - - comm=0.2.1=py312hca03da5_0 - - debugpy=1.6.7=py312h313beb8_0 - - decorator=5.1.1=pyhd3eb1b0_0 - - defusedxml=0.7.1=pyhd3eb1b0_0 - - executing=0.8.3=pyhd3eb1b0_0 - - expat=2.6.3=h313beb8_0 - - h11=0.14.0=py312hca03da5_0 - - httpcore=1.0.2=py312hca03da5_0 - - httpx=0.27.0=py312hca03da5_0 - - idna=3.7=py312hca03da5_0 - - ipykernel=6.29.5=py312hca03da5_0 - - ipython=8.27.0=py312hca03da5_0 - - jedi=0.19.1=py312hca03da5_0 - - jinja2=3.1.4=py312hca03da5_1 - - json5=0.9.25=py312hca03da5_0 - - jsonschema=4.23.0=py312hca03da5_0 - - jsonschema-specifications=2023.7.1=py312hca03da5_0 - - jupyter-lsp=2.2.0=py312hca03da5_0 - - jupyter_client=8.6.0=py312hca03da5_0 - - jupyter_core=5.7.2=py312hca03da5_0 - - jupyter_events=0.10.0=py312hca03da5_0 - - jupyter_server=2.14.1=py312hca03da5_0 - - jupyter_server_terminals=0.4.4=py312hca03da5_1 - - jupyterlab=4.2.5=py312hca03da5_0 - - jupyterlab_pygments=0.1.2=py_0 - - jupyterlab_server=2.27.3=py312hca03da5_0 - - libcxx=14.0.6=h848a8c0_0 - - libffi=3.4.4=hca03da5_1 - - libsodium=1.0.18=h1a28f6b_0 - - markupsafe=2.1.3=py312h80987f9_0 - - matplotlib-inline=0.1.6=py312hca03da5_0 - - mistune=2.0.4=py312hca03da5_0 - - nbclient=0.8.0=py312hca03da5_0 - - nbconvert=7.16.4=py312hca03da5_0 - - nbformat=5.10.4=py312hca03da5_0 - - ncurses=6.4=h313beb8_0 - - nest-asyncio=1.6.0=py312hca03da5_0 - - notebook=7.2.2=py312hca03da5_1 - - notebook-shim=0.2.3=py312hca03da5_0 - - openssl=3.0.15=h80987f9_0 - - overrides=7.4.0=py312hca03da5_0 - - packaging=24.1=py312hca03da5_0 - - pandocfilters=1.5.0=pyhd3eb1b0_0 - - parso=0.8.3=pyhd3eb1b0_0 - - pexpect=4.8.0=pyhd3eb1b0_3 - - pip=24.2=py312hca03da5_0 - - platformdirs=3.10.0=py312hca03da5_0 - - prometheus_client=0.21.0=py312hca03da5_0 - - prompt-toolkit=3.0.43=py312hca03da5_0 - - prompt_toolkit=3.0.43=hd3eb1b0_0 - - psutil=5.9.0=py312h80987f9_0 - - ptyprocess=0.7.0=pyhd3eb1b0_2 - - pure_eval=0.2.2=pyhd3eb1b0_0 - - pycparser=2.21=pyhd3eb1b0_0 - - pygments=2.15.1=py312hca03da5_1 - - pysocks=1.7.1=py312hca03da5_0 - - python=3.12.7=h99e199e_0 - - python-dateutil=2.9.0post0=py312hca03da5_2 - - python-fastjsonschema=2.20.0=py312hca03da5_0 - - python-json-logger=2.0.7=py312hca03da5_0 - - pytz=2024.1=py312hca03da5_0 - - pyyaml=6.0.2=py312h80987f9_0 - - pyzmq=25.1.2=py312h313beb8_0 - - readline=8.2=h1a28f6b_0 - - referencing=0.30.2=py312hca03da5_0 - - requests=2.32.3=py312hca03da5_1 - - rfc3339-validator=0.1.4=py312hca03da5_0 - - rfc3986-validator=0.1.1=py312hca03da5_0 - - rpds-py=0.10.6=py312h2aea54e_1 - - send2trash=1.8.2=py312hca03da5_0 - - setuptools=75.1.0=py312hca03da5_0 - - six=1.16.0=pyhd3eb1b0_1 - - sniffio=1.3.0=py312hca03da5_0 - - soupsieve=2.5=py312hca03da5_0 - - sqlite=3.45.3=h80987f9_0 - - stack_data=0.2.0=pyhd3eb1b0_0 - - terminado=0.17.1=py312hca03da5_0 - - tinycss2=1.2.1=py312hca03da5_0 - - tk=8.6.14=h6ba3021_0 - - tornado=6.4.1=py312h80987f9_0 - - traitlets=5.14.3=py312hca03da5_0 - - typing-extensions=4.11.0=py312hca03da5_0 - - typing_extensions=4.11.0=py312hca03da5_0 - - tzdata=2024b=h04d1e81_0 - - urllib3=2.2.3=py312hca03da5_0 - - wcwidth=0.2.5=pyhd3eb1b0_0 - - webencodings=0.5.1=py312hca03da5_2 - - websocket-client=1.8.0=py312hca03da5_0 - - wheel=0.44.0=py312hca03da5_0 - - xz=5.4.6=h80987f9_1 - - yaml=0.2.5=h1a28f6b_0 - - zeromq=4.3.5=h313beb8_0 - - zlib=1.2.13=h18a0788_1 - - pip: - - contourpy==1.3.1 - - cycler==0.12.1 - - fonttools==4.55.3 - - iniconfig==2.0.0 - - kiwisolver==1.4.7 - - matplotlib==3.9.3 - - numpy==2.1.3 - - pillow==11.0.0 - - pluggy==1.5.0 - - pyparsing==3.2.0 - - pytest==8.3.4 diff --git a/src/benchmark.py b/src/benchmark.py index 9dedcae..7a72ebb 100644 --- a/src/benchmark.py +++ b/src/benchmark.py @@ -1,9 +1,10 @@ +from tqdm import tqdm from src.evilnkode import EvilNKode from dataclasses import dataclass - from src.utils import observations, passcode_generator from src.keypad.keypad import BaseKeypad from pathlib import Path +import pickle @dataclass @@ -21,31 +22,20 @@ def benchmark( complexity: int, disparity: int, keypad: BaseKeypad, - file_path: str = '../output', + file_path: Path = '../output', overwrite: bool = False ) -> Benchmark: - shuffle_type = str(type(keypad)) - file_name_break = f"{shuffle_type.lower()}-{number_of_keys}-{properties_per_key}-{passcode_len}-{max_tries_before_lockout}-{complexity}-{disparity}-{run_count}.txt" - full_path_iter_break = Path(file_path) / "iterations_to_break" / file_name_break - file_name_replay = f"{shuffle_type.lower()}-{number_of_keys}-{properties_per_key}-{passcode_len}-{max_tries_before_lockout}-{complexity}-{disparity}-{run_count}.txt" - full_path_iter_replay = Path(file_path) / "iterations_to_replay" / file_name_replay + shuffle_type = str(type(keypad)).lower().split('.')[-1].replace("'>", "") + file_name = f"{shuffle_type}-{number_of_keys}-{properties_per_key}-{passcode_len}-{max_tries_before_lockout}-{complexity}-{disparity}-{run_count}.pkl" + full_path = Path(file_path) / "benchmark" / file_name + if not overwrite and full_path.exists(): + print(f"File exists: {full_path}") + with open(full_path, "rb") as fp: + return pickle.load(fp) + iterations_to_break = [] iterations_to_replay = [] - if not overwrite and full_path_iter_break.exists() and full_path_iter_replay.exists(): - print(f"file exists {file_path}") - with open(full_path_iter_break, "r") as fp: - iterations_to_break = fp.readline() - iterations_to_break = iterations_to_break.split(',') - iterations_to_break = [int(i) for i in iterations_to_break] - with open(full_path_iter_replay, "r") as fp: - iterations_to_replay = fp.readline() - iterations_to_replay = iterations_to_replay.split(',') - iterations_to_replay = [int(i) for i in iterations_to_replay] - return Benchmark( - iterations_to_break=iterations_to_break, - iterations_to_replay=iterations_to_replay - ) - for _ in range(run_count): + for _ in tqdm(range(run_count)): passcode = passcode_generator(number_of_keys, properties_per_key, passcode_len, complexity, disparity) evilnkode = EvilNKode( observations=observations( @@ -61,12 +51,14 @@ def benchmark( iterations_to_break.append(evilout.iterations_to_break) iterations_to_replay.append(evilout.iterations_to_replay) - if not file_path == "": - full_path_iter_break.parent.mkdir(parents=True, exist_ok=True) - with open(full_path_iter_break, "w") as fp: - fp.write(",".join([str(i) for i in iterations_to_break])), - - return Benchmark( + benchmark_result = Benchmark( iterations_to_break=iterations_to_break, iterations_to_replay=iterations_to_replay ) + + if file_path: + full_path.parent.mkdir(parents=True, exist_ok=True) + with open(full_path, "wb") as fp: + pickle.dump(benchmark_result, fp) + + return benchmark_result