Lock-free SPMC byte stream buffer with C++ interoperability via shared memory
Project description
slick-stream-buffer-py
A Python implementation of slick-stream-buffer — a lock-free single-producer multi-consumer (SPMC) byte stream buffer with shared memory support.
Maintains exact binary compatibility with the C++ version: a Python producer and a C++
consumer (or vice versa) communicate seamlessly through the same shared memory segment, using
the same std::atomic synchronization primitives.
Features
- Byte stream, message records: the producer writes raw bytes (
prepare/commit) and publishes them as discrete message records (consume), like a network receive buffer feeding a framing layer - Lock-free SPMC: one producer, any number of consumers, no locks anywhere
- Binary-compatible with C++: identical 64-byte header, 32-byte control records, and
acquire/release memory orderings (
slick/stream_buffer.hpp, header magic'SSB1') - Shared memory IPC: built on
multiprocessing.shared_memory, matching the C++ slick-shm naming conventions on Windows, Linux, and macOS - Lossy by design: slow consumers skip overwritten data and count the loss instead of blocking the producer
- Local memory mode: same API without shared memory for single-process use
- No runtime dependencies: Python 3.8+ standard library plus a small bundled C++ extension for the atomics
Requirements
- Python 3.8+
- 64-bit platform (Windows x86-64, Linux x86-64/ARM64, macOS x86-64/ARM64)
- A C++17 compiler to build the
ssb_atomic_ops_extextension (MSVC 2017+, GCC 5+, Clang 3.8+)
Installation
pip install -e .
# or just build the extension in place:
python setup.py build_ext --inplace
Quick Start
Producer (creates the shared memory segment)
from slick_stream_buffer_py import SlickStreamBuffer
# 64 MB data ring, 65536 message records
stream = SlickStreamBuffer(capacity=1 << 26, control_size=1 << 16, name="market_data")
while True:
mv = stream.prepare(64 * 1024) # contiguous writable memoryview (zero-copy)
n = sock.recv_into(mv) # write network bytes directly into the ring
stream.commit(n)
# publish every complete package as one message record
while (package_size := find_complete_package(stream.data(), stream.size())):
stream.consume(package_size)
Consumer (opens the existing segment — can be C++ or Python)
from slick_stream_buffer_py import SlickStreamBuffer
stream = SlickStreamBuffer(name="market_data") # geometry read from the segment header
cursor = stream.initial_reading_index() # skip history; use 0 to read from the start
while True:
data, length, cursor = stream.read(cursor)
if data is None:
continue
handle_package(data, length)
Local memory mode (single process)
buf = SlickStreamBuffer(capacity=1024, control_size=16)
mv = buf.prepare(5)
mv[:] = b"hello"
buf.commit(5)
buf.consume(5) # publish as one record
data, length, cursor = buf.read(0) # -> b"hello", 5, 1
C++ Interoperability
The C++ side uses the identical layout — either side can create the segment, the other attaches to it:
#include <slick/stream_buffer.hpp>
slick::stream_buffer stream("market_data"); // open segment created by Python
uint64_t cursor = stream.initial_reading_index();
for (;;) {
auto [data, length] = stream.read(cursor);
if (data == nullptr) continue;
handle_package(data, length);
}
Shared memory naming: use get_shm_name() to obtain the exact name to pass to C++
(on POSIX it includes the leading / that shm_open() requires; on Windows it is the
raw name).
Shared memory layout
[HEADER: 64 bytes]
0-7 atomic<uint64> committed_ - monotonic end of committed bytes
8-15 atomic<uint64> consumed_ - monotonic publish boundary
16-23 atomic<uint64> next_seq_ - next record sequence number
24-31 atomic<uint64> reserve_end_ - prepared-region high-water mark
32-39 uint64 capacity_ - data ring size in bytes (power of 2)
40-43 uint32 control_size_ - control ring record count (power of 2)
44-47 uint32 header_magic - 0x53534231 ('SSB1')
48-51 atomic<uint32> init_state - 0=uninit, 2=initializing, 3=ready
52-63 padding
[CONTROL RING: 32 bytes x control_size]
each record: atomic<uint64> seq | uint64 offset | uint32 length | 12 bytes padding
[DATA RING: capacity bytes]
Total segment size: 64 + 32 * control_size + capacity.
API Summary
| Method | Role | Description |
|---|---|---|
prepare(n) -> memoryview |
producer | contiguous writable region; may relocate unconsumed bytes on wrap |
commit(n) |
producer | move n prepared bytes into the readable region (clamped) |
consume(n) -> PublishedRecord |
producer | publish the first n readable bytes as ONE record (clamped) |
discard() |
producer | drop unconsumed + prepared bytes without publishing |
data() -> memoryview / size() |
producer | the committed-but-unconsumed region |
read(cursor) -> (data, length, cursor) |
consumer | next record, or (None, 0, cursor); skips lost records |
read_last() -> (data, length) |
consumer | newest record without a cursor |
initial_reading_index() |
consumer | cursor for a late joiner (skips history) |
loss_count() |
consumer | records skipped by this instance due to overwrite |
reset() |
owner | clear all state (not thread-safe) |
close() / unlink() |
lifecycle | detach / delete the segment |
See API_DIFFERENCES.md for the exact deviations from the C++ API (cursor passed by value, bytes copies vs pointers, exceptions).
Caveats (same as C++)
- Producer methods (
prepare/commit/consume/discard/data/size/reset) must be called from a single thread. - The buffer is lossy: if the producer outruns a consumer by more than the control ring or data ring size, the consumer skips ahead and the loss is counted.
prepare()may relocate the readable region: memoryviews previously returned bydata()orprepare()are invalidated.- A single message (one
consume()call) is limited to < 4 GiB.
Building and Testing
# 1. Build the atomics extension
python setup.py build_ext --inplace
# 2. Pure-Python tests
python tests/test_atomic_ops.py
python tests/test_local_mode.py
python tests/test_shm_mode.py
# 3. C++ interop tests (requires CMake + a C++20 compiler)
cmake -S . -B build
cmake --build build --config Debug
cd build && ctest -C Debug --output-on-failure
The interop tests fetch slick-stream-buffer
(which pulls slick-shm) from GitHub and build real
C++ producer/consumer binaries against the actual stream_buffer.hpp. To build against local
checkouts instead (no network):
cmake -S . -B build \
-DFETCHCONTENT_SOURCE_DIR_SLICK-STREAM-BUFFER=/path/to/slick-stream-buffer \
-DFETCHCONTENT_SOURCE_DIR_SLICK-SHM=/path/to/slick-shm
If a failed test run leaves segments behind: python tests/cleanup_shm.py
Related Projects
- slick-stream-buffer — the C++ implementation
- slick-queue-py / slick-queue — MPMC fixed-element queue with the same interop approach
License
MIT
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
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slick_stream_buffer_py-0.1.0.tar.gz.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0.tar.gz
- Upload date:
- Size: 31.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d1989f9bec9237754713753abc6e9cf666ecec942f0e8ea55cbe1106b97f68b7
|
|
| MD5 |
5f60b38acec60c11f132574a5effc7ad
|
|
| BLAKE2b-256 |
ccf9f9849887e32c91e1101df4d862f8151077dd3d323506de64ee3186c9aaaf
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 23.7 kB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3d560d308231d78381fcd8d50628bc6cb02446f086a3e7c86a8eed7c80fdf2b
|
|
| MD5 |
1a38dedc08a0bb901aafef54dbb3af98
|
|
| BLAKE2b-256 |
187f1e50cd2c825de1969cc9845a349b0247b404c61a6cd1f5bad59e6bae57fe
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 38.8 kB
- Tags: CPython 3.13, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5feada4c7daa8a4c7292e0f857fb51307dc20c14406f5b5faf740a9215ae8bc5
|
|
| MD5 |
813565c97aa1861b62d45ca6aacae4e8
|
|
| BLAKE2b-256 |
5aa0d446d83e71bb3a6abf6ef0959bf0ee9c253c83c7beb41128fa35cecf9f0f
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp313-cp313-macosx_10_13_universal2.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp313-cp313-macosx_10_13_universal2.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.13, macOS 10.13+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3b340e50e9262325d57ac9c1fd092bc3419c0f49f0819dac8dc6563607817b73
|
|
| MD5 |
41658de4b7fd5d19761e14b6f21d7b08
|
|
| BLAKE2b-256 |
ae4f0f64734b07ec85ed771dc0e2431a9e27b90d13b0818ac955ca4f21ad7d46
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 23.8 kB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fbd9914b54f3a4649faf65c5e173a07f9a37b76af982b3dfeeef7110ab8fb27f
|
|
| MD5 |
9657e778f7aaac37c09e6b515734c24b
|
|
| BLAKE2b-256 |
1615f8f2ff40fa5e397df81ebff918af548fbe3de30532769b17682167eeff46
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 38.8 kB
- Tags: CPython 3.12, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b3d78a858e27d05900a65b379467c325faeef50ec5fea616399cd1a8f9911a66
|
|
| MD5 |
616eb034e65a732a11f7ec3d18283a40
|
|
| BLAKE2b-256 |
2639e8f52e7dc285b03c9a3c84fcbdd5a6c3f2ade229a40001972816ac833ebc
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp312-cp312-macosx_10_13_universal2.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp312-cp312-macosx_10_13_universal2.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.12, macOS 10.13+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0c8c6018667c4f2c24906b25143dad8db4fb2a818fb9c766c9037678aaa455b6
|
|
| MD5 |
3ff00796a35edcc5383cd3c7e332baa8
|
|
| BLAKE2b-256 |
a6d155f7dbcfde81f9caadd17d2694edd6d2d4e4fa0a963af633b49c1a122fa5
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 23.8 kB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a238470694bc1f03dd523eb580d302068957f3664c79ad17ffaf4ceefdb711ca
|
|
| MD5 |
812a6e2b4d5d5a8ed1c25ac49ce41c69
|
|
| BLAKE2b-256 |
e7fda490324523f2363073361add4105eb504d4322c48386192ca864ce895173
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 38.9 kB
- Tags: CPython 3.11, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29c1dde2b18f7b86f96cb10a1cc8b4ab039a1c9c31eec1a16c913357c6178ddf
|
|
| MD5 |
d1fba6c6b63d2036c77bf41afe4d3e5a
|
|
| BLAKE2b-256 |
df96bda315e60b0cc4875803b255b4a4df2ac0cc3956815263fc32c83f588fc0
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp311-cp311-macosx_10_9_universal2.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp311-cp311-macosx_10_9_universal2.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.11, macOS 10.9+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5401e5763825f04360c7fc1a326f82475530c9921b6bc2788ad43253a65decc0
|
|
| MD5 |
17543f369e9d0195b32272f3c8fa9324
|
|
| BLAKE2b-256 |
0b4ca5e2b4174f457b1a4c97d119f57a6c6100256281016d8830788af9790d9e
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 23.8 kB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
be326f5268f431bab99e654a679693e99aebadfb867274826521b611cc5a0ed5
|
|
| MD5 |
80605799f16fe3926a7689cff7e1556a
|
|
| BLAKE2b-256 |
33a27ade178031ff967359660cef4d1514b6139942ceb6f13cc86db3d76ed15c
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 38.9 kB
- Tags: CPython 3.10, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
62a8aeabaf6acf388d283a32d9cd048e9ffaa6daf74ca99f2e62cc4ffd246927
|
|
| MD5 |
83fe08e4315b9f96931e2267398c0804
|
|
| BLAKE2b-256 |
f7702730cd283dc05b5b4c14ae1a6f17b483b3dbd663a34c19584fe69662d161
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp310-cp310-macosx_10_9_universal2.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp310-cp310-macosx_10_9_universal2.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.10, macOS 10.9+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b11137a1ffa9f2532ccd86e4a006cadc3a1f909853996c260bc3d342dd4bdd83
|
|
| MD5 |
1890658da18c27a669d33702b1e173f0
|
|
| BLAKE2b-256 |
5f0411afdf0df1917ee1cef2eede15beab3e80494eea53ebfc7d139a7d6c87e1
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 23.8 kB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
816efc709622002d84ca0a634e94256c90936f22dbdf3a3a4b1743c101fb299e
|
|
| MD5 |
bf7514dea8df995884eafcb0258c7310
|
|
| BLAKE2b-256 |
ae8164c085914454aeed09a47cbd98a776d03ba2589786367eb8cef80db45f4b
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 38.6 kB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74dc9af979ca59b2b8cb4a94c5ca1075904edb29cd6d1192b513a66ca90150de
|
|
| MD5 |
31476edccf233e41477ac4a9af8bd3d1
|
|
| BLAKE2b-256 |
02ae9b0131ddb54d3c1ca3494f21f68a4d0d69fffeacd71d10620e872a1eeff2
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp39-cp39-macosx_10_9_universal2.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp39-cp39-macosx_10_9_universal2.whl
- Upload date:
- Size: 23.2 kB
- Tags: CPython 3.9, macOS 10.9+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
126646da8b691a4aa574801f4c6a581fe0132da0341b1b58c30242e56a967df6
|
|
| MD5 |
02d4711c696ddaacebf4a0d90298d172
|
|
| BLAKE2b-256 |
faa488921571619384498e60e5d200063716aff98dcdba66c85d031a65a30e07
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp38-cp38-win_amd64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp38-cp38-win_amd64.whl
- Upload date:
- Size: 23.7 kB
- Tags: CPython 3.8, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b632796d9a33466d0b1108cb3a1260538f90b262a491c41d9e6fb32113f3a98f
|
|
| MD5 |
60cc5dea3d121abd91dc853376f47a14
|
|
| BLAKE2b-256 |
ba061a5db48f2799fe94e24b0bf6ef35cf4ef4b633793e4b53c3901e3f118473
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 39.0 kB
- Tags: CPython 3.8, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
30ce1cec6c6dcee407a0594c122ac4ed760e0d08b7685f94e75de4ce4e2e9eb5
|
|
| MD5 |
c57e911b80534cedb6a1dcbc353e25b0
|
|
| BLAKE2b-256 |
1873038d10b96f45ff69a918ee5658f44e7c912d172f207d4689d0e2c22da645
|
File details
Details for the file slick_stream_buffer_py-0.1.0-cp38-cp38-macosx_10_9_universal2.whl.
File metadata
- Download URL: slick_stream_buffer_py-0.1.0-cp38-cp38-macosx_10_9_universal2.whl
- Upload date:
- Size: 23.0 kB
- Tags: CPython 3.8, macOS 10.9+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
91021870889a293ee806bc7ea562e19132d15d0d94d110a9b62adc71bc771c99
|
|
| MD5 |
4952947181d8ba79433b8f8f01a30691
|
|
| BLAKE2b-256 |
58282b059bf1ffcd73a528068e4a2a9f9f0873ff19d5422536f545e72f425440
|