Skip to main content

A high-performance, O(P) data structure for weighted random sampling of binned probabilities, ideal for large-scale simulations.

Project description

DigitBinIndex

A DigitBinIndex is a tree-based data structure designed for efficient weighted random selection and removal from large collections of items. It is optimized for scenarios involving millions of items where probabilities are approximate and high performance is critical, such as simulations for Wallenius' noncentral hypergeometric distribution or Fisher's noncentral hypergeometric distribution.

This library provides high-performance solutions for both major types of noncentral hypergeometric distributions:

  • Sequential Sampling (Wallenius'): Modeled by select_and_remove, where items are selected and removed one at a time.
  • Simultaneous Sampling (Fisher's): Modeled by select_many_and_remove, where a batch of unique items is selected and removed together.

The Core Problem

In simulations, forecasts, or statistical models (e.g., mortality models, Monte Carlo simulations, or machine learning sampling), managing a large, dynamic set of probabilities is common. A key task is to randomly select items based on their weights, often removing them afterward, and repeat this process efficiently. For datasets with millions of items, achieving high performance while maintaining reasonable accuracy is a significant challenge, especially for complex distributions like Wallenius' or Fisher's.

How It Works

DigitBinIndex is a radix tree that organizes items into bins based on the decimal digits of their rescaled probabilities, enabling fast weighted random selection and updates.

  1. Digit-based Tree Structure: Each level of the tree corresponds to a decimal place of the rescaled weight. For example, a weight of 0.543 at precision 3 is rescaled to 543 and placed by traversing the path: root -> child[5] -> child[4] -> child[3].

  2. Adaptive Bin Storage: Leaf nodes act as bins, storing item IDs in either a fast Vec<u32> (for small bins) or a compressed Roaring Bitmap (for large bins). The bin type is chosen automatically for optimal performance and memory use if a capacity hint is given.

  3. Accumulated Value Index: Each node tracks the accumulated_value (sum of weights beneath it), supporting O(P) weighted random selection, where P is the configured precision (number of decimal places).

Features

  • High Performance: Outperforms general-purpose data structures like Fenwick Trees for both sequential and simultaneous weighted sampling.
  • Dual-Model Support: Optimized methods for Wallenius' (select_and_remove) and Fisher's (select_many_and_remove) distributions.
  • O(P) Complexity: Core operations (add, remove, select) have a time complexity of O(P), where P is the fixed precision, effectively constant for a given configuration.
  • Memory Efficiency: Combines a sparse radix tree with Roaring Bitmaps for efficient storage, especially for sparse or clustered weight distributions.
  • Python Integration: Seamless Python bindings via pyo3 for cross-language support.

Performance

DigitBinIndex trades a small, controllable amount of precision by binning probabilities to achieve significant performance gains. The following benchmarks compare DigitBinIndex against an optimized FenwickTree implementation in a realistic, high-churn simulation.

The benchmark scenario starts with a large population (1M or 10M items), then simulates a high volume of activity:

  • Churn: A significant number of items are selected and removed.
  • Acquisition: New items are added to the population.

This measures the real-world throughput of both data structures under dynamic conditions. The tests were run on a standard desktop (Intel i7, 16GB RAM, Rust 1.75).


Wallenius' Draw (Sequential Churn)

This benchmark simulates sequential selection by removing 100,000 items one-by-one, then adding 110,000 new items. This is a common pattern in agent-based models or iterative simulations. DigitBinIndex's O(P) complexity gives it a decisive advantage as the population scales.

Scenario (N items) DigitBinIndex Time FenwickTree Time Speedup Factor
1 Million Items (p=3) ~27.5 ms ~82.2 ms ~3.0x faster
1 Million Items (p=5) ~39.7 ms ~77.7 ms ~2.0x faster
10 Million Items (p=3) ~551.0 ms ~1723.1 ms ~3.1x faster
  • Key Takeaway: DigitBinIndex is over 3.0 times faster than the FenwickTree for sequential operations on large datasets. Its performance is dependent on precision (P) and not the number of items (N), allowing it to scale far more effectively.

Fisher's Draw (Batch Churn)

This benchmark simulates simultaneous selection by removing a large batch of 100,000 unique items at once, followed by the acquisition of 110,000 new items. DigitBinIndex uses a highly optimized batch rejection sampling method.

Scenario (N items) DigitBinIndex Time FenwickTree Time Speedup Factor
1 Million Items (p=3) ~19.5 ms ~104.2 ms ~5.3x faster
1 Million Items (p=5) ~39.9 ms ~106.6 ms ~2.7x faster
10 Million Items (p=3) ~389.0 ms ~1649.9 ms ~4.2x faster

Key Takeaway: For batch selections, DigitBinIndex is even more efficient, performing up to 5.3 times faster. The batched nature of the operation further highlights the architectural advantages of the radix tree approach for this use case.


When to Choose DigitBinIndex

Use DigitBinIndex when:

  • You need high-performance sampling for Wallenius' or Fisher's distributions.
  • Your dataset is large (N > 100,000).
  • Probabilities are approximate, as is common in empirical data, simulations, or machine learning models.
  • Performance is more critical than perfect precision.

Consider a Fenwick Tree if you require exact precision and your weights differ only at high decimal places (e.g., 0.12345 vs. 0.12346), though this comes at the cost of O(log N) complexity and higher memory usage for large datasets.


Choosing a Precision

The precision parameter controls the radix tree's depth, balancing accuracy, performance, and memory. Higher precision improves sampling accuracy but increases memory usage (up to 10x per additional level) and slightly impacts runtime.

The Rule of Thumb

A precision of 3 or 4 (default: 3) is recommended for most applications. This captures sufficient detail for typical weight distributions while maintaining excellent performance and low memory usage.

The Mathematical Intuition

Each decimal place contributes exponentially less to a weight’s value. For a weight of 0.12345:

  • 1st digit (1): 0.1
  • 2nd digit (2): 0.02
  • 3rd digit (3): 0.003
  • 4th digit (4): 0.0004

Truncating at 3 digits limits the error per item to <0.001. In large populations, these errors average out, minimally affecting the selection distribution.

Guidance

Precision Typical Use Case Trade-offs
1-2 Maximum performance, minimal memory usage. Best for coarse weights (e.g., 0.1, 0.5). Loses accuracy with fine-grained data.
3-4 Recommended Default. Optimal for most scenarios. Captures sufficient detail for simulation or model data. Negligible performance/memory cost.
5+ High-fidelity scenarios with very close weights. Distinguishes weights like 0.12345 vs. 0.12346. Increases memory (up to 10x per level) and slightly impacts performance.

Internal Storage and Capacity

The DigitBinIndex is designed to handle a vast range of use cases, from a few thousand items to trillions, by automatically selecting the most appropriate internal storage engine.

Item Capacity

The index accepts u64 for individual item IDs. However, the internal storage of these IDs depends on the backend chosen.

To provide the best balance of performance and memory usage, the library's DigitBinIndex is an enum that automatically switches between three different backends (Small, Medium, and Large) when you use the with_precision_and_capacity() constructor or the explicit constructors small(), medium(), and large().

The selection is based on a simple heuristic: the average number of items expected per bin, which is calculated as capacity / 10^precision.

  1. Small (Vec<u32>):

    • Constructor: small(precision: u8).
    • Backend Datatype: u32 (max 4 billion).
    • Capacity Trigger: Low average items per bin (<= 1,000).
    • Best for: Small to medium-sized problems where select_and_remove speed is the absolute priority (O(1) swap_remove).
    • Warning: Truncates u64 IDs. remove_many can be O(N) per bin.
  2. Medium (RoaringBitmap):

    • Constructor: medium(precision: u8).
    • Backend Datatype: u32 (max 4 billion).
    • Capacity Trigger: Medium to large average items per bin (> 1,000).
    • Best for: Large-scale problems (millions to billions of items) where IDs fit within u32. Provides excellent memory compression and fast set operations (including remove_many).
    • Warning: Truncates u64 IDs.
  3. Large (RoaringTreemap):

    • Constructor: large(precision: u8).
    • Backend Datatype: u64 (max 18 quintillion = 18 billion billions).
    • Capacity Trigger: Extremely large average items per bin (> 1,000,000,000). This is used as a heuristic to detect that full u64 support is required.
    • Best for: Massive-scale simulations or any dataset that requires the full 64-bit ID space.

Examples of Engine Selection

Here are some practical examples of how calling with_precision_and_capacity translates into a specific internal engine.

Example 1: Small (Vec<u32>) is Chosen

You are simulating a population of 100,000 individuals with u32 IDs.

// Expecting 100,000 items with 3-digit precision
let index = DigitBinIndex::with_precision_and_capacity(3, 100_000);
  • Calculation: The number of bins is 10^3 = 1,000. The average items per bin is 100,000 / 1,000 = 100.
  • Result: Since 100 <= 1,000, the Small variant is chosen. This provides the fastest O(1) select_and_remove performance. (This would truncate u64 IDs).

Example 2: Medium (RoaringBitmap) is Chosen

You need to index 50 million product IDs, all of which fit within u32.

// Expecting 50 million items with 3-digit precision
let index = DigitBinIndex::with_precision_and_capacity(3, 50_000_000);
  • Calculation: The average items per bin is 50,000,000 / 1,000 = 50,000.
  • Result: This is > 1,000. The Medium variant is selected, using RoaringBitmap. This will be highly memory-efficient and very fast for all operations, including remove_many. (This would also truncate u64 IDs).

Example 3: Large (RoaringTreemap) is Chosen

You are working with a massive dataset where item IDs are 64-bit, and you expect trillions of entries.

// Expecting 5 trillion items with 3-digit precision
let index = DigitBinIndex::with_precision_and_capacity(3, 5_000_000_000_000);
  • Calculation: The average items per bin is 5_000_000_000_000 / 1,000 = 5,000,000,000.
  • Result: This is > 1,000,000,000. The Large variant is chosen. The heuristic correctly identifies this as a u64-scale problem and selects the only backend, RoaringTreemap, that provides full 64-bit ID support.

Usage & Installation

DigitBinIndex is available as a Python library on PyPI or as a Rust crate on Crates.io. Ensure Python 3.6+ for Python bindings or Rust 1.75+ for the Rust crate.

For Python 🐍

Install from PyPI:

pip install digit-bin-index

Example usage:

from digit_bin_index import DigitBinIndex

def main():
    # Create an index with precision 3 (default).
    index = DigitBinIndex()

    # With custom precision
    index_5 = DigitBinIndex.with_precision(5)

    # With custom precision and capacity hint for large datasets
    # This might choose a more memory-efficient internal storage.
    index_3_xl = DigitBinIndex.with_precision_and_capacity(3, 10_000_000)

    # Add items with IDs and weights.
    index.add(id=101, weight=0.123)  # Low weight
    index.add(id=202, weight=0.800)  # High weight
    index.add(id=303, weight=0.755)  # High weight
    index.add(id=404, weight=0.110)  # Low weight

    # Sequential (Wallenius') Draw: Select and remove one item.
    # Higher-weighted items (202, 303) are more likely.
    selected_item = index.select_and_remove()
    if selected_item:
        # The returned weight is a float, representing the bin's average weight
        item_id, weight = selected_item
        print(f"Wallenius draw: ID {item_id}, Weight ~{weight:.3f}")
    
    print(f"Items remaining: {index.count()}")  # 3

    # Simultaneous (Fisher's) Draw: Select and remove 2 unique items.
    selected_items = index.select_many_and_remove(2)
    if selected_items:
        print(f"Fisher's draw: {selected_items}")
    
    print(f"Items remaining: {index.count()}")  # 1

if __name__ == "__main__":
    main()

For Rust 🦀

Add to your Cargo.toml:

[dependencies]
digit-bin-index = "0.4.0" # Replace with the latest version from crates.io

Example usage:

use digit_bin_index::DigitBinIndex;

fn main() {
    // Create an index with precision 3.
    let mut index = DigitBinIndex::with_precision(3);

    // Add items with IDs and f64 weights.
    index.add(101, 0.123); // Low weight
    index.add(202, 0.800); // High weight
    index.add(303, 0.755); // High weight
    index.add(404, 0.110); // Low weight

    // Sequential (Wallenius') Draw: Select and remove one item.
    if let Some((id, weight)) = index.select_and_remove() {
        println!("Wallenius draw: ID {}, Weight ~{}", id, weight);
    }
    println!("Items remaining: {}", index.count()); // 3

    // Simultaneous (Fisher's) Draw: Select and remove 2 unique items.
    if let Some(items) = index.select_many_and_remove(2) {
        println!("Fisher's draw: {:?}", items);
    }
    println!("Items remaining: {}", index.count()); // 1
}

License

This project is licensed under the MIT License, a permissive open-source license allowing free use, modification, and distribution.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

digit_bin_index-0.4.2.tar.gz (38.4 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

digit_bin_index-0.4.2-cp38-abi3-win_amd64.whl (178.9 kB view details)

Uploaded CPython 3.8+Windows x86-64

digit_bin_index-0.4.2-cp38-abi3-win32.whl (176.0 kB view details)

Uploaded CPython 3.8+Windows x86

digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_x86_64.whl (475.8 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ x86-64

digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_i686.whl (506.7 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ i686

digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_armv7l.whl (583.7 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARMv7l

digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_aarch64.whl (476.8 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARM64

digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (303.2 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ x86-64

digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl (359.7 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ s390x

digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (340.0 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ppc64le

digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (319.4 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARMv7l

digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (295.6 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

digit_bin_index-0.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl (328.5 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.5+ i686

digit_bin_index-0.4.2-cp38-abi3-macosx_11_0_arm64.whl (269.1 kB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

digit_bin_index-0.4.2-cp38-abi3-macosx_10_12_x86_64.whl (285.9 kB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

Details for the file digit_bin_index-0.4.2.tar.gz.

File metadata

  • Download URL: digit_bin_index-0.4.2.tar.gz
  • Upload date:
  • Size: 38.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.9.4

File hashes

Hashes for digit_bin_index-0.4.2.tar.gz
Algorithm Hash digest
SHA256 ced6ae98ea436f797eaac1ac2ca33ecaf9e795c3ee60e0afc21d0705201f92b1
MD5 d419504b17368f2f8b4ece9c2796c1a8
BLAKE2b-256 f37fd71e33f287208a22784d21a2f74749d26c3918d2f1caeefdc57a1103fbf2

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 003c7f37261a5830091d5ab329020ae9c589fa9da634237ccf47e7af6a0aab09
MD5 078b7d75a7661a8d7c232637cc9f60de
BLAKE2b-256 8fd98b4832e9b79c5d376056113bc929f87c4bb6115be955b1cd84ec70c38c49

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-win32.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-win32.whl
Algorithm Hash digest
SHA256 5977d86234b4910b5cc76823951a48fb1c00fbcbf5b077f1949657f400d30abf
MD5 9eb091524b41dff86b19cf31246d2a7b
BLAKE2b-256 85dcf627b6e46fe4523dbae83d03d42680d55143fd7f3ce9b55239e4474463c3

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_x86_64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 8aad284dc929bde2a6f0bf276abaa9e90dfaa0e0f40b0ca1afdedb16ae653901
MD5 52ab12ba39f04a744fca0e5c5597b922
BLAKE2b-256 ba5fe9bead666a86aa673a9196bac4690d45754815771b293ef6daa2cb777a68

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_i686.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 b3f03aad9212f83c8882d95c907e1e5c43671f0ae8eef2368d2e53f154767a17
MD5 5d943d606169b076bafc198ac7025f49
BLAKE2b-256 7815a8e4ea6db2b5f914963d5ac17be4dd06e2798b21416143e4696a58d75b84

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_armv7l.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 b98da833e1aa4da7abb145efa251a6f536b33f92f5a90af7e3f0d02138b043fc
MD5 93c347b219773929094e95ba185eb9ad
BLAKE2b-256 1850b9fb6c315c01e97222954f7f43a0b81b2cfcc8762c3ad97186b859074a0b

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_aarch64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 6f467db608c96822781f9c32ca832e6c8241b976212f4adf2c8ce01c457ee842
MD5 532acffedb09211428547db3a92c5276
BLAKE2b-256 6e6c2ce10f05bc9c504e1ec10910cbc62a869c0609c867726073e8aa679276fa

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 2b4ef18ae10a49e060c4079ff5166ac8e7cc21daddfa0a31355d7b0bc37f3fb5
MD5 02d4db29cbbe1f9bafe7ed69bd04f0c7
BLAKE2b-256 af04093a402133a9dcf19e5636a7c94a698c121a9d269d590f917545228d8266

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 420af6c080ae6810f96ee76e067f68bbc00d87bb69a264ca037b6265982eb553
MD5 d22b49fbc69fc5592f622930a065ba23
BLAKE2b-256 0cec559c4f2750a48ad5b635b5b70d80b639a0e36e30285fd6b7061136e783d8

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 e8648c568b2b811fe6411093314867b7667fb43975f5cf3573be1b5048a29e16
MD5 837af5af153fd7ab072166620366cc78
BLAKE2b-256 61f95d99bf710aaf6a3ab607c07f06ecbb756d94ff8ac2114d9584e2c4aa8813

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 ebb1581619d59510725a52ea00849b4f2b3629c04146bab0942d925327903962
MD5 25b7a1d0cd07a90100223c9cb659cd83
BLAKE2b-256 c277f25b9c3ff3083fe028b9adff7077eaeecfa6bf10b49894b4b5d7df6eb4c1

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 38dedbf4825acc645415d12ce41187ff83d551361203fc7f775b80c3e350f0e3
MD5 3d49e73bc2bb608ea51e23f67b03c792
BLAKE2b-256 fe19ab3dcd5f746045aab25af8e5e23dde93d055319c563758c373ec99b3fb86

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl
Algorithm Hash digest
SHA256 de5c2d796e5db6a4903b335e8ef55082c36638ce69cc9adf7520af0873d46247
MD5 c3db9540dd5436e03ad93b00c8f0f9ed
BLAKE2b-256 845d79daa671e92f099d2b57c051d961fca7dc335a9c1b360b5abaf271e39313

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 719dba3b76a2c16c231f63465ae96a0f02f681455bb1b7b48d7715b8a890f6db
MD5 e2cbdb7a57ddea4defb2beed6e48d305
BLAKE2b-256 d26a11f524740ec9c9e4642dbf1c8a5d17c039f63bddfbd331c7516084d1a1c4

See more details on using hashes here.

File details

Details for the file digit_bin_index-0.4.2-cp38-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for digit_bin_index-0.4.2-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f96a6663246cb9eca9446ef32ab5b1411896fe0bbbc4c070fe8de9c5e14883be
MD5 e601a463def5ac588ebec0da18d3274d
BLAKE2b-256 9becfa9a133b53c4ef4d481ba87ee8210a1ee8ff9b45339c2827672459c0e71b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page