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.1.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.1-cp38-abi3-win_amd64.whl (178.7 kB view details)

Uploaded CPython 3.8+Windows x86-64

digit_bin_index-0.4.1-cp38-abi3-win32.whl (176.3 kB view details)

Uploaded CPython 3.8+Windows x86

digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_x86_64.whl (475.9 kB view details)

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

digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_i686.whl (508.4 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ i686

digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_armv7l.whl (583.8 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARMv7l

digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_aarch64.whl (475.4 kB view details)

Uploaded CPython 3.8+musllinux: musl 1.2+ ARM64

digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (305.9 kB view details)

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

digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl (359.0 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ s390x

digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl (339.9 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ppc64le

digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl (319.6 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARMv7l

digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (296.1 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.17+ ARM64

digit_bin_index-0.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl (329.4 kB view details)

Uploaded CPython 3.8+manylinux: glibc 2.5+ i686

digit_bin_index-0.4.1-cp38-abi3-macosx_11_0_arm64.whl (268.9 kB view details)

Uploaded CPython 3.8+macOS 11.0+ ARM64

digit_bin_index-0.4.1-cp38-abi3-macosx_10_12_x86_64.whl (286.0 kB view details)

Uploaded CPython 3.8+macOS 10.12+ x86-64

File details

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

File metadata

  • Download URL: digit_bin_index-0.4.1.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.1.tar.gz
Algorithm Hash digest
SHA256 c9fb5dbd2120eef798f04a0375c9c21064adfaee7f2c52245a1ec294db90b260
MD5 1019221f9140f90db2ac2a503ffa5a88
BLAKE2b-256 a8e4293eda3d34b15a60b5d5452e5fe18a13189cfd74609e7a29aea2aa9d8c36

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 1a02328c68c6de5b0ffd526f656ac7ff33fbe8cb513b6c26c04c37121ae5425b
MD5 adac0f7e9b212dd6d276b52280ed02f0
BLAKE2b-256 884a64c61c490b118f8ef17d5f555b20fcffcc798f7a90088ba2730b1bd9f96d

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-win32.whl
Algorithm Hash digest
SHA256 91ffeebe2a95b360b8cfd7077278509478d4917b95f62c7d00a70910e174634e
MD5 18481cea4506a4a74fb324f627719050
BLAKE2b-256 7492950ca30bf390ade44ebf6fe3dccbe66cb62b3c7bb126f5f4800d95605675

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_x86_64.whl
Algorithm Hash digest
SHA256 501b68435d52e6518db484ea6f1388e95f295457d465c4c76a8bb4f6a0682708
MD5 ddf98aa83e5049a00f272118e8b9bc8b
BLAKE2b-256 c36c5c2f5f3c92631e2467c9b4d618723e7f3a850b7b3b8a683a88dd22e7f467

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_i686.whl
Algorithm Hash digest
SHA256 b38cc1d6ace10c4460ad3a6821485c24a297005248dc41ff1ff58189670ec467
MD5 b0006132eaf28dce80aba37816032aee
BLAKE2b-256 5bf4e6a18b90da899a1e914ff48b0e5f9fa438e69d8eabc4776b698dd24e9173

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_armv7l.whl
Algorithm Hash digest
SHA256 d81b9a76ddb755723fd7e6ddab9a6786ed815474d8c2d298e2dfd00958db449b
MD5 4f338d0856dd28e4950ea6052521edd8
BLAKE2b-256 89233324548389356af5d77be851ff5545cbe5a5b670d3212cc09290ded92382

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-musllinux_1_2_aarch64.whl
Algorithm Hash digest
SHA256 ded6db0abbbf786fbdf3718a75ca04218ae42406018c2bdacfacd9c1e2dbbc15
MD5 8d36ff58e0b200a97167653a2756e1cc
BLAKE2b-256 c72071d60e9bfd5a194173c4da2592e55e3229e8056d344175e3f48808724544

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 537bef8a3dffb4dcc312459910f7f7cd5774923c285a79cbefa6567d74b0271e
MD5 5222cdca9f34a002972e01e3597cf854
BLAKE2b-256 5263947382cd445899b9d6266cf39254fc1939c136c6e8dca4ef0a8301d8fc1e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl
Algorithm Hash digest
SHA256 67d2ef37e0fbc778faca5e0837e2f71075114361e51c397d218c3ca5918d0af8
MD5 08a1d5bae48904575f6cc2829f4fc3e3
BLAKE2b-256 57be585f0e5ba8a924cb9b94ecc8307dfa9c5ae4d367cb2dd3cfd9d233d38505

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl
Algorithm Hash digest
SHA256 5f6a8d75116ccb754f332fc5df7cee7bcc951b0dd6ea202e87764a7af25702e6
MD5 d9829352f25c9c54d4e872940f5b5116
BLAKE2b-256 c995caa3d6c3af2afcf37261f58a5e6b333050fb1bb260325e8a0bb38323027f

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl
Algorithm Hash digest
SHA256 de2c1920d7015758b52f381ac3255bc4304eaaec5f5c68eca2629655c630a663
MD5 e9a341aed3ba1e61ba87205c5d218563
BLAKE2b-256 eb7d447284555d3afcf1e997d0875e7f338e58356483136aea7156564810ab9b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 f617288292686dc90bb3dced69db33ab4897ddf3e059189e6fe1432341d812bc
MD5 0e7ab520f463e01063c464dbe8c4a221
BLAKE2b-256 664c5b1ec0dd5283defea3fd4b0ebb8b1b146508536b4ef627b71f76e92f49c4

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl
Algorithm Hash digest
SHA256 6265e00754b150867fd6fdec8a57e73ec8cfb3492d94ecb6e78c649578651923
MD5 2b7f89b865e798ae5a9f868decd5ce3a
BLAKE2b-256 a916a0b621cbf7f5500deddec7eed348402eb2d0f45fe0f5d2588946d680df1b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 2867cae021670ee11e168a28f504cc0f09bc57d6fdda8e92748d968f07b197af
MD5 18bcad11311fa96060a8d997e12acf67
BLAKE2b-256 f79f1b3275a9ecfa8011408ed8a25bdef322a19d390bde51144b0a307da6073a

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for digit_bin_index-0.4.1-cp38-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 5d5f0b8573962e74b561187634d265d781faa41f23bc14fd45ed4cb9542f7a7e
MD5 c26b98cd3ef7deaa468270f6acc80f51
BLAKE2b-256 c8e9f0194d8620d0f11a2b300e9284be28b1711b1508d41ee5daedfe4e3cd498

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