Showing preview only (7,726K chars total). Download the full file or copy to clipboard to get everything.
Repository: fbdtemme/torrenttools
Branch: main
Commit: 337d6a6f6b3c
Files: 177
Total size: 7.1 MB
Directory structure:
gitextract_bkmqqxe5/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── documentation.yml
│ ├── linux.yml
│ ├── macos.yml
│ ├── package.yml
│ └── windows.yml
├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── Dockerfile
├── LICENSE
├── README.md
├── benchmark/
│ ├── benchmark.csv
│ ├── benchmark.ipynb
│ └── benchmark.sh
├── cmake/
│ ├── FindISALCrypto.cmake
│ ├── FindNASM.cmake
│ ├── FindSphinx.cmake
│ ├── FindTBB.cmake
│ └── SanitizersConfig.cmake
├── docs/
│ ├── CMakeLists.txt
│ ├── bep-support.csv
│ ├── commands/
│ │ ├── create.rst
│ │ ├── edit.rst
│ │ ├── info.rst
│ │ ├── magnet.rst
│ │ ├── pad.rst
│ │ ├── show.rst
│ │ └── verify.rst
│ ├── comparison.rst
│ ├── conf.py.in
│ ├── configuration.rst
│ ├── index.rst
│ ├── topics/
│ │ ├── bencode.rst
│ │ ├── bittorrent-metafile-v1.rst
│ │ └── glossary.rst
│ └── why-torrenttools.rst
├── external/
│ ├── CLI11.cmake
│ ├── Catch2.cmake
│ ├── bencode.cmake
│ ├── cliprogress.cmake
│ ├── ctre.cmake
│ ├── date.cmake
│ ├── dottorrent.cmake
│ ├── expected-lite.cmake
│ ├── external.cmake
│ ├── fmt.cmake
│ ├── gsl-lite.cmake
│ ├── isa-l_crypto.cmake
│ ├── nlohmann_json.cmake
│ ├── re2.cmake
│ ├── sigslot.cmake
│ ├── termcontrol.cmake
│ └── yaml-cpp.cmake
├── include/
│ ├── app_data.hpp
│ ├── argument_parsers.hpp
│ ├── cli_helpers.hpp
│ ├── common.hpp
│ ├── config.hpp.in
│ ├── config_parser.hpp
│ ├── create.hpp
│ ├── edit.hpp
│ ├── escape_binary_fields.hpp
│ ├── exceptions.hpp
│ ├── file_matcher.hpp
│ ├── formatters.hpp
│ ├── help_formatter.hpp
│ ├── indicator.hpp
│ ├── info.hpp
│ ├── list_edit_mode.hpp
│ ├── ls_colors.hpp
│ ├── magnet.hpp
│ ├── main_app.hpp
│ ├── natural_sort.hpp
│ ├── pad.hpp
│ ├── profile.hpp
│ ├── profile_config_formatter.hpp
│ ├── progress.hpp
│ ├── show.hpp
│ ├── tracker_database.hpp
│ ├── tree_view.hpp
│ ├── utils.hpp
│ └── verify.hpp
├── packages/
│ ├── appimage/
│ │ ├── build_appimage.sh
│ │ ├── torrenttools-appimage-recipe.yml
│ │ └── torrenttools.desktop
│ ├── arch/
│ │ └── PKGBUILD
│ ├── cpack_dispatch.cmake
│ ├── debian/
│ │ ├── changelog
│ │ ├── compat
│ │ ├── control
│ │ ├── copyright
│ │ ├── rules
│ │ └── source/
│ │ └── format
│ ├── macos-productbuild.cmake
│ ├── package_summary.txt
│ ├── packages.cmake
│ ├── productbuild/
│ │ └── postflight.sh
│ ├── rpm/
│ │ └── torrenttools.spec
│ ├── ubuntu/
│ │ ├── 20.04/
│ │ │ └── changelog
│ │ └── 21.04/
│ │ └── changelog
│ ├── windows-wix.cmake
│ └── wix/
│ ├── broadcast_env_change.xml
│ ├── copy-config.xml
│ ├── create-localappdata-folder.wxs
│ ├── disable_feature_advertise.xml
│ └── update_path.xml
├── resources/
│ ├── config.yml
│ └── trackers.json
├── scripts/
│ └── fetch_dependencies.sh
├── src/
│ ├── app_data.cpp
│ ├── argument_parsers.cpp
│ ├── common.cpp
│ ├── config_parser.cpp
│ ├── create.cpp
│ ├── edit.cpp
│ ├── escape_binary_fields.cpp
│ ├── formatters.cpp
│ ├── indicator.cpp
│ ├── info.cpp
│ ├── ls_colors.cpp
│ ├── magnet.cpp
│ ├── main.cpp
│ ├── main_app.cpp
│ ├── pad.cpp
│ ├── profile.cpp
│ ├── progress.cpp
│ ├── show.cpp
│ ├── tracker_database.cpp
│ ├── tree_view.cpp
│ └── verify.cpp
└── tests/
├── CMakeLists.txt
├── main.cpp
├── private.torrent/
│ └── test_file.txt.torrent
├── resources/
│ ├── CAMELYON17.torrent
│ ├── COVID-19-image-dataset-collection.torrent
│ ├── Fedora-Workstation-Live-x86_64-30.torrent
│ ├── RSNA_Pneumonia_Detection_Challenge.torrent
│ ├── bittorrent-v2-hybrid-test.torrent
│ ├── bittorrent-v2-test.torrent
│ ├── checksums.torrent
│ ├── collection.torrent
│ ├── config/
│ │ ├── config.yml
│ │ └── trackers.json
│ ├── dht-node.torrent
│ ├── http-seeds.torrent
│ ├── lorem_ipsum.txt
│ ├── private.torrent
│ ├── resources-hybrid.torrent
│ ├── resources.torrent
│ ├── similar-v1.torrent
│ ├── similar-v2.torrent
│ ├── test-torrent/
│ │ ├── dirA/
│ │ │ ├── fileA1
│ │ │ └── fileA2
│ │ └── dirB/
│ │ ├── fileB1
│ │ └── fileB2
│ ├── test_file
│ ├── tests.torrent
│ ├── tree_index_test.torrent
│ ├── ubuntu-20.04.1-live-server-amd64.iso.torrent
│ └── web-seed.torrent
├── test_create.cpp
├── test_edit.cpp
├── test_file_matcher.cpp
├── test_info.cpp
├── test_ls_colors.cpp
├── test_magnet.cpp
├── test_main.cpp
├── test_pad.cpp
├── test_profile.cpp
├── test_resources.hpp
├── test_show.cpp
├── test_tracker_database.cpp
├── test_tree_view.cpp
├── test_utils.cpp
└── test_verify.cpp
================================================
FILE CONTENTS
================================================
================================================
FILE: .dockerignore
================================================
.github/
.vscode/
cmake-build-*/
Dockerfile
.dockerignore
================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms
github: fbdtemme
================================================
FILE: .github/workflows/documentation.yml
================================================
name: Documentation
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Install dependencies
run: |
sudo python3 -m pip install sphinx
sudo python3 -m pip install furo
- name: Configure
run: |
mkdir build
cmake -B build -S . \
-DTORRENTTOOLS_BUILD_CORE=OFF \
-DTORRENTTOOLS_BUILD_TESTS=OFF \
-DTORRENTTOOLS_INSTALL=OFF \
-DTORRENTTOOLS_BUILD_DOCS=ON \
-DTORRENTTOOLS_TBB=OFF
- name: build
run: cmake --build build --target Sphinx
- name: Deploy to GitHub Pages
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BRANCH: gh-pages
FOLDER: build/docs/sphinx
CLEAN: true
================================================
FILE: .github/workflows/linux.yml
================================================
name: Linux
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: Build
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Install build dependencies
run: sudo apt-get install -y libstdc++-10-dev g++-10 gcc-10 cmake libssl-dev libtbb-dev libre2-dev libyaml-cpp-dev nlohmann-json3-dev
- name: Configure
run: |
cmake -S . -B cmake-build-debug -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_BUILD_TYPE=Debug -DTORRENTTOOLS_BUILD_TESTS=ON
- name: Build
run: cmake --build cmake-build-debug
- name: Save build artifacts
uses: actions/upload-artifact@v2
with:
name: torrenttools-binaries
path: |
cmake-build-debug
!cmake-build-debug/_deps
retention-days: 1
test:
name: Test
needs: Build
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Install runtime dependencies
run: sudo apt-get install -y libstdc++-10-dev g++-10 gcc-10 libssl-dev libtbb-dev libre2-dev libyaml-cpp-dev nlohmann-json3-dev
- name: Download build artifacts
uses: actions/download-artifact@v2
with:
name: torrenttools-binaries
path: cmake-build-debug
- name: Display structure of downloaded files
run: ls -R
- name: Test
run: |
chmod +x cmake-build-debug/tests/torrenttools-tests
cd cmake-build-debug && ctest
================================================
FILE: .github/workflows/macos.yml
================================================
name: macOS
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: Build
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Install build dependencies
run: |
brew install cmake
brew install gcc
brew install openssl
brew install autoconf
brew install automake
brew install libtool
brew install nasm
- name: Configure
run: |
cmake -G "Unix Makefiles" -S . -B cmake-build-debug \
-DCMAKE_CXX_COMPILER=g++-11 \
-DCMAKE_C_COMPILER=gcc-11 \
-DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl@1.1/1.1.1l \
-DCMAKE_BUILD_TYPE=Debug \
-DTORRENTTOOLS_BUILD_TESTS=ON \
-DTORRENTTOOLS_TBB=OFF \
-DDOTTORRENT_MB_CRYPTO_LIB=isal \
-DDOTTORRENT_CRYPTO_LIB=openssl
- name: Build
run: cmake --build cmake-build-debug
- name: Save build artifacts
uses: actions/upload-artifact@v2
with:
name: torrenttools-binaries-macos
path: |
cmake-build-debug
!cmake-build-debug/_deps
retention-days: 1
test:
name: Test
needs: Build
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Install runtime dependencies
run: |
brew install cmake
brew install gcc
brew install openssl
- name: Download build artifacts
uses: actions/download-artifact@v2
with:
name: torrenttools-binaries-macos
path: cmake-build-debug
- name: Display structure of downloaded files
run: ls -R
- name: Test
run: |
chmod +x cmake-build-debug/tests/torrenttools-tests
cd cmake-build-debug && ctest
================================================
FILE: .github/workflows/package.yml
================================================
name: Package
on:
workflow_dispatch:
branches: [ main, develop ]
inputs:
linux:
description: 'Create a linux AppImage'
required: true
default: 'on'
windows:
description: 'Create a windows installer'
required: true
default: 'on'
macos:
description: 'Create a macOS installer'
required: true
default: 'on'
jobs:
package-tarball:
name: "Tarball"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install build dependencies
run: sudo apt-get install -y libstdc++-10-dev g++-10 gcc-10 cmake libssl-dev libtbb-dev libre2-dev libyaml-cpp-dev nlohmann-json3-dev
- name: Fetch external projects
run: scripts/fetch_dependencies.sh
- name: Configure
run: |
cmake -S . -B cmake-build-release -DCMAKE_CXX_COMPILER=g++-10 -DCMAKE_BUILD_TYPE=Release -DTORRENTTOOLS_BUILD_TESTS=ON
- name: Build tarball
working-directory: cmake-build-release
run: |
cpack --config CPackSourceConfig.cmake -G TGZ
- name: Determine Version
id: cmake_version
run: |
CMAKE_PROJECT_VERSION=$(grep -oP "(?<=CMAKE_PROJECT_VERSION:STATIC=).*" cmake-build-release/CMakeCache.txt)
echo "::set-output name=cmake_project_version::${CMAKE_PROJECT_VERSION}"
echo "${CMAKE_PROJECT_VERSION}" > version.txt
- name: Save version.txt
uses: actions/upload-artifact@v2
with:
name: version.txt
path: version.txt
retention-days: 1
- name: Upload tarball as artifact
uses: actions/upload-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz
path: cmake-build-release/torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz
retention-days: 1
package-windows:
name: "Windows installer"
if: ${{ github.event.inputs.windows == 'on' }}
runs-on: windows-latest
needs: [ package-tarball ]
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
update: true
install: >-
make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-yasm
mingw-w64-x86_64-openssl
mingw-w64-x86_64-intel-tbb
- name: Download version file
uses: actions/download-artifact@v2
with:
name: version.txt
- name: Retrieve version
id : cmake_version
run: |
CMAKE_PROJECT_VERSION="$(cat version.txt)"
echo "::set-output name=cmake_project_version::${CMAKE_PROJECT_VERSION}"
- name: Download tarball artifact
uses: actions/download-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz
- name: Unpack sources tarball
run: |
tar -zxf torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz \
--exclude torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}/external/CLI11/tests \
--exclude torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}/packages/ubuntu
- name: Configure
run: |
cmake -G "MSYS Makefiles" \
-B cmake-build-release \
-S torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }} \
-DDOTTORRENT_CRYPTO_LIB=openssl \
-DDOTTORRENT_MB_CRYPTO_LIB=isal \
-DCMAKE_BUILD_TYPE=Release \
-DTORRENTTOOLS_BUILD_TESTS=OFF \
-DTORRENTTOOLS_BUILD_DOCS=OFF
- name: Build
run: cmake --build cmake-build-release --target torrenttools
- name: Check linkage
run: ldd cmake-build-release/torrenttools.exe
- name: Package
run: |
cd cmake-build-release
cpack --verbose -G WIX
- name: Upload installer as artifact
uses: actions/upload-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}-windows-x86_64.msi
path: cmake-build-release/torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.msi
retention-days: 1
package-macos:
name: "macOS installer"
if: ${{ github.event.inputs.macos == 'on' }}
runs-on: macos-latest
needs: [ package-tarball ]
steps:
- name: Download version file
uses: actions/download-artifact@v2
with:
name: version.txt
- name: Retrieve version
id: cmake_version
run: |
CMAKE_PROJECT_VERSION="$(cat version.txt)"
echo "::set-output name=cmake_project_version::${CMAKE_PROJECT_VERSION}"
- name: Download tarball artifact
uses: actions/download-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz
- name: Unpack sources tarball
run: |
tar -zxf torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz \
--exclude torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}/external/CLI11/tests
- name: Install build dependencies
run: |
brew install cmake
brew install gcc
brew install openssl
brew install autoconf
brew install automake
brew install libtool
brew install nasm
- name: List working dir
run: ls -al .
- name: Configure
run: |
cmake -G "Unix Makefiles" \
-B cmake-build-release \
-S torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }} \
-DCMAKE_CXX_COMPILER=g++-11 \
-DCMAKE_C_COMPILER=gcc-11 \
-DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl@1.1/1.1.1l \
-DCMAKE_BUILD_TYPE=Release \
-DTORRENTTOOLS_BUILD_TESTS=OFF \
-DTORRENTTOOLS_TBB=OFF \
-DDOTTORRENT_MB_CRYPTO_LIB=isal \
-DDOTTORRENT_CRYPTO_LIB=openssl
- name: Build
run: cmake --build cmake-build-release
- name: Package
run: |
cd cmake-build-release
cpack --verbose -G productbuild
- name: Upload installer as artifact
uses: actions/upload-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}-macos-x86_64.pkg
path: cmake-build-release/torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.pkg
retention-days: 1
package-linux:
name: "Linux AppImage"
if: ${{ github.event.inputs.linux == 'on' }}
runs-on: ubuntu-20.04
needs: [ package-tarball ]
steps:
- name: Download version file
uses: actions/download-artifact@v2
with:
name: version.txt
- name: Retrieve version
id: cmake_version
run: |
CMAKE_PROJECT_VERSION="$(cat version.txt)"
echo "::set-output name=cmake_project_version::${CMAKE_PROJECT_VERSION}"
- name: Download tarball artifact
uses: actions/download-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz
- name: Unpack sources tarball
run: |
tar -zxf torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}.tar.gz \
--exclude torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}/external/CLI11/tests
- name: Install build dependencies
run: |
sudo apt-get install -y libstdc++-10-dev g++-10 gcc-10 cmake \
libssl-dev libtbb-dev nasm libtool automake autoconf
- name: Configure
run: |
cmake -S torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }} \
-B cmake-build-release \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_COMPILER=g++-10 \
-DTORRENTTOOLS_BUILD_TESTS=OFF \
-DDOTTORRENT_MB_CRYPTO_LIB=isal \
-DDOTTORRENT_CRYPTO_LIB=openssl \
-DSYSCONF_INSTALL_DIR=/etc
- name: Build
run: cmake --build cmake-build-release --target torrenttools
- name: Prepare AppDir
run: |
SRCDIR="torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}"
DESTDIR=AppDir cmake --install cmake-build-release --prefix=/usr --component torrenttools
mkdir -p AppDir/usr/share/icons/256x256/apps
cp $SRCDIR/resources/icons/256x256/torrenttools.png AppDir/usr/share/icons/256x256/apps/
mkdir -p AppDir/usr/share/applications/
cp $SRCDIR/packages/appimage/torrenttools.desktop AppDir/usr/share/applications/torrenttools.desktop
- name: Build AppImage
uses: AppImageCrafters/build-appimage@master
with:
recipe: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}/packages/appimage/torrenttools-appimage-recipe.yml
env:
UPDATE_INFO: gh-releases-zsync|AppImageCrafters|appimage-demo-qt5|latest|*x86_64.AppImage.zsync
- name: Upload AppImage as artifact
uses: actions/upload-artifact@v2
with:
name: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}-x86_64.AppImage
path: torrenttools-${{ steps.cmake_version.outputs.cmake_project_version }}-x86_64.AppImage
retention-days: 1
================================================
FILE: .github/workflows/windows.yml
================================================
name: Windows
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
name: Build
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
update: true
install: >-
make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-yasm
mingw-w64-x86_64-openssl
mingw-w64-x86_64-intel-tbb
- uses: actions/checkout@v2
- name: Configure
run: |
mkdir build;
cmake --help
cmake -G "MSYS Makefiles" -B cmake-build-debug -S . \
-DDOTTORRENT_CRYPTO_LIB=openssl \
-DDOTTORRENT_MB_CRYPTO_LIB=isal \
-DCMAKE_BUILD_TYPE=Debug \
-DTORRENTTOOLS_BUILD_TESTS=ON \
-DTORRENTTOOLS_BUILD_DOCS=OFF
- name: Build
run: cmake --build cmake-build-debug
- name: Save build artifacts
uses: actions/upload-artifact@v2
with:
name: torrenttools-binaries-windows
path: |
cmake-build-debug
!cmake-build-debug/_deps
retention-days: 1
test:
name: Test
needs: Build
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: msys2/setup-msys2@v2
with:
update: true
install: >-
make
mingw-w64-x86_64-cmake
mingw-w64-x86_64-toolchain
mingw-w64-x86_64-yasm
mingw-w64-x86_64-openssl
mingw-w64-x86_64-intel-tbb
- uses: actions/checkout@v2
- name: Download build artifacts
uses: actions/download-artifact@v2
with:
name: torrenttools-binaries-windows
path: cmake-build-debug
- name: Display structure of downloaded files
run: ls -R
- name: Test
run: |
chmod +x cmake-build-debug/tests/torrenttools-tests
cd cmake-build-debug && ctest
================================================
FILE: .gitignore
================================================
venv/**
**/.idea/**
**/.vscode/**
**/cmake-build-*/**
**/.DS_Store
================================================
FILE: CHANGELOG.md
================================================
# Changelog
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## [v0.6.2] - 2021-08-31
### Changed
* Workaround crashes on Windows due to re2 with MinGW issues.
## [v0.6.1] - 2021-08-07
### Added
* Add missing --simple-progress option.
### Changed
* Fix issues with torrents containing one file under the root directory. (#22)
## [v0.6.0] - 2021-08-02
### Added
* Enable new metafiles for cross-seeding by default.
* Add versions of crypto backends to --version output
### Changed
* Read user-config location from XDG_CONFIG_HOME on linux.
* Fix macOS installer bundling system library leading to linking errors.
* Add support for more trackers in the default trackers.json file (thanks @Audionut)
* Fix freeze when LS_COLORS contains 8-bit or 24-bit colors.
* Increase re2 compiler memory to support long regexes.
## [v0.5.1] - 2021-07-26
### Changed
* Fix misconfiguration of global config directory on linux.
## [v0.5.0] - 2021-07-25
### Added
* Add support for windows and macOS.
* Add support for create and edit profiles.
* Add missing show subcommands and info entries for dht-nodes and web-seeds.
* Add support for BEP 38: Finding Local Data Via Torrent File Hints (#9).
* Add support for BEP-17: http-seeding (#8).
* Add support for printing per-file checksums in sha1sum format (#7)
* Add progress reporting while scanning for files. (#10)
### Changed
* Improve formatting of info command output.
* Fix invalid v1 infohash reporting for hybrid torrents.
* Fix rare race condition in progress bar causing deadlocks.
* Report progress when scanning filesystem and preparing metafile.
* Optionally accelerate sorting when linked to Intel TBB.
* Skip file tree for metafiles with more than 1000 files.
* Fix v2 and hybrid issues with empty files.
## [v0.4.1] - 2021-04-15
### Changed
* Fix undefined behaviour in verify command when output is piped.
* Fix missing progress lines for create command when output is piped.
## [v0.4.0] - 2021-04-10
### Added
* Add named tracker groups.
* Add `--config` and `--trackers-config` to pass custom configuration files locations.
* Add colored file tree using LS_COLORS environment variable.
* Add docker container.
* Add limited wolfssl support.
### Changed
* Fix progressbar for verify command.
* Fix hybrid torrent issues for both v1 and v2 verification.
* Fix infinite loop on unrecoverable IO error during hashing.
* Fix threads options ignored when verifying.
* Fix progress reporting when there are no files inside the torrent.
* Fix issue with worker threads exiting due to uninitialized stop state.
## [v0.3.2] - 2021-02-20
### Changed
* Fix announce url substitution overriding announce url
## [v0.3.1] - 2021-02-19
### Changed
* Fix regression in create command --output option.
## [v0.3.0] - 2021-02-19
### Added
* Faster hashing backend using Intel ISA-L Crypto multi-buffer hashing.
* Read target name from input stream.
### Changed
* Fix announce url not properly set for single tracker metafiles.
* Progress bar now shows total progress instead of per-file progress and ETA.
* Reduced resource consumption by removing busy waiting.
## [v0.2.2] - 2021-01-30
### Changed
* Fix source tag not being set in create command.
## [v0.2.1] - 2021-01-28
### Added
* magnet command to generate magnet URI's from a bittorrent metafile.
* Simpler progress reporting when output is piped (eg. ruTorrent task output).
* Add "show size" command.
### Changed
* Fix race triggered when hashing multiple small files in v2 hasher.
## [v0.2.0] - 2021-01-25
### Added
* Add experimental windows support and installer.
* Add show command to query specific fields of a metafile.
* Add edit command to edit an existing metafile.
* Add "--creation-date" option to override the creation date.
* Add "--created-by" option to override the default created by string (program and version)
* Add "--stdout" options enable writing torrent file to the standard output.
* Add "--version" option to show program version.
### Changed
* Fix behavior of options accepting multiple values: "--announce", "--web-seeds", "--dht-nodes".
* Fix loading config files from user-local directory.
* Allow to include hidden files when they match an include regex without specifying the --include-hidden flag.
* Move query options of info to the new show command.
* Fix --name option being ignored.
* Fix multiple announce urls being invalidly serialized.
* Allow serialization of metafiles with zero-length files.
* Fix dht-node serialization and deserialization.
[comment]: <> (### Removed)
================================================
FILE: CMakeLists.txt
================================================
cmake_minimum_required(VERSION 3.15)
# Version string
cmake_policy(SET CMP0048 NEW)
cmake_policy(SET CMP0077 NEW)
if (UNIX AND NOT APPLE)
set(LINUX TRUE)
endif()
project(torrenttools
DESCRIPTION "A commandline tool for creating, inspecting and modifying BitTorrent metafiles."
LANGUAGES CXX
VERSION 0.6.2
HOMEPAGE_URL https://www.github.com/fbdtemme/torrenttools)
# Make Find modules in cmake dir available
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
if (APPLE)
set(CMAKE_INSTALL_NAME_DIR "@executable_path/../lib")
endif()
if (TORRENTTOOLS_PACKAGES_ONLY)
include(packages/packages.cmake)
return()
endif()
include(CTest)
include(GNUInstallDirs)
# Path including images, config files etc
set(RESOURCES_DIR "${CMAKE_CURRENT_SOURCE_DIR}/resources")
include(CMakeDependentOption)
option(TORRENTTOOLS_BUILD_TESTS
"Build tests" OFF)
cmake_dependent_option(TORRENTTOOLS_BUILD_TESTS_COVERAGE
"Build tests with coverage." OFF "TORRENTTOOLS_BUILD_TESTS" OFF)
option(TORRENTTOOLS_BUILD_DOCS
"Generate documentation" OFF)
option(TORRENTTOOLS_INSTALL
"Generate an install target" ON)
option(TORRENTTOOLS_TBB "Accelerate using Intel TBB library." ON)
#add_subdirectory(../cliprogress cliprogress)
#add_subdirectory(../dottorrent dottorrent)
#add_subdirectory(../termcontrol termcontrol)
#add_subdirectory(../bencode bencode)
include(external/external.cmake)
if (TORRENTTOOLS_TBB)
find_package(TBB REQUIRED)
endif()
add_executable(torrenttools
src/app_data.cpp
src/argument_parsers.cpp
src/common.cpp
src/config_parser.cpp
src/create.cpp
src/main_app.cpp
src/edit.cpp
src/escape_binary_fields.cpp
src/formatters.cpp
src/indicator.cpp
src/info.cpp
src/magnet.cpp
src/main.cpp
src/pad.cpp
src/progress.cpp
src/show.cpp
src/tracker_database.cpp
src/tree_view.cpp
src/verify.cpp
src/profile.cpp
src/ls_colors.cpp
)
target_include_directories(torrenttools PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_features(torrenttools PUBLIC cxx_std_20)
target_link_libraries(torrenttools PRIVATE
dottorrent::dottorrent
termcontrol::termcontrol
cliprogress::cliprogress
fmt::fmt
date::date
gsl::gsl-lite-v1
CLI11::CLI11
re2::re2
yaml-cpp
nlohmann_json::nlohmann_json
)
if (TORRENTTOOLS_TBB)
message(STATUS "Using Intel TBB library.")
target_link_libraries(torrenttools PRIVATE TBB::tbb)
target_compile_definitions(torrenttools PRIVATE TORRENTTOOLS_USE_TBB)
endif()
# Set the linker to lld to get decent link times on MinGW
if (MINGW)
find_program(HAS_LLD_LINKER "lld")
if (HAS_LLD_LINKER)
message(STATUS "Using lld linker for MinGW generator.")
target_link_options(torrenttools PRIVATE -fuse-ld=lld)
endif()
endif()
if (TORRENTTOOLS_BUILD_TESTS)
add_subdirectory(tests)
endif()
if(TORRENTTOOLS_BUILD_DOCS)
add_subdirectory(docs)
endif()
# Set the install prefix to /usr/local/bin/torrenttools
message(DEBUG ${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT})
if (MINGW OR WIN32)
# Set the install prefix to Program Files instead of Program Files (x86)
message(DEBUG ${CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT})
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
message(DEBUG "Changing default install prefix")
SET(CMAKE_INSTALL_PREFIX "C:/Program Files/${PROJECT_NAME}" CACHE PATH
"Install path prefix, prepended onto install directories." FORCE)
endif()
elseif (APPLE)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
message(DEBUG "Changing default install prefix")
set(CMAKE_INSTALL_PREFIX "/Library/${PROJECT_NAME}" CACHE PATH
"Install path prefix, prepended onto install directories." FORCE)
endif()
endif()
message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
## Load the sysconf install dir as set by the RPM and DEB
if(NOT DEFINED SYSCONF_INSTALL_DIR)
set(SYSCONF_INSTALL_DIR ${CMAKE_INSTALL_FULL_SYSCONFDIR})
message(DEBUG "Setting SYSCONF_INSTALL_DIR: ${SYSCONF_INSTALL_DIR}")
else()
message(DEBUG "Setting SYSCONF_INSTALL_DIR: ${SYSCONF_INSTALL_DIR}")
endif()
# torrenttools_sysconf_dir: Full path used to lookup system scope configuration files.
if (LINUX)
set(torrenttools_sysconf_dir "${SYSCONF_INSTALL_DIR}/torrenttools")
elseif (WIN32)
# Dump everything in the install prefix on windows
set(torrenttools_sysconf_dir "${CMAKE_INSTALL_PREFIX}")
elseif (APPLE)
set(torrenttools_sysconf_dir "${CMAKE_INSTALL_PREFIX}/etc")
endif ()
message(STATUS "Install sysconf dir: ${torrenttools_sysconf_dir}")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/include/config.hpp)
if (TORRENTTOOLS_INSTALL)
if (LINUX)
# install trackers to system config dir since it is global data.
install(FILES resources/trackers.json
resources/config.yml
COMPONENT torrenttools
DESTINATION ${torrenttools_sysconf_dir})
# install executable
install(TARGETS torrenttools
COMPONENT torrenttools
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if (MINGW OR WIN32)
# install resources in the install prefix
install(FILES resources/trackers.json
resources/config.yml
COMPONENT torrenttools
DESTINATION ".")
# install executable
install(TARGETS torrenttools
COMPONENT torrenttools
RUNTIME DESTINATION ".")
# Install mingw shared libraries to the project dir
# Filter out core windows libraries with regex
install(CODE [[
set(LIBRARY_PATH $ENV{PATH})
string(REPLACE "\\" "/" LIBRARY_PATH "${LIBRARY_PATH}")
message(STATUS "Searching for libraries in: ${LIBRARY_PATH}")
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:torrenttools>
DIRECTORIES ${LIBRARY_PATH}
RESOLVED_DEPENDENCIES_VAR _r_deps
UNRESOLVED_DEPENDENCIES_VAR _u_deps
PRE_EXCLUDE_REGEXES ".*-ms-win-.*" ".*ext-ms-.*"
POST_INCLUDE_REGEXES ".*libcrypto.*"
POST_EXCLUDE_REGEXES ".*system32.*"
)
foreach(_file ${_r_deps})
file(INSTALL ${_file}
DESTINATION "${CMAKE_INSTALL_PREFIX}"
FOLLOW_SYMLINK_CHAIN)
endforeach()
list(LENGTH _u_deps _u_length)
if("${_u_length}" GREATER 0)
message(STATUS "${_u_deps}")
message(WARNING "Unresolved dependencies detected!")
foreach(_u_dep ${_u_deps})
message(WARNING "Dependency unresolved: ${_u_dep}")
endforeach()
endif()
]]
COMPONENT torrenttools)
endif()
if (APPLE)
# install executable
install(TARGETS torrenttools
COMPONENT torrenttools
DESTINATION "bin")
# install configuration
install(FILES resources/trackers.json
resources/config.yml
COMPONENT torrenttools
DESTINATION "etc")
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES $<TARGET_FILE:torrenttools>
DIRECTORIES "/usr/bin/local/Cellar" "/usr/bin/local"
RESOLVED_DEPENDENCIES_VAR _r_deps
UNRESOLVED_DEPENDENCIES_VAR _u_deps
PRE_EXCLUDE_REGEXES ".*libSystem.B.*"
)
foreach(_file ${_r_deps})
file(INSTALL ${_file}
DESTINATION "${CMAKE_INSTALL_PREFIX}/lib"
FOLLOW_SYMLINK_CHAIN)
get_filename_component(_file_name "${_file}" NAME)
execute_process(COMMAND install_name_tool -change "${_file}" "@executable_path/../lib/${_file_name}" "${CMAKE_INSTALL_PREFIX}/bin/torrenttools" )
endforeach()
list(LENGTH _u_deps _u_length)
if("${_u_length}" GREATER 0)
message(STATUS "${_u_deps}")
message(WARNING "Unresolved dependencies detected!")
foreach(_u_dep ${_u_deps})
message(WARNING "Dependency unresolved: ${_u_dep}")
endforeach()
endif()
]]
COMPONENT torrenttools)
endif()
endif()
include(packages/packages.cmake)
================================================
FILE: Dockerfile
================================================
FROM alpine:latest AS build-stage
RUN apk add --update-cache \
git \
make \
cmake \
autoconf \
automake \
libtool \
g++ \
nasm \
openssl-dev \
libtbb-dev
# Copy source files
#COPY . /torrenttools
#WORKDIR /torrenttools
ENV VERSION="0.5.0"
RUN wget "https://github.com/fbdtemme/torrenttools/releases/download/v$VERSION/torrenttools-$VERSION.tar.gz"
RUN tar -xzf "torrenttools-$VERSION.tar.gz"
RUN mv torrenttools-$VERSION torrenttools
# Generate build files
RUN cmake -S torrenttools -B cmake-build-relwithdebinfo \
-DCMAKE_CXX_COMPILER=g++ \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DTORRENTTOOLS_BUILD_TESTS=OFF \
-DTORRENTTOOLS_BUILD_DOCS=OFF \
-DDOTTORRENT_MB_CRYPTO_LIB=isal
# Build
RUN cd cmake-build-relwithdebinfo && make -j$(nproc) torrenttools
FROM alpine:latest AS runtime
RUN apk add --update-cache openssl libtbb
COPY --from=build-stage cmake-build-relwithdebinfo/torrenttools /usr/bin/
RUN chmod +x "/usr/bin/torrenttools"
ENTRYPOINT ["/usr/bin/torrenttools"]
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Florian De Temmerman
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================


[](https://copr.fedorainfracloud.org/coprs/fbdtemme/torrenttools/package/torrenttools/)
[](https://github.com/fbdtemme/torrenttools/releases)
[](https://isocpp.org/)
[](https://app.codacy.com/manual/floriandetemmerman/torrenttools?utm_source=github.com&utm_medium=referral&utm_content=fbdtemme/bencode&utm_campaign=Badge_Grade_Dashboard)
[](https://opensource.org/licenses/MIT)
A commandline tool for creating, inspecting and modifying bittorrent metafiles.
[**Features**](#Status) |
[**Documentation**](#Documentation) |
[**Binary releases**](#binary-releases) |
[**Building**](#Building) |
[**License**](#License)
## Features
* Creating bittorrent metafiles.
* Inspecting bittorrent metafiles.
* Verifying bittorrent metafiles against local data.
* Editing existing bittorrent metafiles.
* Support for the new [v2 and hybrid protocols](https://blog.libtorrent.org/2020/09/bittorrent-v2/) .
* Support for tracker abbreviations.
* Support for announce substitution parameters.
* Fast multi-buffer hashing with Intel ISA-L.
## Example

## Status
This project is under development.
The commandline interface can change at any release prior to 1.0.0.
## Performance
Following test were performed on a in in-memory filesystem with 1 MiB piece size
and as target a file filed with random data totalling 15.0 GiB:
The tested CPU is an Intel i7-7700HQ in a Dell XPS 15-9560 machine.

## Documentation
Documentation is hosted on [Github Pages](https://fbdtemme.github.io/torrenttools/).
## Binary releases
### Contents
* [Windows](#Windows)
* [macOS](#macOS)
* [Linux](#Linux)
* [Fedora](#Fedora)
* [CentOS](#CentOS/RHEL)
* [Ubuntu](#Ubuntu)
* [Debian](#Debian)
* [Ubuntu](#Ubuntu)
* [OpenSUSE](#OpenSUSE)
* [SUSE Linux Enterprise Server](#SUSE-Linux-Enterprise-Server-15)
* [Arch](#Arch)
* [AppImage](#AppImage)
* [Docker](#inux)
### Windows
An .msi installer is available as a [release asset](https://github.com/fbdtemme/torrenttools/releases).
__IMPORTANT: Please use a modern terminal that supports most ANSI escape codes, like [Windows Terminal](https://www.microsoft.com/en-us/p/windows-terminal/9n0dx20hk701) (not cmd or PowerShell).__
### macOS
A .pkg installer is available as a [release asset](https://github.com/fbdtemme/torrenttools/releases).
### Linux
#### Fedora
Binary and source packages for Fedora 32, Fedora 33, Fedora 34 and Fedora Rawhide and CentOS
stream are available in a [COPR repo](https://copr.fedorainfracloud.org/coprs/fbdtemme/torrenttools/).
```shell
sudo dnf copr enable fbdtemme/torrenttools
sudo dnf install torrenttools
```
#### CentOS/RHEL
Binary and source packages for CentOS8/RHEL8 and CentOS stream are available
in a [COPR repo](https://copr.fedorainfracloud.org/coprs/fbdtemme/torrenttools/).
```shell
sudo dnf copr enable fbdtemme/torrenttools
sudo dnf install torrenttools
```
#### Ubuntu
Binary and source packages for Ubuntu 20.04, Ubuntu 20.10, Ubuntu 21.04 are available
as a PPA via [launchpad](https://launchpad.net/torrenttools).
```shell
sudo add-apt-repository ppa:fbdtemme/torrenttools
sudo apt-get update
sudo apt install torrenttools
```
#### Debian
A binary package is available for Debian Sid.
Older debian distributions should use the AppImage.
```shell
echo 'deb http://download.opensuse.org/repositories/home:/fbdtemme/Debian_Unstable/ /' | sudo tee /etc/apt/sources.list.d/home:fbdtemme.list
curl -fsSL https://download.opensuse.org/repositories/home:fbdtemme/Debian_Unstable/Release.key | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/home_fbdtemme.gpg > /dev/null
sudo apt update
sudo apt install torrenttools
```
#### openSUSE
For openSUSE Tumbleweed run the following as root:
```shell
zypper addrepo https://download.opensuse.org/repositories/home:fbdtemme/openSUSE_Tumbleweed/home:fbdtemme.repo
zypper refresh
zypper install torrenttools
```
For openSUSE Leap 15.2 run the following as root:
```shell
zypper addrepo https://download.opensuse.org/repositories/home:fbdtemme/openSUSE_Leap_15.2/home:fbdtemme.repo
zypper refresh
zypper install torrenttools
```
For openSUSE Leap 15.3 run the following as root:
```shell
zypper addrepo https://download.opensuse.org/repositories/home:fbdtemme/openSUSE_Leap_15.3/home:fbdtemme.repo
zypper refresh
zypper install torrenttools
```
#### SUSE Linux Enterprise Server 15
For SLE 15 SP2 run the following as root:
```shell
zypper addrepo https://download.opensuse.org/repositories/home:fbdtemme/SLE_15_SP2/home:fbdtemme.repo
zypper refresh
zypper install torrenttools
```
For SLE 15 SP3 run the following as root:
```shell
zypper addrepo https://download.opensuse.org/repositories/home:fbdtemme/SLE_15_SP3/home:fbdtemme.repo
zypper refresh
zypper install torrenttools
```
#### Arch
A source package for Arch linux is available on [AUR](https://aur.archlinux.org/packages/torrenttools/).
```shell
git clone https://aur.archlinux.org/torrenttools.git
cd torrenttools
makepkg -is
```
#### AppImage
Distributions that have no package yet can use the AppImage that is available for download as a [release asset](https://github.com/fbdtemme/torrenttools/releases).
### Docker
A docker image is available on [dockerhub](https://hub.docker.com/repository/docker/fbdtemme/torrenttools).
```shell
docker pull fbdtemme/torrenttools
```
## Building
This library depends on following projects:
* [CLI11](https://github.com/CLIUtils/CLI11)
* [Catch2](https://github.com/catchorg/Catch2)
* [CTRE](https://github.com/hanickadot/compile-time-regular-expressions)
* [gsl-lite](https://github.com/gsl-lite/gsl-lite)
* [RE2](https://github.com/google/re2)
* [expected-lite](https://github.com/martinmoene/expected-lite)
* [fmt](https://github.com/fmtlib/fmt)
* [nlohmann/json](https://github.com/nlohmann/json)
* [yaml-cpp](https://github.com/jbeder/yaml-cpp)
* [bencode](https://github.com/fbdtemme/bencode)
* [date](https://github.com/HowardHinnant/date)
* [OpenSSL](https://github.com/openssl/openssl)
* Optional: [ISA-L Crypto](https://github.com/intel/isa-l_crypto)
Almost all dependencies can be fetched from github during configure time or can be installed manually.
OpenSSL has to be installed on the system in advance.
### Installing build dependencies
Ubuntu
```shell
sudo apt install build-essential git cmake g++-10 libssl-dev
```
Debian
```shell
sudo apt install build-essential git cmake g++-10 libssl-dev libtbb-dev
```
Fedora/RHEL/CentOS
```shell
sudo dnf install cmake make g++ git openssl-devel automake autoconf
```
### Configuration
| Option | Type | Description |
|--------------------------------|----------|------------------------------|
| TORRENTTOOLS_BUILD_TESTS | Bool | Build tests. |
| TORRENTTOOLS_BUILD_DOCS | Bool | Build documentation. |
| TORRENTTOOLS_INSTALL | Bool | Generate an install target. |
| DOTTORRENT_MB_CRYPTO_LIB | String | Pass "isal" for fast multibuffer hashing |
### Building
This project requires C++20.
Currently only GCC 10 or later is supported.
This project can be build as every other project which makes use of the CMake build system.
```{bash}
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --target torrenttools
```
### Installation
Installing the project:
```{bash}
sudo cmake --install . --component torrentttools
```
## License
Distributed under the MIT license. See `LICENSE` for more information.
================================================
FILE: benchmark/benchmark.csv
================================================
threads,programs,speed_mean,speed_stddev
1,mktorrent,843.5375805340137,29.24016226983715
1,imdl,422.5956018664747,21.94521233645368
1,dottorrent-cli,465.43693577067035,5.708140591930167
1,pyrocore,694.6542989125322,28.286594276984108
1,transmission-create,694.7122046474267,38.43063952671966
1,py3createtorrent,768.842931714354,7.946207871730497
1,torf-cli,847.8770944894188,8.542897593491706
1,buildtorrent,465.63563386940734,3.906536033318984
1,torrenttools (OpenSSL),857.7468673905892,0.016150143162648407
1,torrenttools (ISA-L),2394.788777088055,25.55599825968731
2,mktorrent,1739.7457165731003,0.8165668598526372
2,imdl,422.5956018664747,21.94521233645368
2,dottorrent-cli,465.43693577067035,5.708140591930167
2,pyrocore,694.6542989125322,28.286594276984108
2,transmission-create,694.7122046474267,38.43063952671966
2,py3createtorrent,768.842931714354,7.946207871730497
2,torf-cli,1518.007777768706,20.55486136084764
2,buildtorrent,465.63563386940734,3.906536033318984
2,torrenttools (OpenSSL),1647.8120961785146,0.059603003086080776
2,torrenttools (ISA-L),4267.054895474759,138.34210665689523
3,mktorrent,2401.1029284404635,231.78107838447514
3,imdl,422.5956018664747,21.94521233645368
3,dottorrent-cli,465.43693577067035,5.708140591930167
3,pyrocore,694.6542989125322,28.286594276984108
3,transmission-create,694.7122046474267,38.43063952671966
3,py3createtorrent,768.842931714354,7.946207871730497
3,torf-cli,2026.5801897912054,28.28542069623083
3,buildtorrent,465.63563386940734,3.906536033318984
3,torrenttools (OpenSSL),2448.5222121223073,27.990338548381576
3,torrenttools (ISA-L),4255.814143177331,1.1925163622392736
4,mktorrent,3149.4450558966864,125.745768568161
4,imdl,422.5956018664747,21.94521233645368
4,dottorrent-cli,465.43693577067035,5.708140591930167
4,pyrocore,694.6542989125322,28.286594276984108
4,transmission-create,694.7122046474267,38.43063952671966
4,py3createtorrent,768.842931714354,7.946207871730497
4,torf-cli,2030.287245340613,17.163154357953065
4,buildtorrent,465.63563386940734,3.906536033318984
4,torrenttools (OpenSSL),3269.5331103167205,49.6780674007491
4,torrenttools (ISA-L),4258.630736286791,3.9837368331762373
================================================
FILE: benchmark/benchmark.ipynb
================================================
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.2-final"
},
"orig_nbformat": 2,
"kernelspec": {
"name": "python392jvsc74a57bd0767d51c1340bd893661ea55ea3124f6de3c7a262a8b4abca0554b478b1e2ff90",
"display_name": "Python 3.9.2 64-bit ('base': conda)"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import pandas as pd\n",
"import matplotlib.pyplot as plt\n",
"import re\n",
"from IPython.display import Javascript\n",
"import getpass"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"password = None\n",
"if password is None:\n",
" password = getpass.getpass()"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[sudo] password for fbdtemme: "
]
}
],
"source": [
"!echo $password | sudo -S mount -t tmpfs -o size=20g tmpfs /mnt/tmpfs/\n",
"!head -c 20G /dev/urandom > /mnt/tmpfs/data"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"pwd = \"/mnt/tmpfs\"\n",
"max_threads = 4\n",
"iterations = 3\n",
"target = 'data'"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"fs = !du -b $pwd/$target | grep -o \"[0-9]*\"\n",
"file_size = int(fs[0])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"21474836480"
]
},
"metadata": {},
"execution_count": 6
}
],
"source": [
"file_size"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[sudo] password for fbdtemme: Setting cpu: 0\n",
"Setting cpu: 1\n",
"Setting cpu: 2\n",
"Setting cpu: 3\n",
"Setting cpu: 4\n",
"Setting cpu: 5\n",
"Setting cpu: 6\n",
"Setting cpu: 7\n"
]
}
],
"source": [
"# Disable cpu frequency scaling\n",
"!echo $password | sudo -S cpupower frequency-set -g performance"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def parse_real_time(data: str):\n",
" results = []\n",
" match = re.search(R\"real\\s(\\d+)m([\\d.]+)s\", data)\n",
" minutes = float(match.group(1))\n",
" seconds = float(match.group(2))\n",
" return minutes * 60 + seconds\n",
"\n",
"def parse_real_time_sequence(data: str):\n",
" results = []\n",
" for match in re.findall(R\"real\\s(\\d+)m([\\d.]+)s\", data):\n",
" print(match[0])\n",
" print(match[1])\n",
" minutes = float(match[0])\n",
" seconds = float(match[1])\n",
" results.append(minutes * 60 + seconds)\n",
" return results"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"data = {}"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"def run_benchmark(name: str, use_threads:bool = True):\n",
" duration = np.ndarray(shape=(iterations, max_threads))\n",
" \n",
" if use_threads:\n",
" for t in range(1, max_threads+1):\n",
" for i in range(0, iterations):\n",
" result = !./benchmark.sh \"{name}\" \"{pwd}\" \"{target}\" \"{t}\"\n",
" result_str = '\\n'.join(result)\n",
" print(f\"-- iteration {i+1} | threads {t}\\n{result_str}\")\n",
" duration[i, t-1] = parse_real_time(result_str)\n",
" else:\n",
" for i in range(0, iterations):\n",
" t = 1\n",
" result = !./benchmark.sh \"{name}\" \"{pwd}\" \"{target}\" \"{t}\"\n",
" result_str = '\\n'.join(result)\n",
" print(f\"-- iteration {i+1} | threads {t}\\n{result_str}\")\n",
" duration[i, :] = parse_real_time(result_str)\n",
"\n",
" speed = file_size / duration\n",
" mean = np.mean(speed, axis=0)\n",
" std = np.std(speed, axis=0)\n",
" return (mean, std)"
]
},
{
"source": [
"### mktorrent"
],
"cell_type": "markdown",
"metadata": {}
},
{
"source": [
"mktorrent_data = run_benchmark(\"mktorrent\")"
],
"cell_type": "code",
"metadata": {},
"execution_count": 163,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m24.658s\n",
"user\t0m24.564s\n",
"sys\t0m4.014s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m26.743s\n",
"user\t0m26.588s\n",
"sys\t0m6.149s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m25.067s\n",
"user\t0m25.211s\n",
"sys\t0m4.936s\n",
"\n",
"-- iteration 1 | threads 2\n",
"\n",
"real\t0m12.336s\n",
"user\t0m24.587s\n",
"sys\t0m3.970s\n",
"\n",
"-- iteration 2 | threads 2\n",
"\n",
"real\t0m12.345s\n",
"user\t0m24.662s\n",
"sys\t0m3.876s\n",
"\n",
"-- iteration 3 | threads 2\n",
"\n",
"real\t0m12.350s\n",
"user\t0m24.630s\n",
"sys\t0m3.896s\n",
"\n",
"-- iteration 1 | threads 3\n",
"\n",
"real\t0m8.320s\n",
"user\t0m24.733s\n",
"sys\t0m4.106s\n",
"\n",
"-- iteration 2 | threads 3\n",
"\n",
"real\t0m8.427s\n",
"user\t0m25.103s\n",
"sys\t0m4.126s\n",
"\n",
"-- iteration 3 | threads 3\n",
"\n",
"real\t0m10.355s\n",
"user\t0m29.589s\n",
"sys\t0m5.067s\n",
"\n",
"-- iteration 1 | threads 4\n",
"\n",
"real\t0m7.202s\n",
"user\t0m28.176s\n",
"sys\t0m4.462s\n",
"\n",
"-- iteration 2 | threads 4\n",
"\n",
"real\t0m6.749s\n",
"user\t0m26.623s\n",
"sys\t0m4.683s\n",
"\n",
"-- iteration 3 | threads 4\n",
"\n",
"real\t0m6.538s\n",
"user\t0m25.863s\n",
"sys\t0m4.455s\n",
"\n"
]
}
]
},
{
"cell_type": "code",
"execution_count": 148,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m25.037s\n",
"user\t0m25.866s\n",
"sys\t0m4.253s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m25.036s\n",
"user\t0m25.846s\n",
"sys\t0m4.554s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m25.036s\n",
"user\t0m25.782s\n",
"sys\t0m4.581s\n",
"\n",
"-- iteration 1 | threads 2\n",
"\n",
"real\t0m13.032s\n",
"user\t0m26.208s\n",
"sys\t0m4.615s\n",
"\n",
"-- iteration 2 | threads 2\n",
"\n",
"real\t0m13.032s\n",
"user\t0m26.199s\n",
"sys\t0m4.722s\n",
"\n",
"-- iteration 3 | threads 2\n",
"\n",
"real\t0m13.033s\n",
"user\t0m26.259s\n",
"sys\t0m4.805s\n",
"\n",
"-- iteration 1 | threads 3\n",
"\n",
"real\t0m8.843s\n",
"user\t0m26.037s\n",
"sys\t0m4.552s\n",
"\n",
"-- iteration 2 | threads 3\n",
"\n",
"real\t0m8.631s\n",
"user\t0m25.714s\n",
"sys\t0m4.321s\n",
"\n",
"-- iteration 3 | threads 3\n",
"\n",
"real\t0m8.841s\n",
"user\t0m26.020s\n",
"sys\t0m4.430s\n",
"\n",
"-- iteration 1 | threads 4\n",
"\n",
"real\t0m6.640s\n",
"user\t0m25.525s\n",
"sys\t0m4.262s\n",
"\n",
"-- iteration 2 | threads 4\n",
"\n",
"real\t0m6.639s\n",
"user\t0m25.691s\n",
"sys\t0m4.259s\n",
"\n",
"-- iteration 3 | threads 4\n",
"\n",
"real\t0m6.430s\n",
"user\t0m25.464s\n",
"sys\t0m4.227s\n",
"\n"
]
}
],
"source": [
"torrenttools_openssl_data = run_benchmark(\"torrenttools_openssl\")"
]
},
{
"cell_type": "code",
"execution_count": 177,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m8.834s\n",
"user\t0m8.615s\n",
"sys\t0m4.127s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m9.036s\n",
"user\t0m8.813s\n",
"sys\t0m4.298s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m9.035s\n",
"user\t0m8.732s\n",
"sys\t0m4.267s\n",
"\n",
"-- iteration 1 | threads 2\n",
"\n",
"real\t0m4.839s\n",
"user\t0m9.246s\n",
"sys\t0m4.572s\n",
"\n",
"-- iteration 2 | threads 2\n",
"\n",
"real\t0m5.239s\n",
"user\t0m9.935s\n",
"sys\t0m4.668s\n",
"\n",
"-- iteration 3 | threads 2\n",
"\n",
"real\t0m5.036s\n",
"user\t0m9.433s\n",
"sys\t0m4.626s\n",
"\n",
"-- iteration 1 | threads 3\n",
"\n",
"real\t0m5.045s\n",
"user\t0m11.723s\n",
"sys\t0m4.717s\n",
"\n",
"-- iteration 2 | threads 3\n",
"\n",
"real\t0m5.048s\n",
"user\t0m12.280s\n",
"sys\t0m4.794s\n",
"\n",
"-- iteration 3 | threads 3\n",
"\n",
"real\t0m5.045s\n",
"user\t0m11.848s\n",
"sys\t0m4.781s\n",
"\n",
"-- iteration 1 | threads 4\n",
"\n",
"real\t0m5.036s\n",
"user\t0m12.315s\n",
"sys\t0m4.881s\n",
"\n",
"-- iteration 2 | threads 4\n",
"\n",
"real\t0m5.046s\n",
"user\t0m12.140s\n",
"sys\t0m4.872s\n",
"\n",
"-- iteration 3 | threads 4\n",
"\n",
"real\t0m5.046s\n",
"user\t0m12.136s\n",
"sys\t0m4.863s\n",
"\n"
]
}
],
"source": [
"torrenttools_isal_data = run_benchmark(\"torrenttools_isal\")"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m49.640s\n",
"user\t0m45.046s\n",
"sys\t0m4.038s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m48.473s\n",
"user\t0m44.369s\n",
"sys\t0m3.654s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m54.762s\n",
"user\t0m47.667s\n",
"sys\t0m5.675s\n",
"\n"
]
}
],
"source": [
"imdl_data = run_benchmark(\"imdl\", use_threads=False)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m45.398s\n",
"user\t0m32.861s\n",
"sys\t0m11.519s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m46.758s\n",
"user\t0m33.550s\n",
"sys\t0m12.022s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m46.282s\n",
"user\t0m33.563s\n",
"sys\t0m11.964s\n",
"\n"
]
}
],
"source": [
"dottorrent_cli_data = run_benchmark(\"dottorrent-cli\", use_threads=False)"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m29.641s\n",
"user\t0m25.230s\n",
"sys\t0m4.039s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m30.556s\n",
"user\t0m25.640s\n",
"sys\t0m4.534s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m32.703s\n",
"user\t0m26.834s\n",
"sys\t0m5.418s\n",
"\n"
]
}
],
"source": [
"pyrocore_data = run_benchmark(\"pyrocore\", use_threads=False)"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m33.512s\n",
"user\t0m26.585s\n",
"sys\t0m4.951s\n",
"\n",
"-- iteration 2 | threads 1\n",
"rm: cannot remove '*.torrent': No such file or directory\n",
"\n",
"real\t0m30.008s\n",
"user\t0m25.216s\n",
"sys\t0m4.041s\n",
"\n",
"-- iteration 3 | threads 1\n",
"rm: cannot remove '*.torrent': No such file or directory\n",
"\n",
"real\t0m29.511s\n",
"user\t0m25.037s\n",
"sys\t0m3.791s\n",
"\n"
]
}
],
"source": [
"transmission_create_data = run_benchmark(\"transmission-create\", use_threads=False)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"rm: cannot remove '*.torrent': No such file or directory\n",
"\n",
"real\t0m28.100s\n",
"user\t0m24.199s\n",
"sys\t0m3.405s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m27.531s\n",
"user\t0m23.952s\n",
"sys\t0m3.169s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m28.172s\n",
"user\t0m23.977s\n",
"sys\t0m3.270s\n",
"\n"
]
}
],
"source": [
"py3createtorrent_data = run_benchmark(\"py3createtorrent\", use_threads=False)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m25.609s\n",
"user\t0m23.964s\n",
"sys\t0m9.948s\n",
"\n",
"-- iteration 2 | threads 1\n",
"\n",
"real\t0m24.994s\n",
"user\t0m23.313s\n",
"sys\t0m9.235s\n",
"\n",
"-- iteration 3 | threads 1\n",
"\n",
"real\t0m25.388s\n",
"user\t0m23.761s\n",
"sys\t0m9.512s\n",
"\n",
"-- iteration 1 | threads 2\n",
"\n",
"real\t0m13.950s\n",
"user\t0m24.642s\n",
"sys\t0m10.750s\n",
"\n",
"-- iteration 2 | threads 2\n",
"\n",
"real\t0m14.088s\n",
"user\t0m24.869s\n",
"sys\t0m11.001s\n",
"\n",
"-- iteration 3 | threads 2\n",
"\n",
"real\t0m14.410s\n",
"user\t0m25.176s\n",
"sys\t0m11.003s\n",
"\n",
"-- iteration 1 | threads 3\n",
"\n",
"real\t0m10.548s\n",
"user\t0m25.179s\n",
"sys\t0m10.208s\n",
"\n",
"-- iteration 2 | threads 3\n",
"\n",
"real\t0m10.801s\n",
"user\t0m24.889s\n",
"sys\t0m10.453s\n",
"\n",
"-- iteration 3 | threads 3\n",
"\n",
"real\t0m10.447s\n",
"user\t0m24.213s\n",
"sys\t0m10.145s\n",
"\n",
"-- iteration 1 | threads 4\n",
"\n",
"real\t0m10.540s\n",
"user\t0m27.706s\n",
"sys\t0m10.462s\n",
"\n",
"-- iteration 2 | threads 4\n",
"\n",
"real\t0m10.492s\n",
"user\t0m28.131s\n",
"sys\t0m10.342s\n",
"\n",
"-- iteration 3 | threads 4\n",
"\n",
"real\t0m10.702s\n",
"user\t0m25.584s\n",
"sys\t0m10.397s\n",
"\n"
]
}
],
"source": [
"torf_data = run_benchmark(\"torf-cli\")"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"-- iteration 1 | threads 1\n",
"\n",
"real\t0m46.673s\n",
"user\t0m41.712s\n",
"sys\t0m4.031s\n",
"\n",
"-- iteration 2 | threads 1\n",
"rm: cannot remove '*.torrent': No such file or directory\n",
"\n",
"real\t0m45.859s\n",
"user\t0m41.532s\n",
"sys\t0m3.884s\n",
"\n",
"-- iteration 3 | threads 1\n",
"rm: cannot remove '*.torrent': No such file or directory\n",
"\n",
"real\t0m45.836s\n",
"user\t0m41.261s\n",
"sys\t0m3.952s\n",
"\n"
]
}
],
"source": [
"buildtorrent_data = run_benchmark(\"buildtorrent\", use_threads=False)"
]
},
{
"source": [
"maketorrent_data = run_benchmark(\"maketorrent\")"
],
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"source": [
"benchmark_data = {\n",
" \"mktorrent\": mktorrent_data, \n",
" \"imdl\": imdl_data,\n",
" \"dottorrent-cli\": dottorrent_cli_data,\n",
" \"pyrocore\": pyrocore_data,\n",
" \"transmission-create\": transmission_create_data,\n",
" \"py3createtorrent\" : py3createtorrent_data,\n",
" \"torf-cli\": torf_data,\n",
" \"buildtorrent\": buildtorrent_data,\n",
" # \"maketorrent\" : maketorrent_data,\n",
" \"torrenttools (OpenSSL)\": torrenttools_openssl_data,\n",
" \"torrenttools (ISA-L)\": torrenttools_isal_data,\n",
"}"
],
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"source": [
"programs = list(benchmark_data.keys())\n",
"threads = list(range(1, max_threads+1))\n",
"index = pd.MultiIndex.from_product((threads, programs), names=[\"threads\", \"programs\"])\n",
"\n",
"speed_mean_data = {}\n",
"speed_stddev_data = {}\n",
"for program, data in benchmark_data.items():\n",
" speed_mean_data[program] = data[0]\n",
" speed_stddev_data[program] = data[1]\n",
" \n",
"\n",
"speed_mean = pd.DataFrame(speed_mean_data).stack()\n",
"speed_stddev = pd.DataFrame(speed_stddev_data).stack()"
],
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"source": [
"df = pd.DataFrame()\n",
"df[\"speed_mean\"], df[\"speed_stddev\"] = speed_mean / 1e6, speed_stddev / 1e6\n",
"df.index = index"
],
"cell_type": "code",
"metadata": {},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"execution_count": 181,
"metadata": {},
"outputs": [],
"source": [
"# df.to_csv(\"benchmark.csv\")"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [],
"source": [
"df = pd.read_csv(\"benchmark.csv\")\n",
"df.set_index([\"threads\",\"programs\"], inplace=True)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" speed_mean speed_stddev\n",
"threads programs \n",
"1 mktorrent 843.537581 29.240162\n",
" imdl 422.595602 21.945212\n",
" dottorrent-cli 465.436936 5.708141\n",
" pyrocore 694.654299 28.286594\n",
" transmission-create 694.712205 38.430640\n",
" py3createtorrent 768.842932 7.946208\n",
" torf-cli 847.877094 8.542898\n",
" buildtorrent 465.635634 3.906536\n",
" torrenttools (OpenSSL) 857.746867 0.016150\n",
" torrenttools (ISA-L) 2394.788777 25.555998\n",
"2 mktorrent 1739.745717 0.816567\n",
" imdl 422.595602 21.945212\n",
" dottorrent-cli 465.436936 5.708141\n",
" pyrocore 694.654299 28.286594\n",
" transmission-create 694.712205 38.430640\n",
" py3createtorrent 768.842932 7.946208\n",
" torf-cli 1518.007778 20.554861\n",
" buildtorrent 465.635634 3.906536\n",
" torrenttools (OpenSSL) 1647.812096 0.059603\n",
" torrenttools (ISA-L) 4267.054895 138.342107\n",
"3 mktorrent 2401.102928 231.781078\n",
" imdl 422.595602 21.945212\n",
" dottorrent-cli 465.436936 5.708141\n",
" pyrocore 694.654299 28.286594\n",
" transmission-create 694.712205 38.430640\n",
" py3createtorrent 768.842932 7.946208\n",
" torf-cli 2026.580190 28.285421\n",
" buildtorrent 465.635634 3.906536\n",
" torrenttools (OpenSSL) 2448.522212 27.990339\n",
" torrenttools (ISA-L) 4255.814143 1.192516\n",
"4 mktorrent 3149.445056 125.745769\n",
" imdl 422.595602 21.945212\n",
" dottorrent-cli 465.436936 5.708141\n",
" pyrocore 694.654299 28.286594\n",
" transmission-create 694.712205 38.430640\n",
" py3createtorrent 768.842932 7.946208\n",
" torf-cli 2030.287245 17.163154\n",
" buildtorrent 465.635634 3.906536\n",
" torrenttools (OpenSSL) 3269.533110 49.678067\n",
" torrenttools (ISA-L) 4258.630736 3.983737"
],
"text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th></th>\n <th>speed_mean</th>\n <th>speed_stddev</th>\n </tr>\n <tr>\n <th>threads</th>\n <th>programs</th>\n <th></th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th rowspan=\"10\" valign=\"top\">1</th>\n <th>mktorrent</th>\n <td>843.537581</td>\n <td>29.240162</td>\n </tr>\n <tr>\n <th>imdl</th>\n <td>422.595602</td>\n <td>21.945212</td>\n </tr>\n <tr>\n <th>dottorrent-cli</th>\n <td>465.436936</td>\n <td>5.708141</td>\n </tr>\n <tr>\n <th>pyrocore</th>\n <td>694.654299</td>\n <td>28.286594</td>\n </tr>\n <tr>\n <th>transmission-create</th>\n <td>694.712205</td>\n <td>38.430640</td>\n </tr>\n <tr>\n <th>py3createtorrent</th>\n <td>768.842932</td>\n <td>7.946208</td>\n </tr>\n <tr>\n <th>torf-cli</th>\n <td>847.877094</td>\n <td>8.542898</td>\n </tr>\n <tr>\n <th>buildtorrent</th>\n <td>465.635634</td>\n <td>3.906536</td>\n </tr>\n <tr>\n <th>torrenttools (OpenSSL)</th>\n <td>857.746867</td>\n <td>0.016150</td>\n </tr>\n <tr>\n <th>torrenttools (ISA-L)</th>\n <td>2394.788777</td>\n <td>25.555998</td>\n </tr>\n <tr>\n <th rowspan=\"10\" valign=\"top\">2</th>\n <th>mktorrent</th>\n <td>1739.745717</td>\n <td>0.816567</td>\n </tr>\n <tr>\n <th>imdl</th>\n <td>422.595602</td>\n <td>21.945212</td>\n </tr>\n <tr>\n <th>dottorrent-cli</th>\n <td>465.436936</td>\n <td>5.708141</td>\n </tr>\n <tr>\n <th>pyrocore</th>\n <td>694.654299</td>\n <td>28.286594</td>\n </tr>\n <tr>\n <th>transmission-create</th>\n <td>694.712205</td>\n <td>38.430640</td>\n </tr>\n <tr>\n <th>py3createtorrent</th>\n <td>768.842932</td>\n <td>7.946208</td>\n </tr>\n <tr>\n <th>torf-cli</th>\n <td>1518.007778</td>\n <td>20.554861</td>\n </tr>\n <tr>\n <th>buildtorrent</th>\n <td>465.635634</td>\n <td>3.906536</td>\n </tr>\n <tr>\n <th>torrenttools (OpenSSL)</th>\n <td>1647.812096</td>\n <td>0.059603</td>\n </tr>\n <tr>\n <th>torrenttools (ISA-L)</th>\n <td>4267.054895</td>\n <td>138.342107</td>\n </tr>\n <tr>\n <th rowspan=\"10\" valign=\"top\">3</th>\n <th>mktorrent</th>\n <td>2401.102928</td>\n <td>231.781078</td>\n </tr>\n <tr>\n <th>imdl</th>\n <td>422.595602</td>\n <td>21.945212</td>\n </tr>\n <tr>\n <th>dottorrent-cli</th>\n <td>465.436936</td>\n <td>5.708141</td>\n </tr>\n <tr>\n <th>pyrocore</th>\n <td>694.654299</td>\n <td>28.286594</td>\n </tr>\n <tr>\n <th>transmission-create</th>\n <td>694.712205</td>\n <td>38.430640</td>\n </tr>\n <tr>\n <th>py3createtorrent</th>\n <td>768.842932</td>\n <td>7.946208</td>\n </tr>\n <tr>\n <th>torf-cli</th>\n <td>2026.580190</td>\n <td>28.285421</td>\n </tr>\n <tr>\n <th>buildtorrent</th>\n <td>465.635634</td>\n <td>3.906536</td>\n </tr>\n <tr>\n <th>torrenttools (OpenSSL)</th>\n <td>2448.522212</td>\n <td>27.990339</td>\n </tr>\n <tr>\n <th>torrenttools (ISA-L)</th>\n <td>4255.814143</td>\n <td>1.192516</td>\n </tr>\n <tr>\n <th rowspan=\"10\" valign=\"top\">4</th>\n <th>mktorrent</th>\n <td>3149.445056</td>\n <td>125.745769</td>\n </tr>\n <tr>\n <th>imdl</th>\n <td>422.595602</td>\n <td>21.945212</td>\n </tr>\n <tr>\n <th>dottorrent-cli</th>\n <td>465.436936</td>\n <td>5.708141</td>\n </tr>\n <tr>\n <th>pyrocore</th>\n <td>694.654299</td>\n <td>28.286594</td>\n </tr>\n <tr>\n <th>transmission-create</th>\n <td>694.712205</td>\n <td>38.430640</td>\n </tr>\n <tr>\n <th>py3createtorrent</th>\n <td>768.842932</td>\n <td>7.946208</td>\n </tr>\n <tr>\n <th>torf-cli</th>\n <td>2030.287245</td>\n <td>17.163154</td>\n </tr>\n <tr>\n <th>buildtorrent</th>\n <td>465.635634</td>\n <td>3.906536</td>\n </tr>\n <tr>\n <th>torrenttools (OpenSSL)</th>\n <td>3269.533110</td>\n <td>49.678067</td>\n </tr>\n <tr>\n <th>torrenttools (ISA-L)</th>\n <td>4258.630736</td>\n <td>3.983737</td>\n </tr>\n </tbody>\n</table>\n</div>"
},
"metadata": {},
"execution_count": 35
}
],
"source": [
"df"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": "<Figure size 576x576 with 1 Axes>",
"image/svg+xml": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n<!-- Created with matplotlib (https://matplotlib.org/) -->\n<svg height=\"494.754375pt\" version=\"1.1\" viewBox=\"0 0 684.62625 494.754375\" width=\"684.62625pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n <metadata>\n <rdf:RDF xmlns:cc=\"http://creativecommons.org/ns#\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n <cc:Work>\n <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/StillImage\"/>\n <dc:date>2021-04-20T14:17:37.448712</dc:date>\n <dc:format>image/svg+xml</dc:format>\n <dc:creator>\n <cc:Agent>\n <dc:title>Matplotlib v3.3.4, https://matplotlib.org/</dc:title>\n </cc:Agent>\n </dc:creator>\n </cc:Work>\n </rdf:RDF>\n </metadata>\n <defs>\n <style type=\"text/css\">*{stroke-linecap:butt;stroke-linejoin:round;}</style>\n </defs>\n <g id=\"figure_1\">\n <g id=\"patch_1\">\n <path d=\"M 0 494.754375 \nL 684.62625 494.754375 \nL 684.62625 0 \nL 0 0 \nz\n\" style=\"fill:#ffffff;\"/>\n </g>\n <g id=\"axes_1\">\n <g id=\"patch_2\">\n <path d=\"M 53.328125 457.198125 \nL 499.728125 457.198125 \nL 499.728125 22.318125 \nL 53.328125 22.318125 \nz\n\" style=\"fill:#ffffff;\"/>\n </g>\n <g id=\"PolyCollection_1\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 238.048202 \nL 73.619034 243.093938 \nL 208.891761 69.399447 \nL 344.164489 56.969825 \nL 479.437216 56.96732 \nL 479.437216 56.180777 \nL 479.437216 56.180777 \nL 344.164489 56.734376 \nL 208.891761 42.085398 \nL 73.619034 238.048202 \nz\n\" style=\"fill:#1f77b4;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_2\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 392.305051 \nL 73.619034 392.30824 \nL 208.891761 314.317908 \nL 344.164489 238.029731 \nL 479.437216 159.121173 \nL 479.437216 149.312813 \nL 479.437216 149.312813 \nL 344.164489 232.503363 \nL 208.891761 314.30614 \nL 73.619034 392.305051 \nz\n\" style=\"fill:#ff7f0e;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_3\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 390.822809 \nL 73.619034 396.595941 \nL 208.891761 305.317019 \nL 344.164489 262.828988 \nL 479.437216 178.485516 \nL 479.437216 153.658468 \nL 479.437216 153.658468 \nL 344.164489 217.066495 \nL 208.891761 305.155798 \nL 73.619034 390.822809 \nz\n\" style=\"fill:#2ca02c;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_4\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 392.437633 \nL 73.619034 394.12433 \nL 208.891761 329.155364 \nL 344.164489 279.712648 \nL 479.437216 278.248709 \nL 479.437216 274.860043 \nL 479.437216 274.860043 \nL 344.164489 274.128019 \nL 208.891761 325.097045 \nL 73.619034 392.437633 \nz\n\" style=\"fill:#d62728;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_5\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 400.298729 \nL 73.619034 401.867616 \nL 208.891761 401.867616 \nL 344.164489 401.867616 \nL 479.437216 401.867616 \nL 479.437216 400.298729 \nL 479.437216 400.298729 \nL 344.164489 400.298729 \nL 208.891761 400.298729 \nL 73.619034 400.298729 \nz\n\" style=\"fill:#9467bd;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_6\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 404.607457 \nL 73.619034 412.195142 \nL 208.891761 412.195142 \nL 344.164489 412.195142 \nL 479.437216 412.195142 \nL 479.437216 404.607457 \nL 479.437216 404.607457 \nL 344.164489 404.607457 \nL 208.891761 404.607457 \nL 73.619034 404.607457 \nz\n\" style=\"fill:#8c564b;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_7\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 405.614586 \nL 73.619034 411.199447 \nL 208.891761 411.199447 \nL 344.164489 411.199447 \nL 479.437216 411.199447 \nL 479.437216 405.614586 \nL 479.437216 405.614586 \nL 344.164489 405.614586 \nL 208.891761 405.614586 \nL 73.619034 405.614586 \nz\n\" style=\"fill:#e377c2;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_8\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 430.62991 \nL 73.619034 431.40121 \nL 208.891761 431.40121 \nL 344.164489 431.40121 \nL 479.437216 431.40121 \nL 479.437216 430.62991 \nL 479.437216 430.62991 \nL 344.164489 430.62991 \nL 208.891761 430.62991 \nL 73.619034 430.62991 \nz\n\" style=\"fill:#7f7f7f;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_9\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 430.471672 \nL 73.619034 431.598678 \nL 208.891761 431.598678 \nL 344.164489 431.598678 \nL 479.437216 431.598678 \nL 479.437216 430.471672 \nL 479.437216 430.471672 \nL 344.164489 430.471672 \nL 208.891761 430.471672 \nL 73.619034 430.471672 \nz\n\" style=\"fill:#bcbd22;fill-opacity:0.1;\"/>\n </g>\n <g id=\"PolyCollection_10\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 433.098024 \nL 73.619034 437.430852 \nL 208.891761 437.430852 \nL 344.164489 437.430852 \nL 479.437216 437.430852 \nL 479.437216 433.098024 \nL 479.437216 433.098024 \nL 344.164489 433.098024 \nL 208.891761 433.098024 \nL 73.619034 433.098024 \nz\n\" style=\"fill:#17becf;fill-opacity:0.1;\"/>\n </g>\n <g id=\"matplotlib.axis_1\">\n <g id=\"xtick_1\">\n <g id=\"line2d_1\">\n <defs>\n <path d=\"M 0 0 \nL 0 3.5 \n\" id=\"m0d8df1839a\" style=\"stroke:#000000;stroke-width:0.8;\"/>\n </defs>\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"73.619034\" xlink:href=\"#m0d8df1839a\" y=\"457.198125\"/>\n </g>\n </g>\n <g id=\"text_1\">\n <!-- 1 -->\n <g transform=\"translate(70.437784 471.796562)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 12.40625 8.296875 \nL 28.515625 8.296875 \nL 28.515625 63.921875 \nL 10.984375 60.40625 \nL 10.984375 69.390625 \nL 28.421875 72.90625 \nL 38.28125 72.90625 \nL 38.28125 8.296875 \nL 54.390625 8.296875 \nL 54.390625 0 \nL 12.40625 0 \nz\n\" id=\"DejaVuSans-49\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-49\"/>\n </g>\n </g>\n </g>\n <g id=\"xtick_2\">\n <g id=\"line2d_2\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"208.891761\" xlink:href=\"#m0d8df1839a\" y=\"457.198125\"/>\n </g>\n </g>\n <g id=\"text_2\">\n <!-- 2 -->\n <g transform=\"translate(205.710511 471.796562)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 19.1875 8.296875 \nL 53.609375 8.296875 \nL 53.609375 0 \nL 7.328125 0 \nL 7.328125 8.296875 \nQ 12.9375 14.109375 22.625 23.890625 \nQ 32.328125 33.6875 34.8125 36.53125 \nQ 39.546875 41.84375 41.421875 45.53125 \nQ 43.3125 49.21875 43.3125 52.78125 \nQ 43.3125 58.59375 39.234375 62.25 \nQ 35.15625 65.921875 28.609375 65.921875 \nQ 23.96875 65.921875 18.8125 64.3125 \nQ 13.671875 62.703125 7.8125 59.421875 \nL 7.8125 69.390625 \nQ 13.765625 71.78125 18.9375 73 \nQ 24.125 74.21875 28.421875 74.21875 \nQ 39.75 74.21875 46.484375 68.546875 \nQ 53.21875 62.890625 53.21875 53.421875 \nQ 53.21875 48.921875 51.53125 44.890625 \nQ 49.859375 40.875 45.40625 35.40625 \nQ 44.1875 33.984375 37.640625 27.21875 \nQ 31.109375 20.453125 19.1875 8.296875 \nz\n\" id=\"DejaVuSans-50\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-50\"/>\n </g>\n </g>\n </g>\n <g id=\"xtick_3\">\n <g id=\"line2d_3\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"344.164489\" xlink:href=\"#m0d8df1839a\" y=\"457.198125\"/>\n </g>\n </g>\n <g id=\"text_3\">\n <!-- 3 -->\n <g transform=\"translate(340.983239 471.796562)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 40.578125 39.3125 \nQ 47.65625 37.796875 51.625 33 \nQ 55.609375 28.21875 55.609375 21.1875 \nQ 55.609375 10.40625 48.1875 4.484375 \nQ 40.765625 -1.421875 27.09375 -1.421875 \nQ 22.515625 -1.421875 17.65625 -0.515625 \nQ 12.796875 0.390625 7.625 2.203125 \nL 7.625 11.71875 \nQ 11.71875 9.328125 16.59375 8.109375 \nQ 21.484375 6.890625 26.8125 6.890625 \nQ 36.078125 6.890625 40.9375 10.546875 \nQ 45.796875 14.203125 45.796875 21.1875 \nQ 45.796875 27.640625 41.28125 31.265625 \nQ 36.765625 34.90625 28.71875 34.90625 \nL 20.21875 34.90625 \nL 20.21875 43.015625 \nL 29.109375 43.015625 \nQ 36.375 43.015625 40.234375 45.921875 \nQ 44.09375 48.828125 44.09375 54.296875 \nQ 44.09375 59.90625 40.109375 62.90625 \nQ 36.140625 65.921875 28.71875 65.921875 \nQ 24.65625 65.921875 20.015625 65.03125 \nQ 15.375 64.15625 9.8125 62.3125 \nL 9.8125 71.09375 \nQ 15.4375 72.65625 20.34375 73.4375 \nQ 25.25 74.21875 29.59375 74.21875 \nQ 40.828125 74.21875 47.359375 69.109375 \nQ 53.90625 64.015625 53.90625 55.328125 \nQ 53.90625 49.265625 50.4375 45.09375 \nQ 46.96875 40.921875 40.578125 39.3125 \nz\n\" id=\"DejaVuSans-51\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-51\"/>\n </g>\n </g>\n </g>\n <g id=\"xtick_4\">\n <g id=\"line2d_4\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"479.437216\" xlink:href=\"#m0d8df1839a\" y=\"457.198125\"/>\n </g>\n </g>\n <g id=\"text_4\">\n <!-- 4 -->\n <g transform=\"translate(476.255966 471.796562)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 37.796875 64.3125 \nL 12.890625 25.390625 \nL 37.796875 25.390625 \nz\nM 35.203125 72.90625 \nL 47.609375 72.90625 \nL 47.609375 25.390625 \nL 58.015625 25.390625 \nL 58.015625 17.1875 \nL 47.609375 17.1875 \nL 47.609375 0 \nL 37.796875 0 \nL 37.796875 17.1875 \nL 4.890625 17.1875 \nL 4.890625 26.703125 \nz\n\" id=\"DejaVuSans-52\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-52\"/>\n </g>\n </g>\n </g>\n <g id=\"text_5\">\n <!-- # hashing threads -->\n <g transform=\"translate(230.430469 485.474687)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 51.125 44 \nL 36.921875 44 \nL 32.8125 27.6875 \nL 47.125 27.6875 \nz\nM 43.796875 71.78125 \nL 38.71875 51.515625 \nL 52.984375 51.515625 \nL 58.109375 71.78125 \nL 65.921875 71.78125 \nL 60.890625 51.515625 \nL 76.125 51.515625 \nL 76.125 44 \nL 58.984375 44 \nL 54.984375 27.6875 \nL 70.515625 27.6875 \nL 70.515625 20.21875 \nL 53.078125 20.21875 \nL 48 0 \nL 40.1875 0 \nL 45.21875 20.21875 \nL 30.90625 20.21875 \nL 25.875 0 \nL 18.015625 0 \nL 23.09375 20.21875 \nL 7.71875 20.21875 \nL 7.71875 27.6875 \nL 24.90625 27.6875 \nL 29 44 \nL 13.28125 44 \nL 13.28125 51.515625 \nL 30.90625 51.515625 \nL 35.890625 71.78125 \nz\n\" id=\"DejaVuSans-35\"/>\n <path id=\"DejaVuSans-32\"/>\n <path d=\"M 54.890625 33.015625 \nL 54.890625 0 \nL 45.90625 0 \nL 45.90625 32.71875 \nQ 45.90625 40.484375 42.875 44.328125 \nQ 39.84375 48.1875 33.796875 48.1875 \nQ 26.515625 48.1875 22.3125 43.546875 \nQ 18.109375 38.921875 18.109375 30.90625 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 75.984375 \nL 18.109375 75.984375 \nL 18.109375 46.1875 \nQ 21.34375 51.125 25.703125 53.5625 \nQ 30.078125 56 35.796875 56 \nQ 45.21875 56 50.046875 50.171875 \nQ 54.890625 44.34375 54.890625 33.015625 \nz\n\" id=\"DejaVuSans-104\"/>\n <path d=\"M 34.28125 27.484375 \nQ 23.390625 27.484375 19.1875 25 \nQ 14.984375 22.515625 14.984375 16.5 \nQ 14.984375 11.71875 18.140625 8.90625 \nQ 21.296875 6.109375 26.703125 6.109375 \nQ 34.1875 6.109375 38.703125 11.40625 \nQ 43.21875 16.703125 43.21875 25.484375 \nL 43.21875 27.484375 \nz\nM 52.203125 31.203125 \nL 52.203125 0 \nL 43.21875 0 \nL 43.21875 8.296875 \nQ 40.140625 3.328125 35.546875 0.953125 \nQ 30.953125 -1.421875 24.3125 -1.421875 \nQ 15.921875 -1.421875 10.953125 3.296875 \nQ 6 8.015625 6 15.921875 \nQ 6 25.140625 12.171875 29.828125 \nQ 18.359375 34.515625 30.609375 34.515625 \nL 43.21875 34.515625 \nL 43.21875 35.40625 \nQ 43.21875 41.609375 39.140625 45 \nQ 35.0625 48.390625 27.6875 48.390625 \nQ 23 48.390625 18.546875 47.265625 \nQ 14.109375 46.140625 10.015625 43.890625 \nL 10.015625 52.203125 \nQ 14.9375 54.109375 19.578125 55.046875 \nQ 24.21875 56 28.609375 56 \nQ 40.484375 56 46.34375 49.84375 \nQ 52.203125 43.703125 52.203125 31.203125 \nz\n\" id=\"DejaVuSans-97\"/>\n <path d=\"M 44.28125 53.078125 \nL 44.28125 44.578125 \nQ 40.484375 46.53125 36.375 47.5 \nQ 32.28125 48.484375 27.875 48.484375 \nQ 21.1875 48.484375 17.84375 46.4375 \nQ 14.5 44.390625 14.5 40.28125 \nQ 14.5 37.15625 16.890625 35.375 \nQ 19.28125 33.59375 26.515625 31.984375 \nL 29.59375 31.296875 \nQ 39.15625 29.25 43.1875 25.515625 \nQ 47.21875 21.78125 47.21875 15.09375 \nQ 47.21875 7.46875 41.1875 3.015625 \nQ 35.15625 -1.421875 24.609375 -1.421875 \nQ 20.21875 -1.421875 15.453125 -0.5625 \nQ 10.6875 0.296875 5.421875 2 \nL 5.421875 11.28125 \nQ 10.40625 8.6875 15.234375 7.390625 \nQ 20.0625 6.109375 24.8125 6.109375 \nQ 31.15625 6.109375 34.5625 8.28125 \nQ 37.984375 10.453125 37.984375 14.40625 \nQ 37.984375 18.0625 35.515625 20.015625 \nQ 33.0625 21.96875 24.703125 23.78125 \nL 21.578125 24.515625 \nQ 13.234375 26.265625 9.515625 29.90625 \nQ 5.8125 33.546875 5.8125 39.890625 \nQ 5.8125 47.609375 11.28125 51.796875 \nQ 16.75 56 26.8125 56 \nQ 31.78125 56 36.171875 55.265625 \nQ 40.578125 54.546875 44.28125 53.078125 \nz\n\" id=\"DejaVuSans-115\"/>\n <path d=\"M 9.421875 54.6875 \nL 18.40625 54.6875 \nL 18.40625 0 \nL 9.421875 0 \nz\nM 9.421875 75.984375 \nL 18.40625 75.984375 \nL 18.40625 64.59375 \nL 9.421875 64.59375 \nz\n\" id=\"DejaVuSans-105\"/>\n <path d=\"M 54.890625 33.015625 \nL 54.890625 0 \nL 45.90625 0 \nL 45.90625 32.71875 \nQ 45.90625 40.484375 42.875 44.328125 \nQ 39.84375 48.1875 33.796875 48.1875 \nQ 26.515625 48.1875 22.3125 43.546875 \nQ 18.109375 38.921875 18.109375 30.90625 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 54.6875 \nL 18.109375 54.6875 \nL 18.109375 46.1875 \nQ 21.34375 51.125 25.703125 53.5625 \nQ 30.078125 56 35.796875 56 \nQ 45.21875 56 50.046875 50.171875 \nQ 54.890625 44.34375 54.890625 33.015625 \nz\n\" id=\"DejaVuSans-110\"/>\n <path d=\"M 45.40625 27.984375 \nQ 45.40625 37.75 41.375 43.109375 \nQ 37.359375 48.484375 30.078125 48.484375 \nQ 22.859375 48.484375 18.828125 43.109375 \nQ 14.796875 37.75 14.796875 27.984375 \nQ 14.796875 18.265625 18.828125 12.890625 \nQ 22.859375 7.515625 30.078125 7.515625 \nQ 37.359375 7.515625 41.375 12.890625 \nQ 45.40625 18.265625 45.40625 27.984375 \nz\nM 54.390625 6.78125 \nQ 54.390625 -7.171875 48.1875 -13.984375 \nQ 42 -20.796875 29.203125 -20.796875 \nQ 24.46875 -20.796875 20.265625 -20.09375 \nQ 16.0625 -19.390625 12.109375 -17.921875 \nL 12.109375 -9.1875 \nQ 16.0625 -11.328125 19.921875 -12.34375 \nQ 23.78125 -13.375 27.78125 -13.375 \nQ 36.625 -13.375 41.015625 -8.765625 \nQ 45.40625 -4.15625 45.40625 5.171875 \nL 45.40625 9.625 \nQ 42.625 4.78125 38.28125 2.390625 \nQ 33.9375 0 27.875 0 \nQ 17.828125 0 11.671875 7.65625 \nQ 5.515625 15.328125 5.515625 27.984375 \nQ 5.515625 40.671875 11.671875 48.328125 \nQ 17.828125 56 27.875 56 \nQ 33.9375 56 38.28125 53.609375 \nQ 42.625 51.21875 45.40625 46.390625 \nL 45.40625 54.6875 \nL 54.390625 54.6875 \nz\n\" id=\"DejaVuSans-103\"/>\n <path d=\"M 18.3125 70.21875 \nL 18.3125 54.6875 \nL 36.8125 54.6875 \nL 36.8125 47.703125 \nL 18.3125 47.703125 \nL 18.3125 18.015625 \nQ 18.3125 11.328125 20.140625 9.421875 \nQ 21.96875 7.515625 27.59375 7.515625 \nL 36.8125 7.515625 \nL 36.8125 0 \nL 27.59375 0 \nQ 17.1875 0 13.234375 3.875 \nQ 9.28125 7.765625 9.28125 18.015625 \nL 9.28125 47.703125 \nL 2.6875 47.703125 \nL 2.6875 54.6875 \nL 9.28125 54.6875 \nL 9.28125 70.21875 \nz\n\" id=\"DejaVuSans-116\"/>\n <path d=\"M 41.109375 46.296875 \nQ 39.59375 47.171875 37.8125 47.578125 \nQ 36.03125 48 33.890625 48 \nQ 26.265625 48 22.1875 43.046875 \nQ 18.109375 38.09375 18.109375 28.8125 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 54.6875 \nL 18.109375 54.6875 \nL 18.109375 46.1875 \nQ 20.953125 51.171875 25.484375 53.578125 \nQ 30.03125 56 36.53125 56 \nQ 37.453125 56 38.578125 55.875 \nQ 39.703125 55.765625 41.0625 55.515625 \nz\n\" id=\"DejaVuSans-114\"/>\n <path d=\"M 56.203125 29.59375 \nL 56.203125 25.203125 \nL 14.890625 25.203125 \nQ 15.484375 15.921875 20.484375 11.0625 \nQ 25.484375 6.203125 34.421875 6.203125 \nQ 39.59375 6.203125 44.453125 7.46875 \nQ 49.3125 8.734375 54.109375 11.28125 \nL 54.109375 2.78125 \nQ 49.265625 0.734375 44.1875 -0.34375 \nQ 39.109375 -1.421875 33.890625 -1.421875 \nQ 20.796875 -1.421875 13.15625 6.1875 \nQ 5.515625 13.8125 5.515625 26.8125 \nQ 5.515625 40.234375 12.765625 48.109375 \nQ 20.015625 56 32.328125 56 \nQ 43.359375 56 49.78125 48.890625 \nQ 56.203125 41.796875 56.203125 29.59375 \nz\nM 47.21875 32.234375 \nQ 47.125 39.59375 43.09375 43.984375 \nQ 39.0625 48.390625 32.421875 48.390625 \nQ 24.90625 48.390625 20.390625 44.140625 \nQ 15.875 39.890625 15.1875 32.171875 \nz\n\" id=\"DejaVuSans-101\"/>\n <path d=\"M 45.40625 46.390625 \nL 45.40625 75.984375 \nL 54.390625 75.984375 \nL 54.390625 0 \nL 45.40625 0 \nL 45.40625 8.203125 \nQ 42.578125 3.328125 38.25 0.953125 \nQ 33.9375 -1.421875 27.875 -1.421875 \nQ 17.96875 -1.421875 11.734375 6.484375 \nQ 5.515625 14.40625 5.515625 27.296875 \nQ 5.515625 40.1875 11.734375 48.09375 \nQ 17.96875 56 27.875 56 \nQ 33.9375 56 38.25 53.625 \nQ 42.578125 51.265625 45.40625 46.390625 \nz\nM 14.796875 27.296875 \nQ 14.796875 17.390625 18.875 11.75 \nQ 22.953125 6.109375 30.078125 6.109375 \nQ 37.203125 6.109375 41.296875 11.75 \nQ 45.40625 17.390625 45.40625 27.296875 \nQ 45.40625 37.203125 41.296875 42.84375 \nQ 37.203125 48.484375 30.078125 48.484375 \nQ 22.953125 48.484375 18.875 42.84375 \nQ 14.796875 37.203125 14.796875 27.296875 \nz\n\" id=\"DejaVuSans-100\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-35\"/>\n <use x=\"83.789062\" xlink:href=\"#DejaVuSans-32\"/>\n <use x=\"115.576172\" xlink:href=\"#DejaVuSans-104\"/>\n <use x=\"178.955078\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"240.234375\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"292.333984\" xlink:href=\"#DejaVuSans-104\"/>\n <use x=\"355.712891\" xlink:href=\"#DejaVuSans-105\"/>\n <use x=\"383.496094\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"446.875\" xlink:href=\"#DejaVuSans-103\"/>\n <use x=\"510.351562\" xlink:href=\"#DejaVuSans-32\"/>\n <use x=\"542.138672\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"581.347656\" xlink:href=\"#DejaVuSans-104\"/>\n <use x=\"644.726562\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"683.589844\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"745.113281\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"806.392578\" xlink:href=\"#DejaVuSans-100\"/>\n <use x=\"869.869141\" xlink:href=\"#DejaVuSans-115\"/>\n </g>\n </g>\n </g>\n <g id=\"matplotlib.axis_2\">\n <g id=\"ytick_1\">\n <g id=\"line2d_5\">\n <defs>\n <path d=\"M 0 0 \nL -3.5 0 \n\" id=\"m165b357ab2\" style=\"stroke:#000000;stroke-width:0.8;\"/>\n </defs>\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"427.623136\"/>\n </g>\n </g>\n <g id=\"text_6\">\n <!-- 500 -->\n <g transform=\"translate(27.240625 431.422355)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 10.796875 72.90625 \nL 49.515625 72.90625 \nL 49.515625 64.59375 \nL 19.828125 64.59375 \nL 19.828125 46.734375 \nQ 21.96875 47.46875 24.109375 47.828125 \nQ 26.265625 48.1875 28.421875 48.1875 \nQ 40.625 48.1875 47.75 41.5 \nQ 54.890625 34.8125 54.890625 23.390625 \nQ 54.890625 11.625 47.5625 5.09375 \nQ 40.234375 -1.421875 26.90625 -1.421875 \nQ 22.3125 -1.421875 17.546875 -0.640625 \nQ 12.796875 0.140625 7.71875 1.703125 \nL 7.71875 11.625 \nQ 12.109375 9.234375 16.796875 8.0625 \nQ 21.484375 6.890625 26.703125 6.890625 \nQ 35.15625 6.890625 40.078125 11.328125 \nQ 45.015625 15.765625 45.015625 23.390625 \nQ 45.015625 31 40.078125 35.4375 \nQ 35.15625 39.890625 26.703125 39.890625 \nQ 22.75 39.890625 18.8125 39.015625 \nQ 14.890625 38.140625 10.796875 36.28125 \nz\n\" id=\"DejaVuSans-53\"/>\n <path d=\"M 31.78125 66.40625 \nQ 24.171875 66.40625 20.328125 58.90625 \nQ 16.5 51.421875 16.5 36.375 \nQ 16.5 21.390625 20.328125 13.890625 \nQ 24.171875 6.390625 31.78125 6.390625 \nQ 39.453125 6.390625 43.28125 13.890625 \nQ 47.125 21.390625 47.125 36.375 \nQ 47.125 51.421875 43.28125 58.90625 \nQ 39.453125 66.40625 31.78125 66.40625 \nz\nM 31.78125 74.21875 \nQ 44.046875 74.21875 50.515625 64.515625 \nQ 56.984375 54.828125 56.984375 36.375 \nQ 56.984375 17.96875 50.515625 8.265625 \nQ 44.046875 -1.421875 31.78125 -1.421875 \nQ 19.53125 -1.421875 13.0625 8.265625 \nQ 6.59375 17.96875 6.59375 36.375 \nQ 6.59375 54.828125 13.0625 64.515625 \nQ 19.53125 74.21875 31.78125 74.21875 \nz\n\" id=\"DejaVuSans-48\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-53\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_2\">\n <g id=\"line2d_6\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"378.263527\"/>\n </g>\n </g>\n <g id=\"text_7\">\n <!-- 1000 -->\n <g transform=\"translate(20.878125 382.062746)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-49\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_3\">\n <g id=\"line2d_7\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"328.903918\"/>\n </g>\n </g>\n <g id=\"text_8\">\n <!-- 1500 -->\n <g transform=\"translate(20.878125 332.703137)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-49\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-53\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_4\">\n <g id=\"line2d_8\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"279.544309\"/>\n </g>\n </g>\n <g id=\"text_9\">\n <!-- 2000 -->\n <g transform=\"translate(20.878125 283.343528)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-50\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_5\">\n <g id=\"line2d_9\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"230.1847\"/>\n </g>\n </g>\n <g id=\"text_10\">\n <!-- 2500 -->\n <g transform=\"translate(20.878125 233.983919)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-50\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-53\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_6\">\n <g id=\"line2d_10\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"180.825091\"/>\n </g>\n </g>\n <g id=\"text_11\">\n <!-- 3000 -->\n <g transform=\"translate(20.878125 184.62431)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-51\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_7\">\n <g id=\"line2d_11\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"131.465482\"/>\n </g>\n </g>\n <g id=\"text_12\">\n <!-- 3500 -->\n <g transform=\"translate(20.878125 135.264701)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-51\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-53\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_8\">\n <g id=\"line2d_12\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"82.105873\"/>\n </g>\n </g>\n <g id=\"text_13\">\n <!-- 4000 -->\n <g transform=\"translate(20.878125 85.905092)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-52\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"ytick_9\">\n <g id=\"line2d_13\">\n <g>\n <use style=\"stroke:#000000;stroke-width:0.8;\" x=\"53.328125\" xlink:href=\"#m165b357ab2\" y=\"32.746264\"/>\n </g>\n </g>\n <g id=\"text_14\">\n <!-- 4500 -->\n <g transform=\"translate(20.878125 36.545482)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-52\"/>\n <use x=\"63.623047\" xlink:href=\"#DejaVuSans-53\"/>\n <use x=\"127.246094\" xlink:href=\"#DejaVuSans-48\"/>\n <use x=\"190.869141\" xlink:href=\"#DejaVuSans-48\"/>\n </g>\n </g>\n </g>\n <g id=\"text_15\">\n <!-- Hash rate (MiB/s) -->\n <g transform=\"translate(14.798438 283.014375)rotate(-90)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 9.8125 72.90625 \nL 19.671875 72.90625 \nL 19.671875 43.015625 \nL 55.515625 43.015625 \nL 55.515625 72.90625 \nL 65.375 72.90625 \nL 65.375 0 \nL 55.515625 0 \nL 55.515625 34.71875 \nL 19.671875 34.71875 \nL 19.671875 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-72\"/>\n <path d=\"M 31 75.875 \nQ 24.46875 64.65625 21.28125 53.65625 \nQ 18.109375 42.671875 18.109375 31.390625 \nQ 18.109375 20.125 21.3125 9.0625 \nQ 24.515625 -2 31 -13.1875 \nL 23.1875 -13.1875 \nQ 15.875 -1.703125 12.234375 9.375 \nQ 8.59375 20.453125 8.59375 31.390625 \nQ 8.59375 42.28125 12.203125 53.3125 \nQ 15.828125 64.359375 23.1875 75.875 \nz\n\" id=\"DejaVuSans-40\"/>\n <path d=\"M 9.8125 72.90625 \nL 24.515625 72.90625 \nL 43.109375 23.296875 \nL 61.8125 72.90625 \nL 76.515625 72.90625 \nL 76.515625 0 \nL 66.890625 0 \nL 66.890625 64.015625 \nL 48.09375 14.015625 \nL 38.1875 14.015625 \nL 19.390625 64.015625 \nL 19.390625 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-77\"/>\n <path d=\"M 19.671875 34.8125 \nL 19.671875 8.109375 \nL 35.5 8.109375 \nQ 43.453125 8.109375 47.28125 11.40625 \nQ 51.125 14.703125 51.125 21.484375 \nQ 51.125 28.328125 47.28125 31.5625 \nQ 43.453125 34.8125 35.5 34.8125 \nz\nM 19.671875 64.796875 \nL 19.671875 42.828125 \nL 34.28125 42.828125 \nQ 41.5 42.828125 45.03125 45.53125 \nQ 48.578125 48.25 48.578125 53.8125 \nQ 48.578125 59.328125 45.03125 62.0625 \nQ 41.5 64.796875 34.28125 64.796875 \nz\nM 9.8125 72.90625 \nL 35.015625 72.90625 \nQ 46.296875 72.90625 52.390625 68.21875 \nQ 58.5 63.53125 58.5 54.890625 \nQ 58.5 48.1875 55.375 44.234375 \nQ 52.25 40.28125 46.1875 39.3125 \nQ 53.46875 37.75 57.5 32.78125 \nQ 61.53125 27.828125 61.53125 20.40625 \nQ 61.53125 10.640625 54.890625 5.3125 \nQ 48.25 0 35.984375 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-66\"/>\n <path d=\"M 25.390625 72.90625 \nL 33.6875 72.90625 \nL 8.296875 -9.28125 \nL 0 -9.28125 \nz\n\" id=\"DejaVuSans-47\"/>\n <path d=\"M 8.015625 75.875 \nL 15.828125 75.875 \nQ 23.140625 64.359375 26.78125 53.3125 \nQ 30.421875 42.28125 30.421875 31.390625 \nQ 30.421875 20.453125 26.78125 9.375 \nQ 23.140625 -1.703125 15.828125 -13.1875 \nL 8.015625 -13.1875 \nQ 14.5 -2 17.703125 9.0625 \nQ 20.90625 20.125 20.90625 31.390625 \nQ 20.90625 42.671875 17.703125 53.65625 \nQ 14.5 64.65625 8.015625 75.875 \nz\n\" id=\"DejaVuSans-41\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-72\"/>\n <use x=\"75.195312\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"136.474609\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"188.574219\" xlink:href=\"#DejaVuSans-104\"/>\n <use x=\"251.953125\" xlink:href=\"#DejaVuSans-32\"/>\n <use x=\"283.740234\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"324.853516\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"386.132812\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"425.341797\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"486.865234\" xlink:href=\"#DejaVuSans-32\"/>\n <use x=\"518.652344\" xlink:href=\"#DejaVuSans-40\"/>\n <use x=\"557.666016\" xlink:href=\"#DejaVuSans-77\"/>\n <use x=\"643.945312\" xlink:href=\"#DejaVuSans-105\"/>\n <use x=\"671.728516\" xlink:href=\"#DejaVuSans-66\"/>\n <use x=\"740.332031\" xlink:href=\"#DejaVuSans-47\"/>\n <use x=\"774.023438\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"826.123047\" xlink:href=\"#DejaVuSans-41\"/>\n </g>\n </g>\n </g>\n <g id=\"line2d_14\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 240.57107 \nL 208.891761 55.742422 \nL 344.164489 56.852101 \nL 479.437216 56.574049 \n\" style=\"fill:none;stroke:#1f77b4;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_15\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 392.306645 \nL 208.891761 314.312024 \nL 344.164489 235.266547 \nL 479.437216 154.216993 \n\" style=\"fill:none;stroke:#ff7f0e;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_16\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 393.709375 \nL 208.891761 305.236409 \nL 344.164489 239.947742 \nL 479.437216 166.071992 \n\" style=\"fill:none;stroke:#2ca02c;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_17\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 393.280982 \nL 208.891761 327.126204 \nL 344.164489 276.920334 \nL 479.437216 276.554376 \n\" style=\"fill:none;stroke:#d62728;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_18\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 401.083172 \nL 208.891761 401.083172 \nL 344.164489 401.083172 \nL 479.437216 401.083172 \n\" style=\"fill:none;stroke:#9467bd;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_19\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 408.4013 \nL 208.891761 408.4013 \nL 344.164489 408.4013 \nL 479.437216 408.4013 \n\" style=\"fill:none;stroke:#8c564b;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_20\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 408.407016 \nL 208.891761 408.407016 \nL 344.164489 408.407016 \nL 479.437216 408.407016 \n\" style=\"fill:none;stroke:#e377c2;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_21\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 431.01556 \nL 208.891761 431.01556 \nL 344.164489 431.01556 \nL 479.437216 431.01556 \n\" style=\"fill:none;stroke:#7f7f7f;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_22\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 431.035175 \nL 208.891761 431.035175 \nL 344.164489 431.035175 \nL 479.437216 431.035175 \n\" style=\"fill:none;stroke:#bcbd22;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_23\">\n <path clip-path=\"url(#p4d0c9becf6)\" d=\"M 73.619034 435.264438 \nL 208.891761 435.264438 \nL 344.164489 435.264438 \nL 479.437216 435.264438 \n\" style=\"fill:none;stroke:#17becf;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"patch_3\">\n <path d=\"M 53.328125 457.198125 \nL 53.328125 22.318125 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n </g>\n <g id=\"patch_4\">\n <path d=\"M 499.728125 457.198125 \nL 499.728125 22.318125 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n </g>\n <g id=\"patch_5\">\n <path d=\"M 53.328125 457.198125 \nL 499.728125 457.198125 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n </g>\n <g id=\"patch_6\">\n <path d=\"M 53.328125 22.318125 \nL 499.728125 22.318125 \n\" style=\"fill:none;stroke:#000000;stroke-linecap:square;stroke-linejoin:miter;stroke-width:0.8;\"/>\n </g>\n <g id=\"text_16\">\n <!-- Performance -->\n <g transform=\"translate(238.509687 16.318125)scale(0.12 -0.12)\">\n <defs>\n <path d=\"M 19.671875 64.796875 \nL 19.671875 37.40625 \nL 32.078125 37.40625 \nQ 38.96875 37.40625 42.71875 40.96875 \nQ 46.484375 44.53125 46.484375 51.125 \nQ 46.484375 57.671875 42.71875 61.234375 \nQ 38.96875 64.796875 32.078125 64.796875 \nz\nM 9.8125 72.90625 \nL 32.078125 72.90625 \nQ 44.34375 72.90625 50.609375 67.359375 \nQ 56.890625 61.8125 56.890625 51.125 \nQ 56.890625 40.328125 50.609375 34.8125 \nQ 44.34375 29.296875 32.078125 29.296875 \nL 19.671875 29.296875 \nL 19.671875 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-80\"/>\n <path d=\"M 37.109375 75.984375 \nL 37.109375 68.5 \nL 28.515625 68.5 \nQ 23.6875 68.5 21.796875 66.546875 \nQ 19.921875 64.59375 19.921875 59.515625 \nL 19.921875 54.6875 \nL 34.71875 54.6875 \nL 34.71875 47.703125 \nL 19.921875 47.703125 \nL 19.921875 0 \nL 10.890625 0 \nL 10.890625 47.703125 \nL 2.296875 47.703125 \nL 2.296875 54.6875 \nL 10.890625 54.6875 \nL 10.890625 58.5 \nQ 10.890625 67.625 15.140625 71.796875 \nQ 19.390625 75.984375 28.609375 75.984375 \nz\n\" id=\"DejaVuSans-102\"/>\n <path d=\"M 30.609375 48.390625 \nQ 23.390625 48.390625 19.1875 42.75 \nQ 14.984375 37.109375 14.984375 27.296875 \nQ 14.984375 17.484375 19.15625 11.84375 \nQ 23.34375 6.203125 30.609375 6.203125 \nQ 37.796875 6.203125 41.984375 11.859375 \nQ 46.1875 17.53125 46.1875 27.296875 \nQ 46.1875 37.015625 41.984375 42.703125 \nQ 37.796875 48.390625 30.609375 48.390625 \nz\nM 30.609375 56 \nQ 42.328125 56 49.015625 48.375 \nQ 55.71875 40.765625 55.71875 27.296875 \nQ 55.71875 13.875 49.015625 6.21875 \nQ 42.328125 -1.421875 30.609375 -1.421875 \nQ 18.84375 -1.421875 12.171875 6.21875 \nQ 5.515625 13.875 5.515625 27.296875 \nQ 5.515625 40.765625 12.171875 48.375 \nQ 18.84375 56 30.609375 56 \nz\n\" id=\"DejaVuSans-111\"/>\n <path d=\"M 52 44.1875 \nQ 55.375 50.25 60.0625 53.125 \nQ 64.75 56 71.09375 56 \nQ 79.640625 56 84.28125 50.015625 \nQ 88.921875 44.046875 88.921875 33.015625 \nL 88.921875 0 \nL 79.890625 0 \nL 79.890625 32.71875 \nQ 79.890625 40.578125 77.09375 44.375 \nQ 74.3125 48.1875 68.609375 48.1875 \nQ 61.625 48.1875 57.5625 43.546875 \nQ 53.515625 38.921875 53.515625 30.90625 \nL 53.515625 0 \nL 44.484375 0 \nL 44.484375 32.71875 \nQ 44.484375 40.625 41.703125 44.40625 \nQ 38.921875 48.1875 33.109375 48.1875 \nQ 26.21875 48.1875 22.15625 43.53125 \nQ 18.109375 38.875 18.109375 30.90625 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 54.6875 \nL 18.109375 54.6875 \nL 18.109375 46.1875 \nQ 21.1875 51.21875 25.484375 53.609375 \nQ 29.78125 56 35.6875 56 \nQ 41.65625 56 45.828125 52.96875 \nQ 50 49.953125 52 44.1875 \nz\n\" id=\"DejaVuSans-109\"/>\n <path d=\"M 48.78125 52.59375 \nL 48.78125 44.1875 \nQ 44.96875 46.296875 41.140625 47.34375 \nQ 37.3125 48.390625 33.40625 48.390625 \nQ 24.65625 48.390625 19.8125 42.84375 \nQ 14.984375 37.3125 14.984375 27.296875 \nQ 14.984375 17.28125 19.8125 11.734375 \nQ 24.65625 6.203125 33.40625 6.203125 \nQ 37.3125 6.203125 41.140625 7.25 \nQ 44.96875 8.296875 48.78125 10.40625 \nL 48.78125 2.09375 \nQ 45.015625 0.34375 40.984375 -0.53125 \nQ 36.96875 -1.421875 32.421875 -1.421875 \nQ 20.0625 -1.421875 12.78125 6.34375 \nQ 5.515625 14.109375 5.515625 27.296875 \nQ 5.515625 40.671875 12.859375 48.328125 \nQ 20.21875 56 33.015625 56 \nQ 37.15625 56 41.109375 55.140625 \nQ 45.0625 54.296875 48.78125 52.59375 \nz\n\" id=\"DejaVuSans-99\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-80\"/>\n <use x=\"56.677734\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"118.201172\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"159.314453\" xlink:href=\"#DejaVuSans-102\"/>\n <use x=\"194.519531\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"255.701172\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"295.064453\" xlink:href=\"#DejaVuSans-109\"/>\n <use x=\"392.476562\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"453.755859\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"517.134766\" xlink:href=\"#DejaVuSans-99\"/>\n <use x=\"572.115234\" xlink:href=\"#DejaVuSans-101\"/>\n </g>\n </g>\n <g id=\"legend_1\">\n <g id=\"patch_7\">\n <path d=\"M 529.048125 177.099375 \nL 675.42625 177.099375 \nQ 677.42625 177.099375 677.42625 175.099375 \nL 677.42625 29.318125 \nQ 677.42625 27.318125 675.42625 27.318125 \nL 529.048125 27.318125 \nQ 527.048125 27.318125 527.048125 29.318125 \nL 527.048125 175.099375 \nQ 527.048125 177.099375 529.048125 177.099375 \nz\n\" style=\"fill:#ffffff;opacity:0.8;stroke:#cccccc;stroke-linejoin:miter;\"/>\n </g>\n <g id=\"line2d_24\">\n <path d=\"M 531.048125 35.416562 \nL 551.048125 35.416562 \n\" style=\"fill:none;stroke:#1f77b4;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_25\"/>\n <g id=\"text_17\">\n <!-- torrenttools (ISA-L) -->\n <g transform=\"translate(559.048125 38.916562)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 9.421875 75.984375 \nL 18.40625 75.984375 \nL 18.40625 0 \nL 9.421875 0 \nz\n\" id=\"DejaVuSans-108\"/>\n <path d=\"M 9.8125 72.90625 \nL 19.671875 72.90625 \nL 19.671875 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-73\"/>\n <path d=\"M 53.515625 70.515625 \nL 53.515625 60.890625 \nQ 47.90625 63.578125 42.921875 64.890625 \nQ 37.9375 66.21875 33.296875 66.21875 \nQ 25.25 66.21875 20.875 63.09375 \nQ 16.5 59.96875 16.5 54.203125 \nQ 16.5 49.359375 19.40625 46.890625 \nQ 22.3125 44.4375 30.421875 42.921875 \nL 36.375 41.703125 \nQ 47.40625 39.59375 52.65625 34.296875 \nQ 57.90625 29 57.90625 20.125 \nQ 57.90625 9.515625 50.796875 4.046875 \nQ 43.703125 -1.421875 29.984375 -1.421875 \nQ 24.8125 -1.421875 18.96875 -0.25 \nQ 13.140625 0.921875 6.890625 3.21875 \nL 6.890625 13.375 \nQ 12.890625 10.015625 18.65625 8.296875 \nQ 24.421875 6.59375 29.984375 6.59375 \nQ 38.421875 6.59375 43.015625 9.90625 \nQ 47.609375 13.234375 47.609375 19.390625 \nQ 47.609375 24.75 44.3125 27.78125 \nQ 41.015625 30.8125 33.5 32.328125 \nL 27.484375 33.5 \nQ 16.453125 35.6875 11.515625 40.375 \nQ 6.59375 45.0625 6.59375 53.421875 \nQ 6.59375 63.09375 13.40625 68.65625 \nQ 20.21875 74.21875 32.171875 74.21875 \nQ 37.3125 74.21875 42.625 73.28125 \nQ 47.953125 72.359375 53.515625 70.515625 \nz\n\" id=\"DejaVuSans-83\"/>\n <path d=\"M 34.1875 63.1875 \nL 20.796875 26.90625 \nL 47.609375 26.90625 \nz\nM 28.609375 72.90625 \nL 39.796875 72.90625 \nL 67.578125 0 \nL 57.328125 0 \nL 50.6875 18.703125 \nL 17.828125 18.703125 \nL 11.1875 0 \nL 0.78125 0 \nz\n\" id=\"DejaVuSans-65\"/>\n <path d=\"M 4.890625 31.390625 \nL 31.203125 31.390625 \nL 31.203125 23.390625 \nL 4.890625 23.390625 \nz\n\" id=\"DejaVuSans-45\"/>\n <path d=\"M 9.8125 72.90625 \nL 19.671875 72.90625 \nL 19.671875 8.296875 \nL 55.171875 8.296875 \nL 55.171875 0 \nL 9.8125 0 \nz\n\" id=\"DejaVuSans-76\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"39.208984\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"100.390625\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"139.753906\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"178.617188\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"240.140625\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"303.519531\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"342.728516\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"381.9375\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"443.119141\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"504.300781\" xlink:href=\"#DejaVuSans-108\"/>\n <use x=\"532.083984\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"584.183594\" xlink:href=\"#DejaVuSans-32\"/>\n <use x=\"615.970703\" xlink:href=\"#DejaVuSans-40\"/>\n <use x=\"654.984375\" xlink:href=\"#DejaVuSans-73\"/>\n <use x=\"684.476562\" xlink:href=\"#DejaVuSans-83\"/>\n <use x=\"749.828125\" xlink:href=\"#DejaVuSans-65\"/>\n <use x=\"815.986328\" xlink:href=\"#DejaVuSans-45\"/>\n <use x=\"852.070312\" xlink:href=\"#DejaVuSans-76\"/>\n <use x=\"907.783203\" xlink:href=\"#DejaVuSans-41\"/>\n </g>\n </g>\n <g id=\"line2d_26\">\n <path d=\"M 531.048125 50.094688 \nL 551.048125 50.094688 \n\" style=\"fill:none;stroke:#ff7f0e;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_27\"/>\n <g id=\"text_18\">\n <!-- torrenttools (OpenSSL) -->\n <g transform=\"translate(559.048125 53.594688)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 39.40625 66.21875 \nQ 28.65625 66.21875 22.328125 58.203125 \nQ 16.015625 50.203125 16.015625 36.375 \nQ 16.015625 22.609375 22.328125 14.59375 \nQ 28.65625 6.59375 39.40625 6.59375 \nQ 50.140625 6.59375 56.421875 14.59375 \nQ 62.703125 22.609375 62.703125 36.375 \nQ 62.703125 50.203125 56.421875 58.203125 \nQ 50.140625 66.21875 39.40625 66.21875 \nz\nM 39.40625 74.21875 \nQ 54.734375 74.21875 63.90625 63.9375 \nQ 73.09375 53.65625 73.09375 36.375 \nQ 73.09375 19.140625 63.90625 8.859375 \nQ 54.734375 -1.421875 39.40625 -1.421875 \nQ 24.03125 -1.421875 14.8125 8.828125 \nQ 5.609375 19.09375 5.609375 36.375 \nQ 5.609375 53.65625 14.8125 63.9375 \nQ 24.03125 74.21875 39.40625 74.21875 \nz\n\" id=\"DejaVuSans-79\"/>\n <path d=\"M 18.109375 8.203125 \nL 18.109375 -20.796875 \nL 9.078125 -20.796875 \nL 9.078125 54.6875 \nL 18.109375 54.6875 \nL 18.109375 46.390625 \nQ 20.953125 51.265625 25.265625 53.625 \nQ 29.59375 56 35.59375 56 \nQ 45.5625 56 51.78125 48.09375 \nQ 58.015625 40.1875 58.015625 27.296875 \nQ 58.015625 14.40625 51.78125 6.484375 \nQ 45.5625 -1.421875 35.59375 -1.421875 \nQ 29.59375 -1.421875 25.265625 0.953125 \nQ 20.953125 3.328125 18.109375 8.203125 \nz\nM 48.6875 27.296875 \nQ 48.6875 37.203125 44.609375 42.84375 \nQ 40.53125 48.484375 33.40625 48.484375 \nQ 26.265625 48.484375 22.1875 42.84375 \nQ 18.109375 37.203125 18.109375 27.296875 \nQ 18.109375 17.390625 22.1875 11.75 \nQ 26.265625 6.109375 33.40625 6.109375 \nQ 40.53125 6.109375 44.609375 11.75 \nQ 48.6875 17.390625 48.6875 27.296875 \nz\n\" id=\"DejaVuSans-112\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"39.208984\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"100.390625\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"139.753906\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"178.617188\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"240.140625\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"303.519531\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"342.728516\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"381.9375\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"443.119141\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"504.300781\" xlink:href=\"#DejaVuSans-108\"/>\n <use x=\"532.083984\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"584.183594\" xlink:href=\"#DejaVuSans-32\"/>\n <use x=\"615.970703\" xlink:href=\"#DejaVuSans-40\"/>\n <use x=\"654.984375\" xlink:href=\"#DejaVuSans-79\"/>\n <use x=\"733.695312\" xlink:href=\"#DejaVuSans-112\"/>\n <use x=\"797.171875\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"858.695312\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"922.074219\" xlink:href=\"#DejaVuSans-83\"/>\n <use x=\"985.550781\" xlink:href=\"#DejaVuSans-83\"/>\n <use x=\"1049.027344\" xlink:href=\"#DejaVuSans-76\"/>\n <use x=\"1104.740234\" xlink:href=\"#DejaVuSans-41\"/>\n </g>\n </g>\n <g id=\"line2d_28\">\n <path d=\"M 531.048125 64.772813 \nL 551.048125 64.772813 \n\" style=\"fill:none;stroke:#2ca02c;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_29\"/>\n <g id=\"text_19\">\n <!-- mktorrent -->\n <g transform=\"translate(559.048125 68.272813)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 9.078125 75.984375 \nL 18.109375 75.984375 \nL 18.109375 31.109375 \nL 44.921875 54.6875 \nL 56.390625 54.6875 \nL 27.390625 29.109375 \nL 57.625 0 \nL 45.90625 0 \nL 18.109375 26.703125 \nL 18.109375 0 \nL 9.078125 0 \nz\n\" id=\"DejaVuSans-107\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-109\"/>\n <use x=\"97.412109\" xlink:href=\"#DejaVuSans-107\"/>\n <use x=\"155.322266\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"194.53125\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"255.712891\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"295.076172\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"333.939453\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"395.462891\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"458.841797\" xlink:href=\"#DejaVuSans-116\"/>\n </g>\n </g>\n <g id=\"line2d_30\">\n <path d=\"M 531.048125 79.450938 \nL 551.048125 79.450938 \n\" style=\"fill:none;stroke:#d62728;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_31\"/>\n <g id=\"text_20\">\n <!-- torf-cli -->\n <g transform=\"translate(559.048125 82.950938)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"39.208984\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"100.390625\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"141.503906\" xlink:href=\"#DejaVuSans-102\"/>\n <use x=\"171.208984\" xlink:href=\"#DejaVuSans-45\"/>\n <use x=\"207.292969\" xlink:href=\"#DejaVuSans-99\"/>\n <use x=\"262.273438\" xlink:href=\"#DejaVuSans-108\"/>\n <use x=\"290.056641\" xlink:href=\"#DejaVuSans-105\"/>\n </g>\n </g>\n <g id=\"line2d_32\">\n <path d=\"M 531.048125 94.129063 \nL 551.048125 94.129063 \n\" style=\"fill:none;stroke:#9467bd;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_33\"/>\n <g id=\"text_21\">\n <!-- py3createtorrent -->\n <g transform=\"translate(559.048125 97.629063)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 32.171875 -5.078125 \nQ 28.375 -14.84375 24.75 -17.8125 \nQ 21.140625 -20.796875 15.09375 -20.796875 \nL 7.90625 -20.796875 \nL 7.90625 -13.28125 \nL 13.1875 -13.28125 \nQ 16.890625 -13.28125 18.9375 -11.515625 \nQ 21 -9.765625 23.484375 -3.21875 \nL 25.09375 0.875 \nL 2.984375 54.6875 \nL 12.5 54.6875 \nL 29.59375 11.921875 \nL 46.6875 54.6875 \nL 56.203125 54.6875 \nz\n\" id=\"DejaVuSans-121\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-112\"/>\n <use x=\"63.476562\" xlink:href=\"#DejaVuSans-121\"/>\n <use x=\"122.65625\" xlink:href=\"#DejaVuSans-51\"/>\n <use x=\"186.279297\" xlink:href=\"#DejaVuSans-99\"/>\n <use x=\"241.259766\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"280.123047\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"341.646484\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"402.925781\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"442.134766\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"503.658203\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"542.867188\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"604.048828\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"643.412109\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"682.275391\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"743.798828\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"807.177734\" xlink:href=\"#DejaVuSans-116\"/>\n </g>\n </g>\n <g id=\"line2d_34\">\n <path d=\"M 531.048125 108.807187 \nL 551.048125 108.807187 \n\" style=\"fill:none;stroke:#8c564b;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_35\"/>\n <g id=\"text_22\">\n <!-- transmission-create -->\n <g transform=\"translate(559.048125 112.307187)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"39.208984\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"80.322266\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"141.601562\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"204.980469\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"257.080078\" xlink:href=\"#DejaVuSans-109\"/>\n <use x=\"354.492188\" xlink:href=\"#DejaVuSans-105\"/>\n <use x=\"382.275391\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"434.375\" xlink:href=\"#DejaVuSans-115\"/>\n <use x=\"486.474609\" xlink:href=\"#DejaVuSans-105\"/>\n <use x=\"514.257812\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"575.439453\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"638.818359\" xlink:href=\"#DejaVuSans-45\"/>\n <use x=\"674.902344\" xlink:href=\"#DejaVuSans-99\"/>\n <use x=\"729.882812\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"768.746094\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"830.269531\" xlink:href=\"#DejaVuSans-97\"/>\n <use x=\"891.548828\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"930.757812\" xlink:href=\"#DejaVuSans-101\"/>\n </g>\n </g>\n <g id=\"line2d_36\">\n <path d=\"M 531.048125 123.485313 \nL 551.048125 123.485313 \n\" style=\"fill:none;stroke:#e377c2;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_37\"/>\n <g id=\"text_23\">\n <!-- pyrocore -->\n <g transform=\"translate(559.048125 126.985313)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-112\"/>\n <use x=\"63.476562\" xlink:href=\"#DejaVuSans-121\"/>\n <use x=\"122.65625\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"161.519531\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"222.701172\" xlink:href=\"#DejaVuSans-99\"/>\n <use x=\"277.681641\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"338.863281\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"377.726562\" xlink:href=\"#DejaVuSans-101\"/>\n </g>\n </g>\n <g id=\"line2d_38\">\n <path d=\"M 531.048125 138.163437 \nL 551.048125 138.163437 \n\" style=\"fill:none;stroke:#7f7f7f;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_39\"/>\n <g id=\"text_24\">\n <!-- buildtorrent -->\n <g transform=\"translate(559.048125 141.663437)scale(0.1 -0.1)\">\n <defs>\n <path d=\"M 48.6875 27.296875 \nQ 48.6875 37.203125 44.609375 42.84375 \nQ 40.53125 48.484375 33.40625 48.484375 \nQ 26.265625 48.484375 22.1875 42.84375 \nQ 18.109375 37.203125 18.109375 27.296875 \nQ 18.109375 17.390625 22.1875 11.75 \nQ 26.265625 6.109375 33.40625 6.109375 \nQ 40.53125 6.109375 44.609375 11.75 \nQ 48.6875 17.390625 48.6875 27.296875 \nz\nM 18.109375 46.390625 \nQ 20.953125 51.265625 25.265625 53.625 \nQ 29.59375 56 35.59375 56 \nQ 45.5625 56 51.78125 48.09375 \nQ 58.015625 40.1875 58.015625 27.296875 \nQ 58.015625 14.40625 51.78125 6.484375 \nQ 45.5625 -1.421875 35.59375 -1.421875 \nQ 29.59375 -1.421875 25.265625 0.953125 \nQ 20.953125 3.328125 18.109375 8.203125 \nL 18.109375 0 \nL 9.078125 0 \nL 9.078125 75.984375 \nL 18.109375 75.984375 \nz\n\" id=\"DejaVuSans-98\"/>\n <path d=\"M 8.5 21.578125 \nL 8.5 54.6875 \nL 17.484375 54.6875 \nL 17.484375 21.921875 \nQ 17.484375 14.15625 20.5 10.265625 \nQ 23.53125 6.390625 29.59375 6.390625 \nQ 36.859375 6.390625 41.078125 11.03125 \nQ 45.3125 15.671875 45.3125 23.6875 \nL 45.3125 54.6875 \nL 54.296875 54.6875 \nL 54.296875 0 \nL 45.3125 0 \nL 45.3125 8.40625 \nQ 42.046875 3.421875 37.71875 1 \nQ 33.40625 -1.421875 27.6875 -1.421875 \nQ 18.265625 -1.421875 13.375 4.4375 \nQ 8.5 10.296875 8.5 21.578125 \nz\nM 31.109375 56 \nz\n\" id=\"DejaVuSans-117\"/>\n </defs>\n <use xlink:href=\"#DejaVuSans-98\"/>\n <use x=\"63.476562\" xlink:href=\"#DejaVuSans-117\"/>\n <use x=\"126.855469\" xlink:href=\"#DejaVuSans-105\"/>\n <use x=\"154.638672\" xlink:href=\"#DejaVuSans-108\"/>\n <use x=\"182.421875\" xlink:href=\"#DejaVuSans-100\"/>\n <use x=\"245.898438\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"285.107422\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"346.289062\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"385.652344\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"424.515625\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"486.039062\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"549.417969\" xlink:href=\"#DejaVuSans-116\"/>\n </g>\n </g>\n <g id=\"line2d_40\">\n <path d=\"M 531.048125 152.841563 \nL 551.048125 152.841563 \n\" style=\"fill:none;stroke:#bcbd22;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_41\"/>\n <g id=\"text_25\">\n <!-- dottorrent-cli -->\n <g transform=\"translate(559.048125 156.341563)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-100\"/>\n <use x=\"63.476562\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"124.658203\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"163.867188\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"203.076172\" xlink:href=\"#DejaVuSans-111\"/>\n <use x=\"264.257812\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"303.621094\" xlink:href=\"#DejaVuSans-114\"/>\n <use x=\"342.484375\" xlink:href=\"#DejaVuSans-101\"/>\n <use x=\"404.007812\" xlink:href=\"#DejaVuSans-110\"/>\n <use x=\"467.386719\" xlink:href=\"#DejaVuSans-116\"/>\n <use x=\"506.595703\" xlink:href=\"#DejaVuSans-45\"/>\n <use x=\"542.679688\" xlink:href=\"#DejaVuSans-99\"/>\n <use x=\"597.660156\" xlink:href=\"#DejaVuSans-108\"/>\n <use x=\"625.443359\" xlink:href=\"#DejaVuSans-105\"/>\n </g>\n </g>\n <g id=\"line2d_42\">\n <path d=\"M 531.048125 167.519687 \nL 551.048125 167.519687 \n\" style=\"fill:none;stroke:#17becf;stroke-linecap:square;stroke-width:1.5;\"/>\n </g>\n <g id=\"line2d_43\"/>\n <g id=\"text_26\">\n <!-- imdl -->\n <g transform=\"translate(559.048125 171.019687)scale(0.1 -0.1)\">\n <use xlink:href=\"#DejaVuSans-105\"/>\n <use x=\"27.783203\" xlink:href=\"#DejaVuSans-109\"/>\n <use x=\"125.195312\" xlink:href=\"#DejaVuSans-100\"/>\n <use x=\"188.671875\" xlink:href=\"#DejaVuSans-108\"/>\n </g>\n </g>\n </g>\n </g>\n </g>\n <defs>\n <clipPath id=\"p4d0c9becf6\">\n <rect height=\"434.88\" width=\"446.4\" x=\"53.328125\" y=\"22.318125\"/>\n </clipPath>\n </defs>\n</svg>\n",
"image/png": "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t9+madOmNG/enN9//911fOfOnYSHh9O0aVOeeeYZVFUt6W4LIYQQogBms5latWpJsCqKhUajoVatWoWO2Jd4wDp37lxCQkJyHHv++edJSEggISGB/v37A5CUlMQ333zDvn37WLt2LU888QQOhwOAyZMnExsby+HDhzl8+DBr164t6W4LIYQQohASrIridKPvpxINWE+fPs2vv/7KxIkTb3jt6tWreeihh/Dw8CA4OJimTZuyY8cOUlNTycjIoEOHDmg0GsaOHcuqVatKsttCCCGEEKIcKdGA9bnnnuOdd95Bq835mPnz5xMREcGECRO4cuUKAGfOnKFBgwaua4KCgjhz5gxnzpwhKCgoz/H8xMbGEhUVRVRUFBcuXCiBdySEEEKIspaWlsbHH39cJs+eM2cORqPR9fqtt966rfZ8fX1v6vr777+fY8eOAc4iSdeqm7355puEhoYSERFBZGQkf/31l+seu91O7dq1+b//+78C2128eDFPPfVUnuM9e/Z0xWplqcQC1l9++YW6devStm3bHMcnT57M0aNHSUhIICAggBdffBEg33WpGo2mwOP5mTRpEvHx8cTHx1OnTp1ieBdCCCGEKG9uJWC9tsywoNdFVdwB683Yt28fDoeDxo0b5zi+bds2fvnlF3bt2sXevXtZv359jkHAdevW0bx5c7799tub3gc0ZsyYMvvlILsSyxKwZcsWfvrpJ9asWYPZbCYjI4PRo0fz1Vdfua559NFHXZuxgoKCOHXqlOvc6dOnCQwMJCgoiNOnT+c5LoQQQoiy98bP+0hKySjWNlsG+jNtYGiB56dMmcLRo0eJjIykV69evPPOO7zyyiv89ttvaDQaXnvtNR588EHi4uJ44403CAgIICEhgY8//jjH63/++YcpU6YQFxeHxWLhySef5LHHHiMuLo7p06dTu3ZtEhMTadu2LV999RUffvghKSkpdO/endq1a9O+fXtMJhORkZGEhoaybNky3n//fb744gsAJk6cyHPPPQdQ4PFrUlNTefDBB8nIyMBut/PJJ5/QuXPnHNcsW7aMwYMH5/l6pKamUrt2bTw8PACoXbt2jvPLly/n2Wef5ZNPPmH79u106NChyH8XgwYNonPnzrz66qtFvqcklFjA+vbbb/P2228DEBcXx7vvvstXX31FamoqAQEBAKxcuZKwsDDA+QUZOXIkL7zw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jx492Lt3L8888wzvv/8+GzdupHbt2ly8eJGZM2eyfv16fHx8mD17Nu+//z5Tp069ib/ZWycjrKLMWe0KRmveqYpzGWZm/ppE8/p+PNGtab73ajUa/D2lOIAQQlR10dHRrmAVnCOE10ZRT506xeHDhwFwd3d3jWy2bduW5ORkADp27Mj48eNZsGBBjunz7t274+fnR506dahWrRoDBw4EIDw83HXvNf7+/nh6ejJx4kR+/PFHvL29C237ms2bNzNmzBgA7rnnHi5dukR6ejoA9957Lx4eHtSuXZu6deu6RoSzW79+PU8++aTrdY0aNQDQ6XQMGzYMgD/++IOdO3fSrl07IiMj+eOPPzh2zPmLxrfffkubNm1o3bo1+/btIykpKc8ztm/fTlJSEh07diQyMpIlS5Zw4sSJfP8uSoIMS4kydW0pQG52RWHq6n3YHSozh4Th7pb3dyspDiCEEGXvRiOhpcXHx8f157i4ONavX8+2bdvw9vamW7dumM1mAPR6vWtzrk6nw2537p349NNP+euvv/j111+JjIx0jXB6eFxfiqbVal2vtVqt695r3Nzc2LFjB3/88QfffPMN8+fPZ8OGDQW2fY2aT5Wca33M/vxr/f3oo49YsGABAGvWrEFV1Xw3HHt6eqLT6VzPGDduHG+//XaOa44fP867777L33//TY0aNRg/frzra5W7j7169WL58uV5zpUGGWEVZSrDbEfJ5x/qos3JJJxK45W+zbmzpne+90pxACGEqLr8/PzIzMzM91x6ejo1atTA29ubAwcOsH379hu2d/ToUdq3b8+MGTOoXbs2p06duuk+GQwG0tPT6d+/P3PmzHEFpjdqu0uXLixbtgxwBtu1a9fG39+/wOc8+eSTJCQkkJCQQGBgIL1792b+/Pmu89eWBGTXo0cPvv/+e86fPw84ly+cOHGCjIwMfHx8qFatGufOneO3335z3ZP9axwTE8OWLVs4cuQIAEajkUOHDt301+hWyQirKDNmmwOzLe/UyK4TV/hiy3H6h9enX1hAvvdKcQAhhKjaatWqRceOHQkLC8PLy4t69eq5zvXt25dPP/2UiIgImjdvTkxMzA3be/nllzl8+DCqqtKjRw9atWqVZyT0RjIzMxk8eDBmsxlVVfnggw8KbPt///uf677p06fz8MMPExERgbe3N0uWLLmp57722ms8+eST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\n"
},
"metadata": {}
}
],
"source": [
"import matplotlib.cm\n",
"fig, ax = plt.subplots(1, 1, figsize=(8, 8))\n",
"\n",
"programs = df.index.unique(level=1)\n",
"threads = df.index.unique(level=0)\n",
"programs_by_max_speed = {}\n",
"\n",
"for program in programs:\n",
" sm = df.loc[df.index.get_level_values(1) == program, \"speed_mean\"]\n",
" programs_by_max_speed[program] = np.max(sm)\n",
"\n",
"sorted_programs = sorted(programs_by_max_speed.keys(), key=lambda x : programs_by_max_speed[x], reverse=True)\n",
"\n",
"for idx, program in enumerate(sorted_programs):\n",
" sm = df.loc[df.index.get_level_values(1) == program, \"speed_mean\"]\n",
" sd = df.loc[df.index.get_level_values(1) == program, \"speed_stddev\"]\n",
" ax.plot(threads, sm)\n",
" ax.fill_between(threads, sm - sd, sm + sd, alpha=0.1)\n",
"\n",
"ax.set_title(\"Performance\")\n",
"ax.set_xlabel(\"# hashing threads\")\n",
"ax.set_ylabel(\"Hash rate (MiB/s)\")\n",
"ax.set_xticks(list(range(1, max_threads+1)))\n",
"ax.legend(sorted_programs, bbox_to_anchor=(1.05, 1), loc='upper left')\n",
"fig.patch.set_facecolor(\"white\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
]
}
================================================
FILE: benchmark/benchmark.sh
================================================
#!/usr/bin/env bash
program_name=$1
working_dir=$2
target=$3
threads=$4
function benchmark_mktorrent()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time mktorrent -t$threads -l20 "$target" 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_torrenttools_openssl()
{
target="$1"
threads="$2"
rm *.torrent
# gdbserver :1234 torrenttools-release create -t$threads -l20 "$target"
out="$(time torrenttools-release create -t$threads -l20 "$target" 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_torrenttools_isal()
{
target="$1"
threads="$2"
rm *.torrent
# torrenttools-isal-release create -t$threads -l20 "$target" 2>&1
out="$(time torrenttools-isal-release create -t$threads -l20 "$target" 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_imdl()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time imdl torrent create --piece-length 1MiB "$target" 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_dottorrent_cli()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time dottorrent --piece_size 1M "$target" "output.torrent" 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_pyrocore()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time mktor --chunk-min=1M --chunk-max=1M "$target" https://testurl.com/announce 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_transmission()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time transmission-create --piece-size 1024 "$target" 1> /dev/null 2> /dev/null)";
echo "$out"
return;
}
function benchmark_py3createtorrent()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time py3createtorrent -p 1024 "$target" 1> /dev/null 2> /dev/null)"
echo "$out"
return;
}
function benchmark_torf_cli()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time torf --max-piece-size 1024 --threads "$threads" "$target" 1> /dev/null 2> /dev/null)"
echo "$out"
return;
}
function benchmark_buildtorrent()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time buildtorrent --piecesize 20 --announce dummy "$target" output 1> /dev/null 2> /dev/null)"
echo "$out"
return;
}
function benchmark_maketorrent()
{
target="$1"
threads="$2"
rm *.torrent
out="$(time maketorrent --piece-length 20 --announce dummy "$target" 1> /dev/null 2> /dev/null)"
echo "$out"
return;
}
cd "$working_dir"
if [[ $program_name == "mktorrent" ]]; then
benchmark_mktorrent "$target" "$threads"
elif [[ $program_name == "torrenttools_openssl" ]]; then
benchmark_torrenttools_openssl "$target" "$threads"
elif [[ $program_name == "torrenttools_isal" ]]; then
benchmark_torrenttools_isal "$target" "$threads"
elif [[ $program_name == "imdl" ]]; then
benchmark_imdl "$target" "$threads"
elif [[ $program_name == "pyrocore" ]]; then
benchmark_pyrocore "$target" "$threads"
elif [[ $program_name == "dottorrent-cli" ]]; then
benchmark_dottorrent_cli "$target" "$threads"
elif [[ $program_name == "transmission-create" ]]; then
benchmark_transmission "$target" "$threads"
elif [[ $program_name == "py3createtorrent" ]]; then
benchmark_py3createtorrent "$target" "$threads"
elif [[ $program_name == "maketorrent" ]]; then
benchmark_maketorrent "$target" "$threads"
elif [[ $program_name == "torf-cli" ]]; then
benchmark_torf_cli "$target" "$threads"
elif [[ $program_name == "buildtorrent" ]]; then
benchmark_buildtorrent "$target" "$threads"
elif [[ $program_name == "maketorrent" ]]; then
benchmark_buildtorrent "$target" "$threads"
else
echo "Error: Invalid program name: $program_name"
fi
================================================
FILE: cmake/FindISALCrypto.cmake
================================================
#.rst:
# FindISALCrypto
# -----------
#
# Find the isal-l_crypto library.
#
# IMPORTED Targets
# ^^^^^^^^^^^^^^^^
#
# This module defines :prop_tgt:`IMPORTED` targets:
#
# ``ISAL::Crypto``
# The isa-l_crypto library, if found.
#
# Result variables
# ^^^^^^^^^^^^^^^^
#
# This module defines the following variables:
#
# ::
#
# ISALCrypto_FOUND - true if the headers and library were found
# ISALCrypto_INCLUDE_DIRS - where to find headers
# ISALCrypto_LIBRARIES - list of libraries to link
# ISALCrypto_VERSION - library version that was found, if any
# use pkg-config to get the directories and then use these values
# in the find_path() and find_library() calls
find_package(PkgConfig QUIET)
pkg_check_modules(PC_ISALCrypto QUIET isa-l_crypto)
# find the headers
find_path(ISALCrypto_INCLUDE_DIR
NAMES isa-l_crypto.h
HINTS
${PC_ISALCrypto_INCLUDEDIR}
${PC_ISALCrypto_INCLUDE_DIRS}
PATH_SUFFIXES isa-l_crypto
)
# find the library
find_library(ISALCrypto
NAMES isal_crypto libisal_crypto
HINTS
${PC_ISALCrypto_LIBDIR}
${PC_ISALCrypto_DIRS}
)
# determine the version
if(PC_ISALCrypto_VERSION)
set(ISALCrypto_VERSION ${PC_ISALCrypto_VERSION})
elseif(ISALCrypto_INCLUDE_DIR AND EXISTS "${ISALCrypto_INCLUDE_DIR}/isa-l_crypto.h")
file(STRINGS "${ISALCrypto_INCLUDE_DIR}/isa-l_crypto.h" isal_crypto_version_str
REGEX "^#define[\t ]+(ISALCrypto_VERSION_[A-Z]+)[\t ]+[0-9]+")
string(REGEX REPLACE ".*#define[\t ]+ISAL_CRYPTO_VERSION_MAJOR[\t ]+([0-9]+).*"
"\\1" _isal_crypto_version_major "${isal_crypto_version_str}")
string(REGEX REPLACE ".*#define[\t ]+ISAL_CRYPTO_VERSION_MINOR[\t ]+([0-9]+).*"
"\\1" _isal_crypto_version_minor "${isal_crypto_version_str}")
string(REGEX REPLACE ".*#define[\t ]+ISAL_CRYPTO_VERSION_PATCH[\t ]+([0-9]+).*"
"\\1" _isal_crypto_version_patch "${isal_crypto_version_str}")
set(ISALCrypto_VERSION "${_isal_crypto_version_major}.${_isal_crypto_version_minor}.${_isal_crypto_version_patch}"
CACHE INTERNAL "The version of ISAL_CRYPTO which was detected")
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ISALCrypto
REQUIRED_VARS ISALCrypto ISALCrypto_INCLUDE_DIR
VERSION_VAR ISALCrypto_VERSION
)
if (ISALCrypto_FOUND)
set(ISALCrypto_INCLUDE_DIRS ${ISALCrypto_INCLUDE_DIR} ${PC_ISALCrypto_INCLUDE_DIRS})
set(ISALCrypto_LIBRARIES ${ISALCrypto})
endif()
if (ISALCrypto_FOUND AND NOT TARGET ISAL::Crypto)
# create the new library target
add_library(ISAL::Crypto UNKNOWN IMPORT
gitextract_bkmqqxe5/
├── .dockerignore
├── .github/
│ ├── FUNDING.yml
│ └── workflows/
│ ├── documentation.yml
│ ├── linux.yml
│ ├── macos.yml
│ ├── package.yml
│ └── windows.yml
├── .gitignore
├── CHANGELOG.md
├── CMakeLists.txt
├── Dockerfile
├── LICENSE
├── README.md
├── benchmark/
│ ├── benchmark.csv
│ ├── benchmark.ipynb
│ └── benchmark.sh
├── cmake/
│ ├── FindISALCrypto.cmake
│ ├── FindNASM.cmake
│ ├── FindSphinx.cmake
│ ├── FindTBB.cmake
│ └── SanitizersConfig.cmake
├── docs/
│ ├── CMakeLists.txt
│ ├── bep-support.csv
│ ├── commands/
│ │ ├── create.rst
│ │ ├── edit.rst
│ │ ├── info.rst
│ │ ├── magnet.rst
│ │ ├── pad.rst
│ │ ├── show.rst
│ │ └── verify.rst
│ ├── comparison.rst
│ ├── conf.py.in
│ ├── configuration.rst
│ ├── index.rst
│ ├── topics/
│ │ ├── bencode.rst
│ │ ├── bittorrent-metafile-v1.rst
│ │ └── glossary.rst
│ └── why-torrenttools.rst
├── external/
│ ├── CLI11.cmake
│ ├── Catch2.cmake
│ ├── bencode.cmake
│ ├── cliprogress.cmake
│ ├── ctre.cmake
│ ├── date.cmake
│ ├── dottorrent.cmake
│ ├── expected-lite.cmake
│ ├── external.cmake
│ ├── fmt.cmake
│ ├── gsl-lite.cmake
│ ├── isa-l_crypto.cmake
│ ├── nlohmann_json.cmake
│ ├── re2.cmake
│ ├── sigslot.cmake
│ ├── termcontrol.cmake
│ └── yaml-cpp.cmake
├── include/
│ ├── app_data.hpp
│ ├── argument_parsers.hpp
│ ├── cli_helpers.hpp
│ ├── common.hpp
│ ├── config.hpp.in
│ ├── config_parser.hpp
│ ├── create.hpp
│ ├── edit.hpp
│ ├── escape_binary_fields.hpp
│ ├── exceptions.hpp
│ ├── file_matcher.hpp
│ ├── formatters.hpp
│ ├── help_formatter.hpp
│ ├── indicator.hpp
│ ├── info.hpp
│ ├── list_edit_mode.hpp
│ ├── ls_colors.hpp
│ ├── magnet.hpp
│ ├── main_app.hpp
│ ├── natural_sort.hpp
│ ├── pad.hpp
│ ├── profile.hpp
│ ├── profile_config_formatter.hpp
│ ├── progress.hpp
│ ├── show.hpp
│ ├── tracker_database.hpp
│ ├── tree_view.hpp
│ ├── utils.hpp
│ └── verify.hpp
├── packages/
│ ├── appimage/
│ │ ├── build_appimage.sh
│ │ ├── torrenttools-appimage-recipe.yml
│ │ └── torrenttools.desktop
│ ├── arch/
│ │ └── PKGBUILD
│ ├── cpack_dispatch.cmake
│ ├── debian/
│ │ ├── changelog
│ │ ├── compat
│ │ ├── control
│ │ ├── copyright
│ │ ├── rules
│ │ └── source/
│ │ └── format
│ ├── macos-productbuild.cmake
│ ├── package_summary.txt
│ ├── packages.cmake
│ ├── productbuild/
│ │ └── postflight.sh
│ ├── rpm/
│ │ └── torrenttools.spec
│ ├── ubuntu/
│ │ ├── 20.04/
│ │ │ └── changelog
│ │ └── 21.04/
│ │ └── changelog
│ ├── windows-wix.cmake
│ └── wix/
│ ├── broadcast_env_change.xml
│ ├── copy-config.xml
│ ├── create-localappdata-folder.wxs
│ ├── disable_feature_advertise.xml
│ └── update_path.xml
├── resources/
│ ├── config.yml
│ └── trackers.json
├── scripts/
│ └── fetch_dependencies.sh
├── src/
│ ├── app_data.cpp
│ ├── argument_parsers.cpp
│ ├── common.cpp
│ ├── config_parser.cpp
│ ├── create.cpp
│ ├── edit.cpp
│ ├── escape_binary_fields.cpp
│ ├── formatters.cpp
│ ├── indicator.cpp
│ ├── info.cpp
│ ├── ls_colors.cpp
│ ├── magnet.cpp
│ ├── main.cpp
│ ├── main_app.cpp
│ ├── pad.cpp
│ ├── profile.cpp
│ ├── progress.cpp
│ ├── show.cpp
│ ├── tracker_database.cpp
│ ├── tree_view.cpp
│ └── verify.cpp
└── tests/
├── CMakeLists.txt
├── main.cpp
├── private.torrent/
│ └── test_file.txt.torrent
├── resources/
│ ├── CAMELYON17.torrent
│ ├── COVID-19-image-dataset-collection.torrent
│ ├── Fedora-Workstation-Live-x86_64-30.torrent
│ ├── RSNA_Pneumonia_Detection_Challenge.torrent
│ ├── bittorrent-v2-hybrid-test.torrent
│ ├── bittorrent-v2-test.torrent
│ ├── checksums.torrent
│ ├── collection.torrent
│ ├── config/
│ │ ├── config.yml
│ │ └── trackers.json
│ ├── dht-node.torrent
│ ├── http-seeds.torrent
│ ├── lorem_ipsum.txt
│ ├── private.torrent
│ ├── resources-hybrid.torrent
│ ├── resources.torrent
│ ├── similar-v1.torrent
│ ├── similar-v2.torrent
│ ├── test-torrent/
│ │ ├── dirA/
│ │ │ ├── fileA1
│ │ │ └── fileA2
│ │ └── dirB/
│ │ ├── fileB1
│ │ └── fileB2
│ ├── test_file
│ ├── tests.torrent
│ ├── tree_index_test.torrent
│ ├── ubuntu-20.04.1-live-server-amd64.iso.torrent
│ └── web-seed.torrent
├── test_create.cpp
├── test_edit.cpp
├── test_file_matcher.cpp
├── test_info.cpp
├── test_ls_colors.cpp
├── test_magnet.cpp
├── test_main.cpp
├── test_pad.cpp
├── test_profile.cpp
├── test_resources.hpp
├── test_show.cpp
├── test_tracker_database.cpp
├── test_tree_view.cpp
├── test_utils.cpp
└── test_verify.cpp
SYMBOL INDEX (261 symbols across 46 files)
FILE: include/cli_helpers.hpp
function verify_metafile (line 8) | inline void verify_metafile(const fs::path& metafile)
FILE: include/common.hpp
type torrenttools (line 13) | namespace torrenttools {
class config (line 14) | class config
class tracker_database (line 15) | class tracker_database
type main_app_options (line 18) | struct main_app_options
FILE: include/config_parser.hpp
type YAML (line 14) | namespace YAML { class Node; }
class Node (line 14) | class Node
type torrenttools (line 16) | namespace torrenttools {
class config (line 20) | class config
FILE: include/create.hpp
type CLI (line 25) | namespace CLI { class App; }
class App (line 25) | class App
type torrenttools (line 26) | namespace torrenttools { class file_matcher; }
class file_matcher (line 26) | class file_matcher
type create_app_options (line 28) | struct create_app_options
FILE: include/edit.hpp
type CLI (line 13) | namespace CLI { class App; }
class App (line 13) | class App
type edit_app_options (line 18) | struct edit_app_options
FILE: include/exceptions.hpp
type torrenttools (line 3) | namespace torrenttools
class config_error (line 6) | class config_error : public std::invalid_argument
class profile_error (line 12) | class profile_error : public config_error
FILE: include/file_matcher.hpp
type torrenttools (line 14) | namespace torrenttools {
class file_matcher (line 26) | class file_matcher
method file_matcher (line 29) | file_matcher()
method include_hidden_files (line 36) | void include_hidden_files(bool flag)
method allow_extension (line 41) | void allow_extension(std::string_view extension)
method block_extension (line 56) | void block_extension(std::string_view extension)
method include_pattern (line 71) | void include_pattern(std::string_view pattern)
method exclude_pattern (line 84) | void exclude_pattern(std::string_view pattern)
method exclude_directory (line 99) | void exclude_directory(const fs::path& dir)
method compile (line 108) | void compile()
method set_search_root (line 124) | void set_search_root(const fs::path& root)
method files_processed (line 130) | std::size_t files_processed() const noexcept
method files_included (line 135) | std::size_t files_included() const noexcept
method start (line 140) | void start()
method is_running (line 146) | bool is_running() const noexcept
method results (line 151) | [[nodiscard]] std::vector<fs::path> results()
method wait (line 156) | void wait()
method stop (line 163) | void stop()
method run (line 169) | void run(std::stop_token stop_token)
method is_hidden_file (line 214) | static bool is_hidden_file(const fs::directory_entry& entry)
method make_default_options (line 219) | static re2::RE2::Options make_default_options()
FILE: include/formatters.hpp
type torrenttools (line 9) | namespace torrenttools {
function format_duration (line 16) | std::string format_duration(std::chrono::duration<Rep, Period> duration)
type unit_base (line 39) | enum class unit_base { decimal, binary }
function format_hash_rate (line 44) | inline auto format_hash_rate(double rate)-> std::string
FILE: include/help_formatter.hpp
class help_formatter (line 6) | class help_formatter : public CLI::Formatter {
method make_option_opts (line 8) | std::string make_option_opts(const CLI::Option* opt) const override {
FILE: include/indicator.hpp
class progress_indicator (line 30) | class progress_indicator
function on_indicator_completion (line 92) | inline void on_indicator_completion(std::unique_ptr<cliprogress::progres...
FILE: include/info.hpp
type format_type (line 16) | enum class format_type { text, json }
type info_app_options (line 18) | struct info_app_options
type formatting_options (line 34) | struct formatting_options
FILE: include/list_edit_mode.hpp
type torrenttools (line 3) | namespace torrenttools {
type list_edit_mode (line 5) | enum list_edit_mode
FILE: include/ls_colors.hpp
type detail (line 26) | namespace detail {
type ls_colors (line 42) | struct ls_colors
type ls_colors_data (line 47) | struct ls_colors_data
FILE: include/magnet.hpp
type magnet_app_options (line 19) | struct magnet_app_options
FILE: include/natural_sort.hpp
type SI (line 32) | namespace SI
type natural (line 34) | namespace natural
type detail (line 36) | namespace detail
function natural_less (line 40) | bool natural_less(const ElementType &lhs,const ElementType &rhs)
function is_not_digit (line 48) | bool is_not_digit(const ElementType &x)
type comp_over_iterator (line 55) | struct comp_over_iterator
type compare_number (line 85) | struct compare_number
method fractional (line 89) | int fractional(Iterator lhsBegin,Iterator lhsEnd, Iterator rhsBe...
method non_fractional (line 108) | int non_fractional(Iterator lhsBegin,Iterator lhsEnd, Iterator r...
function _compare (line 170) | bool _compare(\
function compare (line 239) | inline bool compare(const String &first ,const String &second)
function compare (line 244) | inline bool compare(char *const &first ,char *const &second)
function sort (line 255) | inline void sort(Container &container)
function sort (line 261) | inline void sort(const Iterator &first,const Iterator &end)
function sort (line 267) | inline void sort(ValueType* const first,ValueType* const end)
function sort (line 273) | inline void sort(ValueType container[N])
FILE: include/pad.hpp
type CLI (line 18) | namespace CLI { class App; }
class App (line 18) | class App
type pad_app_options (line 22) | struct pad_app_options
FILE: include/profile.hpp
type torrenttools (line 14) | namespace torrenttools {
type profile (line 17) | struct profile
FILE: include/profile_config_formatter.hpp
class profile_config_formatter (line 5) | class profile_config_formatter : public CLI::Config
FILE: include/show.hpp
type CLI (line 9) | namespace CLI { class App; }
class App (line 9) | class App
type show_app_options (line 13) | struct show_app_options
FILE: include/tracker_database.hpp
type torrenttools (line 15) | namespace torrenttools
class config (line 21) | class config
type tracker (line 23) | struct tracker
class tracker_database (line 35) | class tracker_database
FILE: include/tree_view.hpp
type tree_options (line 40) | struct tree_options
function ellipsize (line 50) | inline bool ellipsize(std::string& line, std::size_t max_size = 100)
type filetree_index (line 63) | struct filetree_index
type node (line 65) | struct node {
type directory_content_entry (line 72) | struct directory_content_entry
method filetree_index (line 79) | explicit filetree_index(const dottorrent::file_storage& storage, bool ...
method get_directory_size (line 91) | auto get_directory_size(const fs::path& dir) -> std::size_t
method list_directory_content (line 97) | std::vector<directory_content_entry> list_directory_content(const fs::...
method create_sorted_file_indices (line 135) | void create_sorted_file_indices(const dt::file_storage& storage)
method create_directory_map (line 149) | void create_directory_map(const dt::file_storage& storage)
method remove_padding_file_only_directories (line 186) | void remove_padding_file_only_directories()
class tree_printer (line 205) | class tree_printer
type stack_frame (line 218) | struct stack_frame
FILE: include/utils.hpp
type torrenttools::detail (line 6) | namespace torrenttools::detail {
function ltrim (line 9) | static inline void ltrim(std::string &s) {
function rtrim (line 16) | static inline void rtrim(std::string &s) {
function trim (line 23) | static inline void trim(std::string &s) {
function ltrim_copy (line 29) | static inline std::string ltrim_copy(std::string s) {
function rtrim_copy (line 35) | static inline std::string rtrim_copy(std::string s) {
function trim_copy (line 41) | static inline std::string trim_copy(std::string s) {
FILE: include/verify.hpp
type verify_app_options (line 19) | struct verify_app_options
FILE: src/app_data.cpp
function get_user_data_dir (line 3) | fs::path get_user_data_dir()
function get_app_data_search_path (line 32) | std::vector<fs::path> get_app_data_search_path()
FILE: src/argument_parsers.cpp
function ltrim (line 36) | static inline void ltrim(std::string &s) {
function rtrim (line 43) | static inline void rtrim(std::string &s) {
function trim (line 50) | static inline void trim(std::string &s) {
function checksum_transformer (line 56) | std::unordered_set<dottorrent::hash_function> checksum_transformer(const...
function piece_size_transformer (line 74) | std::optional<std::size_t> piece_size_transformer(const std::vector<std:...
function io_block_size_transformer (line 84) | std::optional<std::size_t> io_block_size_transformer(const std::vector<s...
function announce_transformer (line 93) | std::vector<std::vector<std::string>> announce_transformer(const std::ve...
function announce_transformer (line 128) | std::vector<std::vector<std::string>> announce_transformer(const YAML::N...
function dht_node_transformer (line 156) | std::vector<dottorrent::dht_node> dht_node_transformer(const std::vector...
function protocol_transformer (line 179) | dottorrent::protocol protocol_transformer(const std::vector<std::string>...
function path_transformer (line 205) | std::filesystem::path path_transformer(const std::vector<std::string>& v...
function config_path_transformer (line 235) | std::filesystem::path config_path_transformer(const std::vector<std::str...
function metafile_target_transformer (line 256) | std::filesystem::path metafile_target_transformer(const std::vector<std:...
function parse_commandline_size (line 280) | std::optional<std::size_t> parse_commandline_size(std::string_view optio...
function parse_commandline_booleans (line 320) | std::vector<std::optional<bool>> parse_commandline_booleans(std::string_...
function parse_commandline_bool (line 345) | std::optional<bool> parse_commandline_bool(std::string_view option, cons...
function parse_offset (line 358) | std::chrono::minutes parse_offset(std::istream& in)
function parse_utc_datetime (line 374) | std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
function creation_date_transformer (line 428) | std::chrono::system_clock::time_point
function parse_list_edit_mode (line 458) | torrenttools::list_edit_mode parse_list_edit_mode(std::string_view optio...
function parse_explicit_flag (line 488) | bool parse_explicit_flag(std::string_view option, const std::vector<std:...
function similar_transformer (line 500) | std::vector<dt::info_hash>
function seed_transformer (line 549) | std::vector<std::string>
FILE: src/common.cpp
function load_config_and_tracker_db (line 13) | std::pair<const torrenttools::config*, const torrenttools::tracker_datab...
function set_tracker_group (line 46) | void set_tracker_group(dottorrent::metafile& m, const std::vector<std::s...
function set_trackers (line 78) | void set_trackers(dottorrent::metafile& m, const std::vector<std::vector...
function set_trackers (line 145) | void set_trackers(dottorrent::metafile& m, const std::vector<std::vector...
function get_destination_path (line 165) | std::filesystem::path get_destination_path(dottorrent::metafile& m, std:...
FILE: src/config_parser.cpp
type torrenttools (line 17) | namespace torrenttools {
function profile (line 172) | const profile& config::get_profile(std::string_view profile_name) const
function config (line 177) | config* load_config()
function config (line 214) | config* load_config(const fs::path& custom_path)
FILE: src/create.cpp
function configure_create_app (line 51) | void configure_create_app(CLI::App* app, create_app_options& options)
function configure_matcher (line 303) | void configure_matcher(torrenttools::file_matcher& matcher, const create...
function set_files_with_progress (line 318) | void set_files_with_progress(dottorrent::metafile& m, const create_app_o...
function postprocess_create_app (line 382) | void postprocess_create_app(const CLI::App* app, const main_app_options&...
function run_create_app (line 395) | void run_create_app(const main_app_options& main_options, create_app_opt...
function merge_create_profile (line 549) | void merge_create_profile(const tt::config& cfg, std::string_view profil...
FILE: src/edit.cpp
function configure_edit_app (line 20) | void configure_edit_app(CLI::App* app, edit_app_options& options)
function postprocess_edit_app (line 193) | void postprocess_edit_app(const CLI::App* app, const main_app_options& m...
function merge_edit_profile (line 206) | void merge_edit_profile(const tt::config& cfg, std::string_view profile_...
function run_edit_app (line 285) | void run_edit_app(const main_app_options& main_options, const edit_app_o...
function update_announces (line 350) | void update_announces(dt::metafile& m, const main_app_options& main_opti...
function update_announce_group (line 379) | void update_announce_group(dt::metafile& m, const main_app_options& main...
function update_web_seeds (line 423) | void update_web_seeds(dt::metafile& m, const edit_app_options& options)
function update_http_seeds (line 454) | void update_http_seeds(dt::metafile& m, const edit_app_options& options)
function update_dht_nodes (line 484) | void update_dht_nodes(dt::metafile& m, const edit_app_options& options)
function update_similar_torrents (line 514) | void update_similar_torrents(dt::metafile& m, const edit_app_options& op...
function update_collections (line 544) | void update_collections(dt::metafile& m, const edit_app_options& options)
FILE: src/escape_binary_fields.cpp
function escape_binary_metafile_fields (line 6) | bc::bvalue escape_binary_metafile_fields(const bencode::bvalue& value)
function make_v1_piece_list (line 67) | inline auto make_v1_piece_list(bc::bvalue& pieces_field)
function make_v2_piece_list (line 83) | inline auto make_v2_piece_list(bc::bvalue& pieces_field)
function escape_binary_metafile_fields_hex (line 100) | bc::bvalue escape_binary_metafile_fields_hex(const bencode::bvalue& value)
FILE: src/formatters.cpp
type torrenttools (line 3) | namespace torrenttools {
function format_si_prefix (line 6) | std::string format_si_prefix(double value, std::string_view unit, unit...
function format_tree_size (line 33) | std::string format_tree_size(double size)
function format_size (line 50) | std::string format_size(double size, std::size_t precision)
function format_percentage (line 75) | std::string format_percentage(double value)
function format_protocol_version (line 81) | std::string format_protocol_version(dottorrent::protocol version)
FILE: src/indicator.cpp
function print_simple_indicator (line 197) | void print_simple_indicator(std::ostream& os, const dottorrent::file_sto...
function print_simple_indicator_v1 (line 209) | void print_simple_indicator_v1(std::ostream& os, const dottorrent::file_...
function print_simple_indicator_v2 (line 222) | void print_simple_indicator_v2(std::ostream& os, const dottorrent::file_...
FILE: src/info.cpp
function run_info_app (line 43) | void run_info_app(const main_app_options& main_options, const info_app_o...
function configure_info_app (line 67) | void configure_info_app(CLI::App* app, info_app_options& options)
function format_multiline (line 95) | auto format_multiline(std::string_view key,
function format_indented_list (line 116) | std::string format_indented_list(
function create_general_info (line 139) | void create_general_info(std::ostream& os,
function format_announces (line 274) | void format_announces(std::ostream& os, const dottorrent::metafile& meta...
function create_raw_info (line 315) | void create_raw_info(std::ostream& os, const fs::path& metafile_path, bo...
FILE: src/ls_colors.cpp
type detail (line 5) | namespace detail {
function parse_emphasis (line 7) | constexpr tc::emphasis parse_emphasis(std::uint8_t graphics_attribute)
function parse_color (line 28) | inline std::pair<tc::text_style, std::size_t>
function parse_rgb_color_component (line 101) | inline std::pair<tc::rgb_color, std::size_t>
function parse_ls_colors (line 142) | inline std::map<std::string, termcontrol::text_style>
FILE: src/magnet.cpp
function configure_magnet_app (line 9) | void configure_magnet_app(CLI::App* app, magnet_app_options& options)
function run_magnet_app (line 30) | void run_magnet_app(const main_app_options& main_options, const magnet_a...
FILE: src/main.cpp
function main (line 22) | int main(int argc, char** argv) {
FILE: src/main_app.cpp
function setup_console (line 16) | void setup_console()
function list_available_checksums (line 31) | void list_available_checksums()
function print_version (line 42) | void print_version()
function configure_main_app (line 53) | void configure_main_app(CLI::App* app, main_app_options& options)
FILE: src/pad.cpp
function configure_pad_app (line 10) | void configure_pad_app(CLI::App* app, pad_app_options& options)
function run_pad_app (line 30) | void run_pad_app(const main_app_options& main_options, const pad_app_opt...
FILE: src/profile.cpp
type torrenttools (line 7) | namespace torrenttools {
function profile (line 58) | profile parse_create_profile(const YAML::Node& profile_data)
function profile (line 292) | profile parse_edit_profile(const YAML::Node& profile_data)
FILE: src/progress.cpp
function run_with_progress (line 38) | void run_with_progress(std::ostream& os, dottorrent::storage_hasher& has...
function run_with_simple_progress (line 100) | void run_with_simple_progress(std::ostream& os, dottorrent::storage_hash...
function run_with_progress (line 153) | void run_with_progress(std::ostream& os, dottorrent::storage_verifier& v...
function run_with_simple_progress (line 215) | void run_with_simple_progress(std::ostream& os, dottorrent::storage_veri...
function print_completion_statistics (line 269) | void print_completion_statistics(std::ostream& os, const dottorrent::met...
FILE: src/show.cpp
function configure_show_app (line 27) | void configure_show_app(CLI::App* app, show_app_options& options)
function configure_show_common (line 99) | void configure_show_common(CLI::App* subapp, show_app_options& options)
function configure_show_announce_subapp (line 111) | void configure_show_announce_subapp(CLI::App* announce_subapp, show_app_...
function configure_show_protocol_subapp (line 121) | void configure_show_protocol_subapp(CLI::App* protocol_app, show_app_opt...
function configure_show_infohash_subapp (line 127) | void configure_show_infohash_subapp(CLI::App* infohash_app, show_app_opt...
function configure_show_piece_count_subapp (line 148) | void configure_show_piece_count_subapp(CLI::App* piece_size_app, show_ap...
function configure_show_piece_size_subapp (line 153) | void configure_show_piece_size_subapp(CLI::App* piece_size_app, show_app...
function configure_show_created_by_subapp (line 162) | void configure_show_created_by_subapp(CLI::App* created_by_subapp, show_...
function configure_show_creation_date_subapp (line 167) | void configure_show_creation_date_subapp(CLI::App* creation_date_subapp,...
function configure_show_private_subapp (line 175) | void configure_show_private_subapp(CLI::App* private_subapp, show_app_op...
function configure_show_name_subapp (line 181) | void configure_show_name_subapp(CLI::App* name_subapp, show_app_options&...
function configure_show_comment_subapp (line 187) | void configure_show_comment_subapp(CLI::App* creation_date_subapp, show_...
function configure_show_source_subapp (line 192) | void configure_show_source_subapp(CLI::App* source_subapp, show_app_opti...
function configure_show_query_subapp (line 197) | void configure_show_query_subapp(CLI::App* query_subapp, show_app_option...
function configure_show_file_size_subapp (line 211) | void configure_show_file_size_subapp(CLI::App* file_size_subapp, show_ap...
function configure_show_files_subapp (line 220) | void configure_show_files_subapp(CLI::App* files_subapp, show_app_option...
function configure_web_seeds_subapp (line 233) | void configure_web_seeds_subapp(CLI::App* web_seeds_subapp, show_app_opt...
function configure_http_seeds_subapp (line 238) | void configure_http_seeds_subapp(CLI::App* http_seeds_subapp, show_app_o...
function configure_dht_nodes_subapp (line 243) | void configure_dht_nodes_subapp(CLI::App* dht_nodes_subapp, show_app_opt...
function configure_similar_torrents_subapp (line 248) | void configure_similar_torrents_subapp(CLI::App* similar_torrents_subapp...
function configure_collection_subapp (line 253) | void configure_collection_subapp(CLI::App* similar_torrents_subapp, show...
function configure_checksum_subapp (line 258) | void configure_checksum_subapp(CLI::App* checksum_subapp, show_app_optio...
function run_show_app (line 276) | void run_show_app(CLI::App* show_app, const main_app_options& main_optio...
function run_show_protocol_subapp (line 312) | void run_show_protocol_subapp(const main_app_options& main_options, cons...
function run_show_announce_subapp (line 325) | void run_show_announce_subapp(const main_app_options& main_options, cons...
function run_show_piece_count_subapp (line 350) | void run_show_piece_count_subapp(const main_app_options& main_options, c...
function run_show_piece_size_subapp (line 356) | void run_show_piece_size_subapp(const main_app_options& main_options, co...
function run_show_infohash_subapp (line 366) | void run_show_infohash_subapp(const main_app_options& main_options, cons...
function run_show_created_by_subapp (line 425) | void run_show_created_by_subapp(const main_app_options& main_options, co...
function run_show_creation_date_subapp (line 431) | void run_show_creation_date_subapp(const main_app_options& main_options,...
function run_show_private_subapp (line 446) | void run_show_private_subapp(const main_app_options& main_options, const...
function run_show_name_subapp (line 452) | void run_show_name_subapp(const main_app_options& main_options, const sh...
function run_show_comment_subapp (line 458) | void run_show_comment_subapp(const main_app_options& main_options, const...
function run_show_source_subapp (line 464) | void run_show_source_subapp(const main_app_options& main_options, const ...
function run_show_file_size_subapp (line 470) | void run_show_file_size_subapp(const main_app_options& main_options, con...
function run_show_query_subapp (line 481) | void run_show_query_subapp(const main_app_options& main_options, const s...
function run_show_files_subapp (line 510) | void run_show_files_subapp(const main_app_options& main_options, const s...
function run_show_web_seeds_subapp (line 526) | void run_show_web_seeds_subapp(const main_app_options& main_options, con...
function run_show_http_seeds_subapp (line 534) | void run_show_http_seeds_subapp(const main_app_options& main_options, co...
function run_show_dht_nodes_subapp (line 542) | void run_show_dht_nodes_subapp(const main_app_options& main_options, con...
function run_show_similar_torrents_subapp (line 550) | void run_show_similar_torrents_subapp(const main_app_options& main_optio...
function run_show_collection_subapp (line 567) | void run_show_collection_subapp(const main_app_options& main_options, co...
function run_show_checksum_subapp (line 575) | void run_show_checksum_subapp(const main_app_options& main_options, cons...
FILE: src/tracker_database.cpp
type torrenttools (line 14) | namespace torrenttools {
function tracker (line 141) | const tracker& tracker_database::at(std::string_view key) const
function tracker_database (line 194) | tracker_database* load_tracker_database()
function tracker_database (line 232) | tracker_database* load_tracker_database(const fs::path& custom_path)
FILE: src/tree_view.cpp
function format_file_tree (line 134) | std::string format_file_tree(const dottorrent::metafile& m, std::string_...
function format_verify_file_tree (line 160) | std::string format_verify_file_tree(
function format_file_stats (line 222) | std::string format_file_stats(const dottorrent::metafile& m, std::string...
function format_announce_tree (line 259) | std::string format_announce_tree(const dottorrent::announce_url_list& e,...
FILE: src/verify.cpp
function configure_verify_app (line 16) | void configure_verify_app(CLI::App* app, verify_app_options& options)
function run_verify_app (line 53) | void run_verify_app(const main_app_options& main_options, const verify_a...
function print_verify_statistics (line 110) | void print_verify_statistics(const dottorrent::metafile& m, std::chrono:...
FILE: tests/test_file_matcher.cpp
function contains (line 8) | bool contains(std::vector<fs::path> v, const fs::path& path)
FILE: tests/test_resources.hpp
type cout_redirect (line 25) | struct cout_redirect {
method cout_redirect (line 26) | cout_redirect( std::streambuf * new_buffer )
type temporary_directory (line 39) | struct temporary_directory {
method temporary_directory (line 40) | temporary_directory()
method create_temporary_directory (line 58) | static fs::path create_temporary_directory(unsigned long long max_trie...
Copy disabled (too large)
Download .json
Condensed preview — 177 files, each showing path, character count, and a content snippet. Download the .json file for the full structured content (11,680K chars).
[
{
"path": ".dockerignore",
"chars": 57,
"preview": ".github/\n.vscode/\ncmake-build-*/\nDockerfile\n.dockerignore"
},
{
"path": ".github/FUNDING.yml",
"chars": 63,
"preview": "# These are supported funding model platforms\n\ngithub: fbdtemme"
},
{
"path": ".github/workflows/documentation.yml",
"chars": 949,
"preview": "name: Documentation\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n runs-"
},
{
"path": ".github/workflows/linux.yml",
"chars": 1509,
"preview": "name: Linux\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n name: Build\n "
},
{
"path": ".github/workflows/macos.yml",
"chars": 1888,
"preview": "name: macOS\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n name: Build\n "
},
{
"path": ".github/workflows/package.yml",
"chars": 9733,
"preview": "name: Package\n\non:\n workflow_dispatch:\n branches: [ main, develop ]\n inputs:\n linux:\n description: 'C"
},
{
"path": ".github/workflows/windows.yml",
"chars": 2085,
"preview": "name: Windows\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n name: Build"
},
{
"path": ".gitignore",
"chars": 66,
"preview": "venv/**\n**/.idea/**\n**/.vscode/**\n**/cmake-build-*/**\n**/.DS_Store"
},
{
"path": "CHANGELOG.md",
"chars": 4612,
"preview": "# Changelog\nAll notable changes to this project will be documented in this file.\nThis project adheres to [Semantic Versi"
},
{
"path": "CMakeLists.txt",
"chars": 8845,
"preview": "cmake_minimum_required(VERSION 3.15)\n\n# Version string\ncmake_policy(SET CMP0048 NEW)\ncmake_policy(SET CMP0077 NEW)\n\nif ("
},
{
"path": "Dockerfile",
"chars": 1066,
"preview": "FROM alpine:latest AS build-stage\n\nRUN apk add --update-cache \\\n git \\\n make \\\n cmake \\\n autoconf \\\n auto"
},
{
"path": "LICENSE",
"chars": 1077,
"preview": "MIT License\n\nCopyright (c) 2021 Florian De Temmerman\n\nPermission is hereby granted, free of charge, to any person obtain"
},
{
"path": "README.md",
"chars": 8155,
"preview": "\n\n\n{\n target=\"$"
},
{
"path": "cmake/FindISALCrypto.cmake",
"chars": 3307,
"preview": "#.rst:\n# FindISALCrypto\n# -----------\n#\n# Find the isal-l_crypto library.\n#\n# IMPORTED Targets\n# ^^^^^^^^^^^^^^^^\n#\n# Th"
},
{
"path": "cmake/FindNASM.cmake",
"chars": 1834,
"preview": "include(FindPackageHandleStandardArgs)\n\nfind_program(NASM_EXECUTABLE NAMES nasm yasm DOC \"Path to NASM/YASM executable\")"
},
{
"path": "cmake/FindSphinx.cmake",
"chars": 1133,
"preview": "include(FindPackageHandleStandardArgs)\n\n#Look for an executable called sphinx-build\nfind_program(SPHINX_EXECUTABLE\n "
},
{
"path": "cmake/FindTBB.cmake",
"chars": 17173,
"preview": "# - Find ThreadingBuildingBlocks include dirs and libraries\n# Use this module by invoking find_package with the form:\n# "
},
{
"path": "cmake/SanitizersConfig.cmake",
"chars": 2286,
"preview": "# Build Types\nset(CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}\n CACHE STRING \"Choose the type of build, options are: None"
},
{
"path": "docs/CMakeLists.txt",
"chars": 1726,
"preview": "include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/FindSphinx.cmake)\nfind_package(Sphinx REQUIRED)\n\n#This will be the main out"
},
{
"path": "docs/bep-support.csv",
"chars": 1368,
"preview": "BEP, Status, Title\n`03 <http://bittorrent.org/beps/bep_0003.html>`_,✅,The BitTorrent Protocol Specification\n`05 <http://"
},
{
"path": "docs/commands/create.rst",
"chars": 9433,
"preview": ".. _create_command:\n\nCreate\n======\n\nThe create command is used to create new BitTorrent metafiles.\n\nThe basic invocation"
},
{
"path": "docs/commands/edit.rst",
"chars": 6337,
"preview": ".. _edit_command:\n\nEdit\n=====\n\nThe edit commands is used to modify metadata fields in an existing bittorrent file.\nMany "
},
{
"path": "docs/commands/info.rst",
"chars": 11120,
"preview": ".. _info_command:\n\nInfo\n======\n\nThe info command is used to print an overview of BitTorrent metafiles features.\n\nThe bas"
},
{
"path": "docs/commands/magnet.rst",
"chars": 729,
"preview": ".. _magnet_command:\n\nMagnet\n======\n\n.. code-block:: none\n\n Usage: torrenttools magnet [OPTIONS] metafile\n\n Positio"
},
{
"path": "docs/commands/pad.rst",
"chars": 926,
"preview": ".. _pad_command:\n\nPad\n======\n\nThe pad command is used to generate padding files for BitTorrent metafiles that contain th"
},
{
"path": "docs/commands/show.rst",
"chars": 1379,
"preview": ".. _show_command:\n\nShow\n=====\n\nOverview\n---------\n.. code-block:: none\n\n Show specific fields of bittorrent metafiles"
},
{
"path": "docs/commands/verify.rst",
"chars": 652,
"preview": ".. _verify_command:\n\nVerify\n=======\n\nOverview\n---------\n\n.. code-block:: none\n\n Verify local data against bittorrent "
},
{
"path": "docs/comparison.rst",
"chars": 1223,
"preview": "Other metafile utilities\n=========================\n\nMultiple other BitTorrent metafile utilities exist.\nThis feature tab"
},
{
"path": "docs/conf.py.in",
"chars": 500,
"preview": "# The suffix of source filenames.\nsource_suffix = '.rst'\n\n# The encoding of source files.\nsource_encoding = 'utf-8'\n\n# G"
},
{
"path": "docs/configuration.rst",
"chars": 5602,
"preview": "Configuration\n+++++++++++++\n\nConfiguration files\n===================\n\nThere are two places for configuration: one that i"
},
{
"path": "docs/index.rst",
"chars": 625,
"preview": "torrenttools\n============\n\nA commandline tool for creating, inspecting and modifying bittorrent metafiles.\n\nSource code "
},
{
"path": "docs/topics/bencode.rst",
"chars": 2173,
"preview": "Bencode format\n==============\n\nIntroduction\n------------\n\nBencode is a simple encoding developed for BitTorrent.\nIt supp"
},
{
"path": "docs/topics/bittorrent-metafile-v1.rst",
"chars": 6768,
"preview": "BitTorrent metafile v1\n=======================\n\nIntroduction\n-------------\n\nMetainfo files (also known as .torrent files"
},
{
"path": "docs/topics/glossary.rst",
"chars": 3425,
"preview": "Glossary\n========\n\n* announce:\n The act of telling a tracker or the DHT network about the existence of oneself and ho"
},
{
"path": "docs/why-torrenttools.rst",
"chars": 1440,
"preview": "Features\n========\n\n* **Multiple subcommands**:\n Torrenttools has multiple subcommands to satisfy all kinds of BitTorr"
},
{
"path": "external/CLI11.cmake",
"chars": 796,
"preview": "if (TARGET CLI11::CLI11)\n log_target_found(CLI11)\n return()\nendif()\n\nfind_package(CLI11 QUIET)\nif (CLI11_FOUND)\n "
},
{
"path": "external/Catch2.cmake",
"chars": 932,
"preview": "if (TARGET Catch2::Catch2)\n log_target_found(Catch2)\n return()\nendif()\n\nfind_package(Catch2 QUIET)\nif (Catch2_FOUN"
},
{
"path": "external/bencode.cmake",
"chars": 870,
"preview": "if (TARGET bencode::bencode)\n log_target_found(bencode)\n return()\nendif()\n\nfind_package(bencode QUIET)\nif (bencode"
},
{
"path": "external/cliprogress.cmake",
"chars": 839,
"preview": "if (TARGET cliprogress::cliprogress)\n log_target_found(cliprogress)\n return()\nendif()\n\nfind_package(cliprogress QU"
},
{
"path": "external/ctre.cmake",
"chars": 796,
"preview": "if (TARGET ctre::ctre)\n log_target_found(ctre)\n return()\nendif()\n\nfind_package(ctre QUIET)\nif (ctre_FOUND)\n log"
},
{
"path": "external/date.cmake",
"chars": 719,
"preview": "if (TARGET date::date)\n log_target_found(date)\n return()\nendif()\n\nfind_package(date QUIET)\nif (date_FOUND)\n log"
},
{
"path": "external/dottorrent.cmake",
"chars": 838,
"preview": "if (TARGET dottorrent::dottorrent)\n log_target_found(dottorrent)\n return()\nendif()\n\nfind_package(dottorrent QUIET)"
},
{
"path": "external/expected-lite.cmake",
"chars": 829,
"preview": "if (TARGET nonstd::expected-lite)\n log_target_found(expected-lite)\n return()\nendif()\n\nfind_package(expected-lite Q"
},
{
"path": "external/external.cmake",
"chars": 1804,
"preview": "cmake_minimum_required(VERSION 3.14)\n\ninclude(FetchContent)\n\nfunction(log_target_found library)\n message(STATUS \"Targ"
},
{
"path": "external/fmt.cmake",
"chars": 719,
"preview": "if (TARGET fmt::fmt)\n log_target_found(fmt)\n return()\nendif()\n\n\nfind_package(fmt 8.0.0 QUIET)\nif (fmt_FOUND)\n l"
},
{
"path": "external/gsl-lite.cmake",
"chars": 746,
"preview": "if (TARGET gsl::gsl-lite-v1)\n log_target_found(gsl-lite)\n return()\nendif()\n\nfind_package(gsl-lite QUIET)\nif (gsl-l"
},
{
"path": "external/isa-l_crypto.cmake",
"chars": 4715,
"preview": "if (TARGET ISAL::Crypto)\n log_target_found(ISAL::Crypto)\n return()\nendif()\n\nfind_package(ISALCrypto QUIET)\nif (ISA"
},
{
"path": "external/nlohmann_json.cmake",
"chars": 909,
"preview": "if (TARGET nlohmann_json::nlohmann_json)\n log_target_found(nlohmann_json)\n return()\nendif()\n\nfind_package(nlohmann"
},
{
"path": "external/re2.cmake",
"chars": 810,
"preview": "if (TARGET re2::re2)\n log_target_found(re2)\n return()\nendif()\n\nfind_package(re2 QUIET)\nif (re2_FOUND)\n log_modu"
},
{
"path": "external/sigslot.cmake",
"chars": 685,
"preview": "if (TARGET Pal::Sigslot)\n log_target_found(PalSigslot)\n return()\nendif()\n\nfind_package(PalSigslot QUIET)\nif (PalSi"
},
{
"path": "external/termcontrol.cmake",
"chars": 865,
"preview": "if (TARGET termcontrol::termcontrol)\n log_target_found(termcontrol)\n return()\nendif()\n\nfind_package(termcontrol QU"
},
{
"path": "external/yaml-cpp.cmake",
"chars": 914,
"preview": "if (TARGET yaml-cpp)\n log_target_found(yaml-cpp)\n return()\nendif()\n\nfind_package(yaml-cpp QUIET)\nif (yaml-cpp_FOUN"
},
{
"path": "include/app_data.hpp",
"chars": 253,
"preview": "#pragma once\n\n#include <filesystem>\n#include <vector>\n\n#include \"config.hpp\"\n\nnamespace fs = std::filesystem;\n\n/// Get t"
},
{
"path": "include/argument_parsers.hpp",
"chars": 2398,
"preview": "#pragma once\n#include <string>\n#include <vector>\n#include <optional>\n#include <chrono>\n#include <unordered_set>\n\n#includ"
},
{
"path": "include/cli_helpers.hpp",
"chars": 439,
"preview": "#pragma once\n\n#include <filesystem>\n\nnamespace fs = std::filesystem;\n\n\ninline void verify_metafile(const fs::path& metaf"
},
{
"path": "include/common.hpp",
"chars": 1085,
"preview": "#pragma once\n\n#include <vector>\n#include <string>\n#include <filesystem>\n\n#include <dottorrent/metafile.hpp>\n#include \"tr"
},
{
"path": "include/config.hpp.in",
"chars": 529,
"preview": "#pragma once\n#define PROJECT_NAME \"@PROJECT_NAME@\"\n#define PROJECT_VERSION_MAJOR @PROJECT_VERSION_MAJOR@\n#def"
},
{
"path": "include/config_parser.hpp",
"chars": 1736,
"preview": "#pragma once\n\n#include <filesystem>\n#include <string_view>\n#include <string>\n#include <memory>\n#include <map>\n#include <"
},
{
"path": "include/create.hpp",
"chars": 2512,
"preview": "#pragma once\n#include <string>\n#include <vector>\n#include <optional>\n#include <cstdint>\n#include <filesystem>\n#include <"
},
{
"path": "include/edit.hpp",
"chars": 2386,
"preview": "#pragma once\n\n#include <filesystem>\n#include <dottorrent/general.hpp>\n#include <dottorrent/dht_node.hpp>\n#include <dotto"
},
{
"path": "include/escape_binary_fields.hpp",
"chars": 306,
"preview": "#pragma once\n\n#include <bencode/bencode.hpp>\n#include <dottorrent/metafile.hpp>\n\nnamespace bc = bencode;\nnamespace dt = "
},
{
"path": "include/exceptions.hpp",
"chars": 245,
"preview": "#pragma once\n\nnamespace torrenttools\n{\n\nclass config_error : public std::invalid_argument\n{\npublic:\n using invalid_ar"
},
{
"path": "include/file_matcher.hpp",
"chars": 6748,
"preview": "#pragma once\n#include <filesystem>\n#include <unordered_set>\n#include <set>\n#include <atomic>\n#include <thread>\n\n#include"
},
{
"path": "include/formatters.hpp",
"chars": 1571,
"preview": "#pragma once\n#include <cmath>\n#include <string>\n#include <chrono>\n#include <fmt/format.h>\n\n#include <dottorrent/general."
},
{
"path": "include/help_formatter.hpp",
"chars": 568,
"preview": "#pragma once\n\n#include <CLI/Formatter.hpp>\n\n\nclass help_formatter : public CLI::Formatter {\npublic:\n std::string make"
},
{
"path": "include/indicator.hpp",
"chars": 3554,
"preview": "#pragma once\n\n#include <memory>\n#include <ranges>\n#include <string>\n#include <string_view>\n\n#include <cliprogressbar/eve"
},
{
"path": "include/info.hpp",
"chars": 2157,
"preview": "#pragma once\n#include <string_view>\n#include <filesystem>\n#include <string>\n#include <chrono>\n\n#include <dottorrent/meta"
},
{
"path": "include/list_edit_mode.hpp",
"chars": 104,
"preview": "#pragma once\n\nnamespace torrenttools {\n\nenum list_edit_mode\n{\n replace,\n append,\n prepend\n};\n\n}"
},
{
"path": "include/ls_colors.hpp",
"chars": 1620,
"preview": "#pragma once\n\n#include <cstdlib>\n#include <array>\n#include <string>\n#include <type_traits>\n#include <string_view>\n#inclu"
},
{
"path": "include/magnet.hpp",
"chars": 577,
"preview": "#pragma once\n\n#include <string>\n#include <vector>\n#include <optional>\n#include <cstdint>\n#include <filesystem>\n#include "
},
{
"path": "include/main_app.hpp",
"chars": 207,
"preview": "#pragma once\n\n#include <CLI/App.hpp>\n\n#include \"common.hpp\"\n\nvoid setup_console();\n\nvoid list_available_checksums();\n\nvo"
},
{
"path": "include/natural_sort.hpp",
"chars": 8294,
"preview": "/*\n\tThe MIT License (MIT)\n\tCopyright (c) 2016 Gagan Kumar(scopeInfinity)\n\tComplete License at https://raw.githubusercont"
},
{
"path": "include/pad.hpp",
"chars": 624,
"preview": "#pragma once\n#include <string>\n#include <vector>\n#include <optional>\n#include <cstdint>\n#include <filesystem>\n#include <"
},
{
"path": "include/profile.hpp",
"chars": 466,
"preview": "#pragma once\n\n#include <string>\n#include <vector>\n#include <variant>\n#include <map>\n\n#include <yaml-cpp/yaml.h>\n\n#includ"
},
{
"path": "include/profile_config_formatter.hpp",
"chars": 424,
"preview": "#pragma once\n\n#include <CLI/Config.hpp>\n\nclass profile_config_formatter : public CLI::Config\n{\n std::string to_config"
},
{
"path": "include/progress.hpp",
"chars": 747,
"preview": "#pragma once\n\n#include <ostream>\n\n#include <dottorrent/metafile.hpp>\n#include <dottorrent/storage_hasher.hpp>\n#include <"
},
{
"path": "include/show.hpp",
"chars": 4836,
"preview": "#pragma once\n\n#include <filesystem>\n#include <dottorrent/general.hpp>\n\n#include \"common.hpp\"\n\n// Forward declarations\nna"
},
{
"path": "include/tracker_database.hpp",
"chars": 2628,
"preview": "#pragma once\n#include <filesystem>\n\n#include <vector>\n#include <string>\n#include <fstream>\n#include <ranges>\n\n#include <"
},
{
"path": "include/tree_view.hpp",
"chars": 8177,
"preview": "#pragma once\n\n#include <string>\n#include <string_view>\n#include <algorithm>\n#include <filesystem>\n#include <iostream>\n#i"
},
{
"path": "include/utils.hpp",
"chars": 961,
"preview": "#include <algorithm>\n#include <cctype>\n#include <locale>\n#include <string>\n\nnamespace torrenttools::detail {\n\n// trim fr"
},
{
"path": "include/verify.hpp",
"chars": 763,
"preview": "#pragma once\n#include <string_view>\n#include <string>\n#include <chrono>\n#include <filesystem>\n\n#include <dottorrent/meta"
},
{
"path": "packages/appimage/build_appimage.sh",
"chars": 634,
"preview": "#!/usr/bin/env bash\n#\nSOURCE_DIR=$(realpath ${1:-$PWD})\nAPPDIR=$SOURCE_DIR/packages/appimage/AppDir\nBUILD_DIR=\"$SOURCE_D"
},
{
"path": "packages/appimage/torrenttools-appimage-recipe.yml",
"chars": 1713,
"preview": "version: 1\n\n#script:\n # - cmake --install $BINDIR --prefix \"$APPDIR/usr\" --component torrenttools\n # - mkdir -p $APP"
},
{
"path": "packages/appimage/torrenttools.desktop",
"chars": 205,
"preview": "[Desktop Entry]\nType=Application\nName=torrenttools\nComment=Commandline tool for inspecting, creating and editing BitTorr"
},
{
"path": "packages/arch/PKGBUILD",
"chars": 1204,
"preview": "# Maintainer: Florian De Temmerman <floriandetemmerman@gmail.com>\npkgname=torrenttools\npkgver=0.6.2\npkgrel=1\npkgdesc=\"Co"
},
{
"path": "packages/cpack_dispatch.cmake",
"chars": 216,
"preview": "if (CPACK_GENERATOR MATCHES \"WIX\")\n include(${CMAKE_CURRENT_LIST_DIR}/windows-wix.cmake)\nendif()\nif (CPACK_GENERATOR "
},
{
"path": "packages/debian/changelog",
"chars": 867,
"preview": "torrenttools (0.6.2-1) unstable; urgency=medium\n\n * Update to 0.6.2\n\ntorrenttools (0.6.1-1) unstable; urgency=medium\n\n "
},
{
"path": "packages/debian/compat",
"chars": 3,
"preview": "12\n"
},
{
"path": "packages/debian/control",
"chars": 519,
"preview": "Source: torrenttools\nPriority: optional\nSection: net\nMaintainer: Florian De Temmerman <floriandetemmerman@gmail.com>\nBui"
},
{
"path": "packages/debian/copyright",
"chars": 1337,
"preview": "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/\nUpstream-Name: torrenttools\nUpstream-Contact:"
},
{
"path": "packages/debian/rules",
"chars": 908,
"preview": "#!/usr/bin/make -f\n# You must remove unused comment lines for the released package.\n#export DH_VERBOSE = 1\n#export DEB_B"
},
{
"path": "packages/debian/source/format",
"chars": 12,
"preview": "3.0 (quilt)\n"
},
{
"path": "packages/macos-productbuild.cmake",
"chars": 771,
"preview": "set(CPACK_PACKAGING_INSTALL_PREFIX \"/Library/torrenttools\")\nmessage(STATUS \"Setting prefix to /Library/torrenttools\")\n\ns"
},
{
"path": "packages/package_summary.txt",
"chars": 153,
"preview": "Torrenttools\n\nTorrenttools is a commandline application to create, inspect and edit BitTorrent Metafiles.\nIt supports th"
},
{
"path": "packages/packages.cmake",
"chars": 3900,
"preview": "if (APPLE)\n set(CPACK_GENERATOR productbuild)\nelseif (WIN32 OR MINGW)\n set(CPACK_GENERATO"
},
{
"path": "packages/productbuild/postflight.sh",
"chars": 220,
"preview": "#!/bin/zsh\n\n# Create symlink o torrenttools executable in PATH \n\nif [ -f /usr/local/bin/torrenttools ]; then\n rm /usr"
},
{
"path": "packages/rpm/torrenttools.spec",
"chars": 3995,
"preview": "%global tag 0.6.2\n\nName: torrenttools\nVersion: %{tag}\nURL: https://www.github.com/fb"
},
{
"path": "packages/ubuntu/20.04/changelog",
"chars": 1400,
"preview": "torrenttools (0.6.2-1~ubuntu20.04.2) focal; urgency=medium\n\n * Update to 0.6.2\n\n -- Florian De Temmerman <floriandetemm"
},
{
"path": "packages/ubuntu/21.04/changelog",
"chars": 1400,
"preview": "torrenttools (0.6.2-1~ubuntu21.04) hirsute; urgency=medium\n\n * Update to 0.6.2\n\n -- Florian De Temmerman <floriandetemm"
},
{
"path": "packages/windows-wix.cmake",
"chars": 698,
"preview": "set(CPACK_WIX_PRODUCT_GUID \"ECB15625-7F24-41F1-8287-E5F7AE9D233E\")\nset(CPACK_WIX_UPGRADE_GUID \"E7E112B4-2A91-4E82-BBF8"
},
{
"path": "packages/wix/broadcast_env_change.xml",
"chars": 215,
"preview": "<CPackWiXPatch>\n <CPackWiXFragment Id=\"#PRODUCT\">\n <CustomActionRef Id=\"WixBroadcastSettingChange\" />\n "
},
{
"path": "packages/wix/copy-config.xml",
"chars": 590,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n<CPackWiXPatch>\n <CPackWiXFragment Id=\"CM_FP_torrenttools.config.yml\">\n "
},
{
"path": "packages/wix/create-localappdata-folder.wxs",
"chars": 373,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Wix xmlns=\"http://schemas.microsoft.com/wix/2006/wi\">\n <Fragment>\n <Di"
},
{
"path": "packages/wix/disable_feature_advertise.xml",
"chars": 99,
"preview": "<CPackWiXPatch>\n <CPackWiXFragment Id=\"CM_C_torrenttools\" AllowAdvertise=\"no\"/>\n</CPackWiXPatch>"
},
{
"path": "packages/wix/update_path.xml",
"chars": 243,
"preview": "<CPackWiXPatch>\n <CPackWiXFragment Id=\"CM_CP_torrenttools.torrenttools.exe\">\n <Environment Id=\"PATH\" Name=\"PAT"
},
{
"path": "resources/config.yml",
"chars": 1698,
"preview": "# This is an example configuration file.\n# It should be copied to the suitable directory for your OS and modified there."
},
{
"path": "resources/trackers.json",
"chars": 2309,
"preview": "[\n {\n \"name\": \"AlphaRatio\",\n \"abbreviation\": \"AR\",\n \"announce_url\": \"http://tracker.alpharatio.cc:2710/{pid}/a"
},
{
"path": "scripts/fetch_dependencies.sh",
"chars": 1511,
"preview": "#!/bin/env bash\n\nfunction nest {\n repo_url=\"$1\"\n branch=\"$2\"\n destination_name=\"$3\"\n\n repo_name_plus_git=$(basename "
},
{
"path": "src/app_data.cpp",
"chars": 902,
"preview": "#include \"app_data.hpp\"\n\nfs::path get_user_data_dir()\n{\n fs::path home_dir;\n\n#if defined(__linux__)\n char* r = std"
},
{
"path": "src/argument_parsers.cpp",
"chars": 16930,
"preview": "#include <ranges>\n#include <bit>\n#include <algorithm>\n#include <functional>\n#include <charconv>\n#include <unordered_set>"
},
{
"path": "src/common.cpp",
"chars": 6999,
"preview": "#include <ranges>\n\n#include <gsl-lite/gsl-lite.hpp>\n#include \"common.hpp\"\n#include \"config_parser.hpp\"\n\nnamespace rng = "
},
{
"path": "src/config_parser.cpp",
"chars": 7326,
"preview": "\n#include <fstream>\n#include <string>\n#include <string_view>\n#include <filesystem>\n#include <stdexcept>\n\n#include <fmt/f"
},
{
"path": "src/create.cpp",
"chars": 22895,
"preview": "\n#include <algorithm>\n#include <functional>\n#include <vector>\n#include <string>\n#include <ranges>\n#include <optional>\n#i"
},
{
"path": "src/edit.cpp",
"chars": 19716,
"preview": "#include <filesystem>\n#include <ranges>\n\n#include <CLI/CLI.hpp>\n#include <dottorrent/metafile.hpp>\n\n#include \"argument_p"
},
{
"path": "src/escape_binary_fields.cpp",
"chars": 5768,
"preview": "#include \"escape_binary_fields.hpp\"\n#include <dottorrent/hex.hpp>\n#include <bencode/traits/span.hpp>\n\n\nbc::bvalue escape"
},
{
"path": "src/formatters.cpp",
"chars": 2976,
"preview": "#include \"formatters.hpp\"\n\nnamespace torrenttools {\n\n\nstd::string format_si_prefix(double value, std::string_view unit, "
},
{
"path": "src/indicator.cpp",
"chars": 7965,
"preview": "#include <memory>\n#include <ranges>\n\n#include <fmt/format.h>\n\n#include <cliprogressbar/progress_indicator.hpp>\n#include "
},
{
"path": "src/info.cpp",
"chars": 11786,
"preview": "#include <string_view>\n\n#include <fmt/format.h>\n#include <fmt/chrono.h>\n\n#include <filesystem>\n#include <string>\n#includ"
},
{
"path": "src/ls_colors.cpp",
"chars": 9041,
"preview": "//\n// Created by fbdtemme on 7/31/21.\n#include \"ls_colors.hpp\"\n\nnamespace detail {\n\nconstexpr tc::emphasis parse_emphasi"
},
{
"path": "src/magnet.cpp",
"chars": 1279,
"preview": "#include <dottorrent/magnet_uri.hpp>\n\n#include \"argument_parsers.hpp\"\n#include \"magnet.hpp\"\n#include \"cli_helpers.hpp\"\n\n"
},
{
"path": "src/main.cpp",
"chars": 3676,
"preview": "#include <iostream>\n#include <fmt/format.h>\n\n#include \"config.hpp\"\n#include \"create.hpp\"\n#include \"edit.hpp\"\n#include \"i"
},
{
"path": "src/main_app.cpp",
"chars": 2395,
"preview": "#include <iostream>\n#include \"config.hpp\"\n#include \"show.hpp\"\n#include \"argument_parsers.hpp\"\n#include \"help_formatter.h"
},
{
"path": "src/pad.cpp",
"chars": 1367,
"preview": "#include <CLI/App.hpp>\n#include <dottorrent/metafile.hpp>\n\n#include \"pad.hpp\"\n#include \"argument_parsers.hpp\"\n#include \""
},
{
"path": "src/profile.cpp",
"chars": 15329,
"preview": "#include <string_view>\n\n#include \"profile.hpp\"\n#include \"exceptions.hpp\"\n#include \"utils.hpp\"\n\nnamespace torrenttools {\n"
},
{
"path": "src/progress.cpp",
"chars": 11474,
"preview": "#include <algorithm>\n#include <functional>\n#include <vector>\n#include <string>\n#include <memory>\n#include <memory>\n#incl"
},
{
"path": "src/show.cpp",
"chars": 23313,
"preview": "\n#include <filesystem>\n#include <chrono>\n#include <fstream>\n\n#include <date/date.h>\n#include <CLI/App.hpp>\n#include <dot"
},
{
"path": "src/tracker_database.cpp",
"chars": 8514,
"preview": "#include <span>\n#include <ranges>\n#include <vector>\n#include <stdexcept>\n\n#include <nlohmann/json.hpp>\n#include <fmt/for"
},
{
"path": "src/tree_view.cpp",
"chars": 9799,
"preview": "#include \"tree_view.hpp\"\n\ntree_printer::tree_printer(const dottorrent::metafile& m, std::string_view prefix, tree_option"
},
{
"path": "src/verify.cpp",
"chars": 3807,
"preview": "//\n// Created by fbdtemme on 3/24/20.\n//\n#include \"verify.hpp\"\n#include \"indicator.hpp\"\n#include \"ls_colors.hpp\"\n#includ"
},
{
"path": "tests/CMakeLists.txt",
"chars": 1617,
"preview": "cmake_minimum_required(VERSION 3.11)\n\nadd_executable(torrenttools-tests test_profile.cpp)\n\nmessage(STATUS ${CMAKE_MODULE"
},
{
"path": "tests/main.cpp",
"chars": 129,
"preview": "#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file\n#include <catch2/catch"
},
{
"path": "tests/private.torrent/test_file.txt.torrent",
"chars": 181,
"preview": "d7:comment20:Private tracker name10:created by18:torrenttools/0.1.413:creation datei1611504195e4:infod6:lengthi0e4:name1"
},
{
"path": "tests/resources/CAMELYON17.torrent",
"chars": 3859113,
"preview": "d8:announce41:https://academictorrents.com/announce.php13:announce-listll41:https://academictorrents.com/announce.phpel3"
},
{
"path": "tests/resources/RSNA_Pneumonia_Detection_Challenge.torrent",
"chars": 2847176,
"preview": "d8:announce41:https://academictorrents.com/announce.php13:announce-listll41:https://academictorrents.com/announce.phpel3"
},
{
"path": "tests/resources/collection.torrent",
"chars": 162,
"preview": "d11:collectionsl5:test25:test1e10:created by18:torrenttools/0.4.113:creation datei1622291018e4:infod6:lengthi0e4:name9:t"
},
{
"path": "tests/resources/config/config.yml",
"chars": 405,
"preview": "# This is an example configuration file.\n# It should be copied to the suitable directory for your OS and modified there."
},
{
"path": "tests/resources/config/trackers.json",
"chars": 155,
"preview": "[\n {\n \"name\": \"AlphaRatio\",\n \"abbreviation\": \"AR\",\n \"announce_url\": \"http://tracker.alpharatio.cc:2710/{pid}/a"
},
{
"path": "tests/resources/dht-node.torrent",
"chars": 178,
"preview": "d10:created by18:torrenttools/0.1.413:creation datei1611573375e4:infod6:lengthi0e4:name13:test_file.txt12:piece lengthi3"
},
{
"path": "tests/resources/http-seeds.torrent",
"chars": 176,
"preview": "d10:created by18:torrenttools/0.4.113:creation datei1622205540e9:httpseedsl28:http://test.url.com/httpseede4:infod6:leng"
},
{
"path": "tests/resources/lorem_ipsum.txt",
"chars": 2733,
"preview": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus molestie orci ante, id dapibus risus ultrices ut. Mauri"
},
{
"path": "tests/resources/private.torrent",
"chars": 163,
"preview": "d10:created by18:torrenttools/0.1.413:creation datei1611502456e4:infod6:lengthi0e4:name13:test_file.txt12:piece lengthi3"
},
{
"path": "tests/resources/similar-v1.torrent",
"chars": 155,
"preview": "d10:created by18:torrenttools/0.4.113:creation datei1622287512e4:infod6:lengthi0e4:name9:test_file12:piece lengthi32768e"
},
{
"path": "tests/resources/similar-v2.torrent",
"chars": 163,
"preview": "d10:created by18:torrenttools/0.4.113:creation datei1622287531e4:infod6:lengthi0e4:name9:test_file12:piece lengthi32768e"
},
{
"path": "tests/resources/test-torrent/dirA/fileA1",
"chars": 0,
"preview": ""
},
{
"path": "tests/resources/test-torrent/dirA/fileA2",
"chars": 0,
"preview": ""
},
{
"path": "tests/resources/test-torrent/dirB/fileB1",
"chars": 0,
"preview": ""
},
{
"path": "tests/resources/test-torrent/dirB/fileB2",
"chars": 0,
"preview": ""
},
{
"path": "tests/resources/test_file",
"chars": 0,
"preview": ""
},
{
"path": "tests/resources/tests.torrent",
"chars": 654,
"preview": "d8:announce4:test10:created by13:mktorrent 1.113:creation datei1582803359e4:infod5:filesld6:lengthi945e4:pathl14:CMakeLi"
},
{
"path": "tests/resources/tree_index_test.torrent",
"chars": 393,
"preview": "d10:created by13:mktorrent 1.113:creation datei1582820406e4:infod5:filesld6:lengthi0e4:pathl4:dir14:dir32:f3eed6:lengthi"
},
{
"path": "tests/resources/web-seed.torrent",
"chars": 181,
"preview": "d10:created by18:torrenttools/0.1.413:creation datei1611568605e4:infod6:lengthi0e4:name13:test_file.txt12:piece lengthi3"
},
{
"path": "tests/test_create.cpp",
"chars": 43986,
"preview": "\n#include <experimental/source_location>\n\n#include <catch2/catch.hpp>\n#include <fmt/format.h>\n#include <CLI/CLI.hpp>\n\n#i"
},
{
"path": "tests/test_edit.cpp",
"chars": 29963,
"preview": "#include <filesystem>\n#include <ranges>\n\n#include <experimental/source_location>\n\n#include <catch2/catch.hpp>\n#include <"
},
{
"path": "tests/test_file_matcher.cpp",
"chars": 3907,
"preview": "#include <catch2/catch.hpp>\n#include <filesystem>\n\n#include \"file_matcher.hpp\"\n\nnamespace fs = std::filesystem;\n\nbool co"
},
{
"path": "tests/test_info.cpp",
"chars": 1,
"preview": "\n"
},
{
"path": "tests/test_ls_colors.cpp",
"chars": 6517,
"preview": "\n#include <catch2/catch.hpp>\n#include \"ls_colors.hpp\"\n\nTEST_CASE(\"test parse_color\")\n{\n SECTION(\"terminal color - for"
},
{
"path": "tests/test_magnet.cpp",
"chars": 3888,
"preview": "\n#include <experimental/source_location>\n\n#include <catch2/catch.hpp>\n#include <fmt/format.h>\n#include <CLI/CLI.hpp>\n\n#i"
},
{
"path": "tests/test_main.cpp",
"chars": 1257,
"preview": "\n#include <experimental/source_location>\n\n#include <catch2/catch.hpp>\n#include <fmt/format.h>\n#include <CLI/CLI.hpp>\n\n#i"
},
{
"path": "tests/test_pad.cpp",
"chars": 1986,
"preview": "\n#include <experimental/source_location>\n\n#include <catch2/catch.hpp>\n#include <fmt/format.h>\n#include <CLI/CLI.hpp>\n\n#i"
},
{
"path": "tests/test_profile.cpp",
"chars": 22758,
"preview": "#include <filesystem>\n#include <string>\n#include <variant>\n\n#include <catch2/catch.hpp>\n#include <yaml-cpp/yaml.h>\n\n#inc"
},
{
"path": "tests/test_resources.hpp",
"chars": 2885,
"preview": "#include <filesystem>\n#include <exception>\n#include <fstream>\n#include <iostream>\n#include <random>\n#include <sstream>\n\n"
},
{
"path": "tests/test_show.cpp",
"chars": 19777,
"preview": "#include <experimental/source_location>\n#include <sstream>\n#include <ostream>\n\n\n#include <catch2/catch.hpp>\n#include <fm"
},
{
"path": "tests/test_tracker_database.cpp",
"chars": 1545,
"preview": "\n#include <catch2/catch.hpp>\n#include \"tracker_database.hpp\"\n\nTEST_CASE(\"test trackers\")\n{\n using namespace torrentto"
},
{
"path": "tests/test_tree_view.cpp",
"chars": 1938,
"preview": "//\n// Created by fbdtemme on 2/26/20.\n//\n#include <filesystem>\n#include <iostream>\n#include <fstream>\n\n\n#include <catch2"
},
{
"path": "tests/test_utils.cpp",
"chars": 191,
"preview": "#include <catch2/catch.hpp>\n#include <iostream>\n//#include <detail/format.hpp>\n\n#include \"ls_colors.hpp\"\n\nTEST_CASE(\"tes"
},
{
"path": "tests/test_verify.cpp",
"chars": 3941,
"preview": "\n#include <experimental/source_location>\n\n#include <catch2/catch.hpp>\n#include <fmt/format.h>\n#include <CLI/CLI.hpp>\n\n#i"
}
]
// ... and 8 more files (download for full content)
About this extraction
This page contains the full source code of the fbdtemme/torrenttools GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 177 files (7.1 MB), approximately 1.9M tokens, and a symbol index with 261 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.