Parallel random access to gzip files
Project description
Parallel Random Access Gzip (pragzip)
This module provides a PragzipFile class, which can be used to seek inside gzip files without having to decompress them first.
Alternatively, you can use this simply as a parallelized gzip decoder as a replacement for Python's builtin gzip
module in order to fully utilize all your cores.
The random seeking support is the same as provided by indexed_gzip but further speedups are realized at the cost of higher memory usage thanks to a least-recently-used cache in combination with a parallelized prefetcher.
Table of Contents
- Installation
- Usage
- Performance comparison with gzip module
- Internal Architecture
- Tracing the Decoder
Installation
You can simply install it from PyPI:
python3 -m pip install --upgrade pip # Recommended for newer manylinux wheels
python3 -m pip install pragzip
The latest unreleased development version can be tested out with:
python3 -m pip install --force-reinstall 'git+https://github.com/mxmlnkn/indexed_bzip2.git@master#egginfo=pragzip&subdirectory=python/pragzip'
And to build locally, you can use build
and install the wheel:
cd python/pragzip
rm -rf dist
python3 -m build .
python3 -m pip install --force-reinstall --user dist/*.whl
Usage
Command Line Tool
pragzip --help
# Parallel decoding: 1.7 s
time pragzip -d -c -P 0 sample.gz | wc -c
# Serial decoding: 22 s
time gzip -d -c sample.gz | wc -c
Python Library
Simple open, seek, read, and close
from pragzip import PragzipFile
file = PragzipFile( "example.gz", parallelization = os.cpu_count() )
# You can now use it like a normal file
file.seek( 123 )
data = file.read( 100 )
file.close()
The first call to seek will ensure that the block offset list is complete and therefore might create them first. Because of this the first call to seek might take a while.
Use with context manager
import os
import pragzip
with pragzip.open( "example.gz", parallelization = os.cpu_count() ) as file:
file.seek( 123 )
data = file.read( 100 )
Storing and loading the block offset map
The creation of the list of gzip blocks can take a while because it has to decode the gzip file completely. To avoid this setup when opening a gzip file, the block offset list can be exported and imported.
Open a pure Python file-like object for indexed reading
import io
import os
import pragzip as pragzip
with open( "example.gz", 'rb' ) as file:
in_memory_file = io.BytesIO( file.read() )
with pragzip.open( in_memory_file, parallelization = os.cpu_count() ) as file:
file.seek( 123 )
data = file.read( 100 )
Via Ratarmount
Because pragzip
can be used as a backend in ratarmount, you can use ratarmount to mount single gzip files easily.
Furthermore, since ratarmount 0.11.0, parallelization is the default and does not have to be specified explicitly with -P
.
base64 /dev/urandom | head -c $(( 4 * 1024 * 1024 * 1024 )) | gzip > sample.gz
# Serial decoding: 23 s
time gzip -c -d sample.gz | wc -c
python3 -m pip install --user ratarmount
ratarmount sample.gz mounted
# Parallel decoding: 3.5 s
time cat mounted/sample | wc -c
# Random seeking to the middle of the file and reading 1 MiB: 0.287 s
time dd if=mounted/sample bs=$(( 1024 * 1024 )) \
iflag=skip_bytes,count_bytes skip=$(( 2 * 1024 * 1024 * 1024 )) count=$(( 1024 * 1024 )) | wc -c
C++ library
Because it is written in C++, it can of course also be used as a C++ library.
In order to make heavy use of templates and to simplify compiling with Python setuptools
, it is mostly header-only so that integration it into another project should be easy.
The license is also permissive enough for most use cases.
I currently did not yet test integrating it into other projects other than simply manually copying the source in src/core
, src/pragzip
, and if integrated zlib is desired also src/external/zlib
.
If you have suggestions and wishes like support with CMake or Conan, please open an issue.
Performance comparison with gzip module when a gzip index exists
These are simple timing tests for reading all the contents of a gzip file sequentially.
import gzip
import time
with gzip.open( gzipFilePath ) as file:
t0 = time.time()
while file.read( 4*1024*1024 ):
pass
t1 = time.time()
print( f"Decoded file in {t1-t0}s" )
The usage of pragzip is slightly different:
import indexed_gzip
import pragzip
import time
with indexed_gzip.IndexedGzipFile(gzipFilePath) as file:
file.build_full_index()
file.export_index(gzipFilePath + ".index")
# parallelization = 0 means that it is automatically using all available cores.
for parallelization in [0, 1, 2, 6, 12, 24, 32]:
with pragzip.PragzipFile(gzipFilePath, parallelization = parallelization) as file:
file.set_block_offsets(open(gzipFilePath + ".index", 'rb'))
t0 = time.time()
while file.read( 4*1024*1024 ):
pass
t1 = time.time()
print( f"Decoded file in {t1-t0}s" )
Results for an AMD Ryzen 3900X 12-core (24 virtual cores) processor and with gzipFilePath=4GB-base64.gz
, which is a 4 GiB gzip compressed file with base64 random data.
Module | Runtime / s |
---|---|
gzip | 17.2 |
pragzip with parallelization = 0 | 1.25 |
pragzip with parallelization = 1 | 13.8 |
pragzip with parallelization = 2 | 7.0 |
pragzip with parallelization = 6 | 2.5 |
pragzip with parallelization = 12 | 1.47 |
pragzip with parallelization = 24 | 1.25 |
pragzip with parallelization = 32 | 1.33 |
The speedup of pragzip
over the gzip
module with parallelization = 0
is 17.2/1.25 = 14.
When using only one core, pragzip
is faster by (17.2-13.8)/17.2 = 20%.
Internal Architecture
The main part of the internal architecture used for parallelizing is the same as used for indexed_bzip2.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Hashes for pragzip-0.2.1-pp39-pypy39_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6c5826b81e42a12d5c668d34c8d022de1c3e2afbaf90da24dff2e8fae104b946 |
|
MD5 | ce08e186b77ed0949df5765c99e87c94 |
|
BLAKE2b-256 | 2017e1e565916e7da58da78d6dab12f70918bc89b7019bdb20bc42c4dce75fcb |
Hashes for pragzip-0.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3945cd6c5bb8d9bb608ad8a62b8a0b130dd3bf3f713856757b8d1e9ea1357a83 |
|
MD5 | 4086b763b9d45ac96cddd06cf540c5e7 |
|
BLAKE2b-256 | 98d1c5f7a706ea56854a7db3a5b69a37471712180a54641c69a5d01d335fb81a |
Hashes for pragzip-0.2.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a0c902fe6455b1dc81ff8608c38933f79e5caae402cb15327c2a8e83c4de1df3 |
|
MD5 | 861aadaa8c5a4a708e9005a967d15628 |
|
BLAKE2b-256 | b56d06698407a60ede96ee49e13c47dbe369ad73c91e4f9aeef8bb16abb68d2f |
Hashes for pragzip-0.2.1-pp38-pypy38_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 84a1125880099268191e9551a00b03a0b9b3e1d57f6562cc94eb3206bcaeedbf |
|
MD5 | 29f5b33323552751f8ca083f5b55cd36 |
|
BLAKE2b-256 | a026ff72be62c7b9040123802474b2269be15a373789289e07b3ed235bfe55fa |
Hashes for pragzip-0.2.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6e196c205efd25b6b352c4de9a9973daa09df29f61c30118ec8896dac53304c2 |
|
MD5 | 4170c618ea3308b53a67ba2ac900c38e |
|
BLAKE2b-256 | b7b29b63266ef5dc5c5e718a26b76182ac58da2f56a2c59521a74ed4202fdf57 |
Hashes for pragzip-0.2.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a8ac205b6a11bc3f716ed9f5a33b945659e07f9abe74bddf401453cad24a6fac |
|
MD5 | 73c16b34d9882ddc48f3092ea846a43e |
|
BLAKE2b-256 | 4fec90045a1f55030dcf0a24090b1dec5606c988c906f0aac5e14b04b5ffb6c3 |
Hashes for pragzip-0.2.1-pp37-pypy37_pp73-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3de6536a6b408d6ba367018a623dc3d29556e4297d42ea90378b84d1fc004d04 |
|
MD5 | 80c342c0cf676be35654ca09c4045c7c |
|
BLAKE2b-256 | 3d724140b106c1b0a8922af9af2650e30bb26eb09eac40152d10a7deb74f9a51 |
Hashes for pragzip-0.2.1-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f8e469a1ef78507d55fd1b7b53171552ed66b46e5a66008bbd813364eb955756 |
|
MD5 | 35110d731c9ab9e11b1f65a161522f8f |
|
BLAKE2b-256 | 7c8f55929ca2fa44bb51ae8bcce5dd379ae7fa672321fa73332fd38d8bba8fce |
Hashes for pragzip-0.2.1-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3dc13f960adaac904c69805daf687af0d991c8a1a9752ec74a1d5fedabd79821 |
|
MD5 | cebe506a030b38077dad44561fe4b0ef |
|
BLAKE2b-256 | 8f1e790080cd033ca51ecf7a983a56aac9d1648e4f73fc27175ccde5f46a017b |
Hashes for pragzip-0.2.1-cp310-cp310-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | b03bb28ada250c0d2c59922596442efb0aac1abe664d040e7b27410366b24c98 |
|
MD5 | a14ef2d0e0f5299b310790058ac86f4c |
|
BLAKE2b-256 | 1057c62022627861e9f7d4af3a9da30fc900919d095a55b05c0eeb499aa988e7 |
Hashes for pragzip-0.2.1-cp310-cp310-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | c2ba22d36d97955fb24a4ce873d6ce11e26728b58362f14effa0b6acec86421f |
|
MD5 | fe880cf52afc49f5ff93ef91e01f9c33 |
|
BLAKE2b-256 | ae5bc43a85ef28de91aa3c7161aa38f975358f8ec8269a79c307baa93f0f9dcb |
Hashes for pragzip-0.2.1-cp310-cp310-musllinux_1_1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 108393896111a9633335933cbe2852b28a6a85074da096978021ebcfe8b14349 |
|
MD5 | 06d0e76ea3d454a2f5450a3f856cf0f0 |
|
BLAKE2b-256 | 43e296a62184802c8a64fb7ff1bc3a5bd131a8e4a04cf030ee32cd356b68b2bb |
Hashes for pragzip-0.2.1-cp310-cp310-musllinux_1_1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | beed5589e2f0b4b1dbf999dac8fea362e79453bbf4cea4c029cbe43cc61e6e79 |
|
MD5 | 85c765f5676320d1eb17e30429fc5359 |
|
BLAKE2b-256 | 6f5c30b8eb7374ff1c4f96a8bf519044652dd9212bd3f395f036c0c5ea310852 |
Hashes for pragzip-0.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | bfdd2cd95186a1439a642924e17ac5e47eaa8e8a362659d35d39e636b266e8b8 |
|
MD5 | a65fceebbe07e3052795791aa1c1a740 |
|
BLAKE2b-256 | 560fe221ed8ead0440220d3df09ff490856f2afe1fba34550cd80a03baeecf7e |
Hashes for pragzip-0.2.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | eb697deef0e352b1ea59b6f134d149380983126f034f358f29e55e277f0d8178 |
|
MD5 | 53d98d2dc3d1dfdff46dc07c1472f392 |
|
BLAKE2b-256 | d8e64d1d6ce184ff61cb341104290450b075f39da2fb7a8c21b44177066177ef |
Hashes for pragzip-0.2.1-cp39-cp39-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a66b14c601533400c0f5b9097824b781cbb9e9f3d380410562164ef6c09d4e96 |
|
MD5 | fd96f4ff860e0ebd1860e621f4da331f |
|
BLAKE2b-256 | 866488a8d5bc3bd546eb532c0a8e2aa9ba2dfa870e133a30745b4c568f600a6f |
Hashes for pragzip-0.2.1-cp39-cp39-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | e31a6cff23fbc856d50258f5467158d30affe465424f2dd7834aef9750d6b093 |
|
MD5 | 1980a0291f4f8c307003a8c4e1787f04 |
|
BLAKE2b-256 | 48bc86a4c6a651d479d52651dec6f120f97c1b766dae0f76201a2ae058e4eba6 |
Hashes for pragzip-0.2.1-cp39-cp39-musllinux_1_1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d52d00b1a660776166b3234749951e0cdef99ef77154c737f06f91c7581363cd |
|
MD5 | 92f11262efb9818bfaea7c3e222717dc |
|
BLAKE2b-256 | 4f5d2d17f5568acc34277f50702607b466761ea34573d7609131d25d8db8e3e1 |
Hashes for pragzip-0.2.1-cp39-cp39-musllinux_1_1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | f92273c032181cc33ce3ffa5a1dc9fdbe0305a5ed9d6917d81f7659a062437cf |
|
MD5 | 42a6f45920b4489a6b37e2c90bc16b04 |
|
BLAKE2b-256 | 0f1e19394fffc0fe512bf34afed16121fb8f1748a18b763ff1fc44259b305251 |
Hashes for pragzip-0.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3d2d27f8aa4f1e1eef1a635304019a18ca557b31c64a1a03d206aafa340c03a9 |
|
MD5 | 69dfa5fc482d0e1cb02740dde1925b70 |
|
BLAKE2b-256 | 0c31dfa630f551138af226c5efbfb03f93d49a666d59e49453ac2df0eb33d43c |
Hashes for pragzip-0.2.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 6fa0aed257ba048467a56efa9faf4cc7f1f72bc325d05bea0da93373c49c4f22 |
|
MD5 | 31a9b2e068e477b5faf909f3881521e5 |
|
BLAKE2b-256 | f772421559fe9d0bd932243fa432e8a564c491e89d777fe5710def4a7428dae0 |
Hashes for pragzip-0.2.1-cp38-cp38-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | d7a7e94930e3d9971561940f9fdbc4af9f758c52ef3038704ca224e6ce7cdb94 |
|
MD5 | 90650edfb5fcbcd8587af2c19f93c4bd |
|
BLAKE2b-256 | eb69636047ec3bcd834e7d59270f5e80381841578a4142653e73dfc1749fa8ff |
Hashes for pragzip-0.2.1-cp38-cp38-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a2fbe6a0d23e43641ad08f13561b3d05f9631ce7639996950b8bf4b25018efb9 |
|
MD5 | 51ee014b4393bcbc252ba7b1872961f6 |
|
BLAKE2b-256 | e03a5ac244b363a7fb2e7fd925e21b054616769fd2f4fc766bce0c394615b7ab |
Hashes for pragzip-0.2.1-cp38-cp38-musllinux_1_1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3dcfecc3258e1bf7b876888eda5888194ad3a3abad0cece5b0aec431d33171fe |
|
MD5 | 0617668dd378c8e4dcffa850a5048679 |
|
BLAKE2b-256 | 88fe14b9bce19c9b1c847a02a850ff84e221150b3fe1f4a731820ab220c7dab9 |
Hashes for pragzip-0.2.1-cp38-cp38-musllinux_1_1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 4e633c0fbf7525a67e289ddd8096dda3c87798c380ef78d30f96d347d3a93049 |
|
MD5 | 01c213d16ca780b8dc92ce3ab2b84580 |
|
BLAKE2b-256 | 1ae9ce7225caba525f7cacb09bd78ae56d82ff2e4151ef1da76fdf1c06eacdc0 |
Hashes for pragzip-0.2.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 5547c900dadfd068c778b9def616c99533f287e1555ea3dfef704692950d96cb |
|
MD5 | d288dfc210ee447e4b5cd24096cb5969 |
|
BLAKE2b-256 | 11eafcf1d74f3147250dece852f61ffb01dd2869651fac1f7eb2f0fd4408e97e |
Hashes for pragzip-0.2.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 10da3739fed90870cc559114f3da021ef07732683322d66dd2581afe037bbfe7 |
|
MD5 | e69afe73d234932244a8420a7110b892 |
|
BLAKE2b-256 | 58639f3b17404d0cf009a8b9b6d95cad7e0cfdb48d3036711cd845db79684337 |
Hashes for pragzip-0.2.1-cp37-cp37m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 86483be2d234a65fb8a247cd845585b3d070d3ea7b0568cb0dce0ebc3064c0e5 |
|
MD5 | 2c020d52052b495e226b7c2033c53c02 |
|
BLAKE2b-256 | 296eed44b680446a42b3ca933f2cc32ca461813347dee6b519d8a2cd66be274c |
Hashes for pragzip-0.2.1-cp37-cp37m-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 318c8b0629b5031183c96a450d1ad531111f6ec35b462cf1257a5acbdd23920e |
|
MD5 | d419669d4ae1e8455fbef649336a113f |
|
BLAKE2b-256 | 3eeba27d5ce5f2574cbbfd0046fef93b0e27289a7972eb7da6ba455e18ab4173 |
Hashes for pragzip-0.2.1-cp37-cp37m-musllinux_1_1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 3ac8edb26a0d9cf9f15f913ae938bcff8cc4558b828e8106f7931a52a621f434 |
|
MD5 | 1b2042a33fef01d73e0c84fba4a20c82 |
|
BLAKE2b-256 | 2f6336125fec3a32b5b52a1e9c7fd22f6b6cbd413c3a3c353e5ad58ca1ad440b |
Hashes for pragzip-0.2.1-cp37-cp37m-musllinux_1_1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 98df7314359076fa284d266f8673cb06d6054d6bb9e29de3817ae90e436b4438 |
|
MD5 | 1646b92cde9404efcd2b0d2720ce4cc0 |
|
BLAKE2b-256 | f1312ce4274c804d919521337bedd41407e54847c5d2ccd2d8a772207e72358e |
Hashes for pragzip-0.2.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2cbccf8375ff84f8634b48331f29feed1393e6c94d3667d314dfa3a7670d55f0 |
|
MD5 | a6a1d18f0a8efbd9bce4dd87835c5b1e |
|
BLAKE2b-256 | eb6f0f18ec360d82131f6924b49c7e9c6a2fa70daf13aa187ba0f074af982886 |
Hashes for pragzip-0.2.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 9da867ab95b4165683610695f96a4aa53387b4fda4d9ad6a5df67218a3430523 |
|
MD5 | 45828fe97c3731c95b041e6a11fe91f4 |
|
BLAKE2b-256 | 52ea96cfc349926b0edefbc03d60b288b1ebab011566d243e8c110f27e178808 |
Hashes for pragzip-0.2.1-cp36-cp36m-win_amd64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 44e6b271830a70e1360262cb878f6f9a860d3aa51a25e810ec7d96b42d3c47e7 |
|
MD5 | 2c0ac4af648f3f2743866ee358915e5d |
|
BLAKE2b-256 | 2340ef8585b35a8d11024932f2719a46c838b289310324db43fee62adef3e5a7 |
Hashes for pragzip-0.2.1-cp36-cp36m-win32.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 270c777fc8587652540fd7e7956d56ea84ff72f7c8f438e0c031a5da6a50441e |
|
MD5 | 198861c9d94123a6c6ea3118dd201b8c |
|
BLAKE2b-256 | f4e97da6e492c8a3cb9f657e9d4247c8a4b2d9c17c525f500ef5edacb5d0cf8d |
Hashes for pragzip-0.2.1-cp36-cp36m-musllinux_1_1_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2a37a1fa11f6f1b3d08f622cba9089acfb6d38b59415d92f25af755ef5a18e55 |
|
MD5 | dd11ce5a67afd9e974f3b854e1f7aefd |
|
BLAKE2b-256 | 943aaeb07535987a41f4b65c048d7f325ffcdf009926d01a286390e2abb95718 |
Hashes for pragzip-0.2.1-cp36-cp36m-musllinux_1_1_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 03b0dd2bbd10fbbce8d5c9d03a0ff77b666d22ad43c1180602f25cc65fffb313 |
|
MD5 | ace862e997e1abe429cb0f78bf5b2bf6 |
|
BLAKE2b-256 | d6b7dc933e18c29bb190e66e6fb00a0a32dc2a5c9fc18d8b669ea974057bc653 |
Hashes for pragzip-0.2.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | 0acc93389cef62c463db84f58647defbbb403b54d7a28be538a30bfd81006305 |
|
MD5 | 50e02ebd46227fa3fc34b0eda94cb77a |
|
BLAKE2b-256 | 823584cde8e19aac0a6a2efed526778250c00130e3e632c1992e2f7de694bdb6 |
Hashes for pragzip-0.2.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl
Algorithm | Hash digest | |
---|---|---|
SHA256 | a3cfb7ee55755f76520c70b1cae4d186399f1f42613dc4bacbe615b78dd9f2a7 |
|
MD5 | bd9b46e2e437d7a9b763496d8009703e |
|
BLAKE2b-256 | 528b3b99cbf30ddd3a11da37d8712c6a79e74e20a7f516ebd1cd089185564e08 |