Skip to main content

Python binding to Omikuji, an efficient implementation of Partioned Label Trees and its variations for extreme multi-label classification

Project description

Omikuji

Build Status Crate version PyPI version

An efficient implementation of Partitioned Label Trees (Prabhu et al., 2018) and its variations for extreme multi-label classification, written in Rust🦀 with love💖.

Features & Performance

Omikuji has has been tested on datasets from the Extreme Classification Repository. All tests below are run on a quad-core Intel® Core™ i7-6700 CPU, and we allowed as many cores to be utilized as possible. We measured training time, and calculated precisions at 1, 3, and 5. (Note that, due to randomness, results might vary from run to run, especially for smaller datasets.)

Parabel, better parallelized

Omikuji provides a more parallelized implementation of Parabel (Prabhu et al., 2018) that trains faster when more CPU cores are available. Compared to the original implementation written in C++, which can only utilize the same number of CPU cores as the number of trees (3 by default), Omikuji maintains the same level of precision but trains 1.3x to 1.7x faster on our quad-core machine. Further speed-up is possible if more CPU cores are available.

Dataset Metric Parabel Omikuji
(balanced,
cluster.k=2)
EURLex-4K P@1 82.2 82.1
P@3 68.8 68.8
P@5 57.6 57.7
Train Time 18s 14s
Amazon-670K P@1 44.9 44.8
P@3 39.8 39.8
P@5 36.0 36.0
Train Time 404s 234s
WikiLSHTC-325K P@1 65.0 64.8
P@3 43.2 43.1
P@5 32.0 32.1
Train Time 959s 659s

Regular k-means for shallow trees

Following Bonsai (Khandagale et al., 2019), Omikuji supports using regular k-means instead of balanced 2-means clustering for tree construction, which results in wider, shallower and unbalanced trees that train slower but have better precision. Comparing to the original Bonsai implementation, Omikuji also achieves the same precisions while training 2.6x to 4.6x faster on our quad-core machine. (Similarly, further speed-up is possible if more CPU cores are available.)

Dataset Metric Bonsai Omikuji
(unbalanced,
cluster.k=100,
max_depth=3)
EURLex-4K P@1 82.8 83.0
P@3 69.4 69.5
P@5 58.1 58.3
Train Time 87s 19s
Amazon-670K P@1 45.5* 45.6
P@3 40.3* 40.4
P@5 36.5* 36.6
Train Time 5,759s 1,753s
WikiLSHTC-325K P@1 66.6* 66.6
P@3 44.5* 44.4
P@5 33.0* 33.0
Train Time 11,156s 4,259s

*Precision numbers as reported in the paper; our machine doesn't have enough memory to run the full prediction with their implementation.

Balanced k-means for balanced shallow trees

Sometimes it's desirable to have shallow and wide trees that are also balanced, in which case Omikuji supports the balanced k-means algorithm used by HOMER (Tsoumakas et al., 2008) for clustering as well.

Dataset Metric Omikuji
(balanced,
cluster.k=100)
EURLex-4K P@1 82.1
P@3 69.4
P@5 58.1
Train Time 19s
Amazon-670K P@1 45.4
P@3 40.3
P@5 36.5
Train Time 1,153s
WikiLSHTC-325K P@1 65.6
P@3 43.6
P@5 32.5
Train Time 3,028s

Layer collapsing for balanced shallow trees

An alternative way for building balanced, shallow and wide trees is to collapse adjacent layers, similar to the tree compression step used in AttentionXML (You et al., 2019): intermediate layers are removed, and their children replace them as the children of their parents. For example, with balanced 2-means clustering, if we collapse 5 layers after each layer, we can increase the tree arity from 2 to 2⁵⁺¹ = 64.

Dataset Metric Omikuji
(balanced,
cluster.k=2,
collapse 5 layers)
EURLex-4K P@1 82.4
P@3 69.3
P@5 58.0
Train Time 16s
Amazon-670K P@1 45.3
P@3 40.2
P@5 36.4
Train Time 460s
WikiLSHTC-325K P@1 64.9
P@3 43.3
P@5 32.3
Train Time 1,649s

Build & Install

Omikuji can be easily built & installed with Cargo as a CLI app:

cargo install omikuji --features cli

Or install from the latest source:

cargo install --git https://github.com/tomtung/omikuji.git --features cli

The CLI app will be available as omikuji. For example, to reproduce the results on the EURLex-4K dataset:

omikuji train eurlex_train.txt --model_path ./model
omikuji test ./model eurlex_test.txt --out_path predictions.txt

Python Binding

A simple Python binding is also available for training and prediction. It can be install via pip:

pip install omikuji

Note that you might still need to install Cargo should compilation become necessary.

You can also install from the latest source:

pip install git+https://github.com/tomtung/omikuji.git -v

The following script demonstrates how to use the Python binding to train a model and make predictions:

import omikuji

# Train
hyper_param = omikuji.Model.default_hyper_param()
# Adjust hyper-parameters as needed
hyper_param.n_trees = 5
model = omikuji.Model.train_on_data("./eurlex_train.txt", hyper_param)

# Serialize & de-serialize
model.save("./model")
model = omikuji.Model.load("./model")
# Optionally densify model weights to trade off between prediction speed and memory usage
model.densify_weights(0.05)

# Predict
feature_value_pairs = [
    (0, 0.101468),
    (1, 0.554374),
    (2, 0.235760),
    (3, 0.065255),
    (8, 0.152305),
    (10, 0.155051),
    # ...
]
label_score_pairs =  model.predict(feature_value_pairs)

Usage

$ omikuji train --help
omikuji-train
Train a new model

USAGE:
    omikuji train [FLAGS] [OPTIONS] <TRAINING_DATA_PATH>

FLAGS:
        --cluster.unbalanced     Perform regular k-means clustering instead of balanced k-means clustering
    -h, --help                   Prints help information
        --train_trees_1_by_1     Finish training each tree before start training the next; limits initial
                                 parallelization but saves memory
        --tree_structure_only    Build the trees without training classifiers; useful when a downstream user needs the
                                 tree structures only
    -V, --version                Prints version information

OPTIONS:
        --centroid_threshold <THRESHOLD>         Threshold for pruning label centroid vectors [default: 0]
        --cluster.eps <EPS>                      Epsilon value for determining clustering convergence [default: 0.0001]
        --cluster.k <K>                          Number of clusters [default: 2]
        --cluster.min_size <SIZE>
            Labels in clusters with sizes smaller than this threshold are reassigned to other clusters instead [default:
            2]
        --collapse_every_n_layers <N>
            Number of adjacent layers to collapse, which increases tree arity and decreases tree depth [default: 0]

        --linear.c <C>                           Cost co-efficient for regularizing linear classifiers [default: 1]
        --linear.eps <EPS>
            Epsilon value for determining linear classifier convergence [default: 0.1]

        --linear.loss <LOSS>
            Loss function used by linear classifiers [default: hinge]  [possible values: hinge, log]

        --linear.max_iter <M>
            Max number of iterations for training each linear classifier [default: 20]

        --linear.weight_threshold <THRESHOLD>
            Threshold for pruning weight vectors of linear classifiers [default: 0.1]

        --max_depth <DEPTH>                      Maximum tree depth [default: 20]
        --min_branch_size <SIZE>
            Number of labels below which no further clustering & branching is done [default: 100]

        --model_path <PATH>
            Optional path of the directory where the trained model will be saved if provided; if an model with
            compatible settings is already saved in the given directory, the newly trained trees will be added to the
            existing model
        --n_threads <T>
            Number of worker threads. If 0, the number is selected automatically [default: 0]

        --n_trees <N>                            Number of trees [default: 3]

ARGS:
    <TRAINING_DATA_PATH>    Path to training dataset file (in the format of the Extreme Classification Repository)
$ omikuji test --help
omikuji-test
Test an existing model

USAGE:
    omikuji test [OPTIONS] <MODEL_PATH> <TEST_DATA_PATH>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
        --beam_size <beam_size>           Beam size for beam search [default: 10]
        --k_top <K>                       Number of top predictions to write out for each test example [default: 5]
        --max_sparse_density <DENSITY>    Density threshold above which sparse weight vectors are converted to dense
                                          format. Lower values speed up prediction at the cost of more memory usage
                                          [default: 0.1]
        --n_threads <T>                   Number of worker threads. If 0, the number is selected automatically [default:
                                          0]
        --out_path <PATH>                 Path to the which predictions will be written, if provided

ARGS:
    <MODEL_PATH>        Path of the directory where the trained model is saved
    <TEST_DATA_PATH>    Path to test dataset file (in the format of the Extreme Classification Repository)

Data format

Our implementation takes dataset files formatted as those provided in the Extreme Classification Repository. A data file starts with a header line with three space-separated integers: total number of examples, number of features, and number of labels. Following the header line, there is one line per each example, starting with comma-separated labels, followed by space-separated feature:value pairs:

label1,label2,...labelk ft1:ft1_val ft2:ft2_val ft3:ft3_val .. ftd:ftd_val

Trivia

The project name comes from o-mikuji (御神籤), which are predictions about one's future written on strips of paper (labels?) at jinjas and temples in Japan, often tied to branches of pine trees after they are read.

References

  • Y. Prabhu, A. Kag, S. Harsola, R. Agrawal, and M. Varma, “Parabel: Partitioned Label Trees for Extreme Classification with Application to Dynamic Search Advertising,” in Proceedings of the 2018 World Wide Web Conference, 2018, pp. 993–1002.
  • S. Khandagale, H. Xiao, and R. Babbar, “Bonsai - Diverse and Shallow Trees for Extreme Multi-label Classification,” Apr. 2019.
  • G. Tsoumakas, I. Katakis, and I. Vlahavas, “Effective and efficient multilabel classification in domains with large number of labels,” ECML, 2008.
  • R. You, S. Dai, Z. Zhang, H. Mamitsuka, and S. Zhu, “AttentionXML: Extreme Multi-Label Text Classification with Multi-Label Attention Based Recurrent Neural Networks,” Jun. 2019.

License

Omikuji is licensed under the MIT License.

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

omikuji-0.4.0.tar.gz (49.7 kB view details)

Uploaded Source

Built Distributions

omikuji-0.4.0-cp39-cp39-win_amd64.whl (363.4 kB view details)

Uploaded CPython 3.9 Windows x86-64

omikuji-0.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (823.2 kB view details)

Uploaded CPython 3.9 manylinux: glibc 2.12+ x86-64 manylinux: glibc 2.5+ x86-64

omikuji-0.4.0-cp39-cp39-macosx_10_15_x86_64.whl (470.2 kB view details)

Uploaded CPython 3.9 macOS 10.15+ x86-64

omikuji-0.4.0-cp38-cp38-win_amd64.whl (363.4 kB view details)

Uploaded CPython 3.8 Windows x86-64

omikuji-0.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (823.2 kB view details)

Uploaded CPython 3.8 manylinux: glibc 2.12+ x86-64 manylinux: glibc 2.5+ x86-64

omikuji-0.4.0-cp38-cp38-macosx_10_15_x86_64.whl (470.2 kB view details)

Uploaded CPython 3.8 macOS 10.15+ x86-64

omikuji-0.4.0-cp37-cp37m-win_amd64.whl (363.4 kB view details)

Uploaded CPython 3.7m Windows x86-64

omikuji-0.4.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (823.2 kB view details)

Uploaded CPython 3.7m manylinux: glibc 2.12+ x86-64 manylinux: glibc 2.5+ x86-64

omikuji-0.4.0-cp37-cp37m-macosx_10_15_x86_64.whl (470.2 kB view details)

Uploaded CPython 3.7m macOS 10.15+ x86-64

omikuji-0.4.0-cp36-cp36m-win_amd64.whl (363.4 kB view details)

Uploaded CPython 3.6m Windows x86-64

omikuji-0.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (823.2 kB view details)

Uploaded CPython 3.6m manylinux: glibc 2.12+ x86-64 manylinux: glibc 2.5+ x86-64

omikuji-0.4.0-cp36-cp36m-macosx_10_15_x86_64.whl (470.2 kB view details)

Uploaded CPython 3.6m macOS 10.15+ x86-64

File details

Details for the file omikuji-0.4.0.tar.gz.

File metadata

  • Download URL: omikuji-0.4.0.tar.gz
  • Upload date:
  • Size: 49.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0.tar.gz
Algorithm Hash digest
SHA256 b799e05c890e4cfa8514b08e6218a870dc2bac3b18a3cc9d8088697b802a5c43
MD5 8bf88b99ca89d611f2bb027084686fc8
BLAKE2b-256 c3902a6b6d6d1f8dfc6aa6b8628cabe0a2177673a7445027533507b703a5c1ad

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 363.4 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 673bbfe71aa761fba33c1735849389da8e07bb42aa62568e63fb9325df3d6f57
MD5 f28560ebd92f8ce8131b792d99beb0d3
BLAKE2b-256 8c920787f9771ef786c760a0d61fad4162458c1c4d000f8dc1862d8e357573c0

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for omikuji-0.4.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 ecd1374fc9f3f6855fa796f340beca60caa4a82004c99051c00e2895d8ea36e2
MD5 cc0b856d97da5397df5a17c6c5a3fed1
BLAKE2b-256 e8b439b84e3f00106c84626fe7dcd350c08623101edfc1c7ce65126c7c1e7871

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp39-cp39-macosx_10_15_x86_64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp39-cp39-macosx_10_15_x86_64.whl
  • Upload date:
  • Size: 470.2 kB
  • Tags: CPython 3.9, macOS 10.15+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp39-cp39-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 03835e918840869d1b5cfbcb131e6e1de40388d45647cbf7ec5ff508db3265e4
MD5 224714c77aff075eaa68190e427b4f03
BLAKE2b-256 f5ea9e5931655b497ad96a264394eb7fa4c1edadfb51a5dc67dfec8525a62762

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 363.4 kB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 a0598fa165b2077b0da307feded5e351f27afe0c153f1e91dad2df30e93b99f7
MD5 05cc1d3e5771d110dc96f6b71d73d4cd
BLAKE2b-256 91b70897824e9cd0546905330780db76687d619de2a650ac4f86dfe9bc02d566

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for omikuji-0.4.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 391788d0978c816967404e47802ae56ebf1e46d15da2b71cb32cc2bc6ecc230e
MD5 7b502da608af5c7e45f867168a6da40f
BLAKE2b-256 9f134dfbc2f9b613bd58f15cde15997559df3d022bc0ed73ea8b969715b982de

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp38-cp38-macosx_10_15_x86_64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp38-cp38-macosx_10_15_x86_64.whl
  • Upload date:
  • Size: 470.2 kB
  • Tags: CPython 3.8, macOS 10.15+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp38-cp38-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 0ab326d262e93769d72382618efbe9809dff40286166210f4fad9763a8090253
MD5 8622d96a5d1c0b875873a7e177b23b8b
BLAKE2b-256 71563754235d01567d4d4407ee51a73dc4118a38619afb74924c391591d4ce7e

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp37-cp37m-win_amd64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp37-cp37m-win_amd64.whl
  • Upload date:
  • Size: 363.4 kB
  • Tags: CPython 3.7m, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 99ef3c398a50a62a12f64a5cc8f12a2943eb813c1fc73f2139616441e5b42b9d
MD5 f35ba03fedfe52c1eaa9a905656573ab
BLAKE2b-256 12dc65601990daa57b15f2e626880870abf5a1c47a1c626b0214c28c7c3052aa

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for omikuji-0.4.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 b28f5984346dfdb266697a60e65f9ffe2da76637313f024ff6feebbcda93457c
MD5 44f568b285fb43e49ebafaac2cbf046f
BLAKE2b-256 c6c731097bce82d5ec4b334d7c984557c1f0e24017e6a466cde1867b70a9a4bc

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp37-cp37m-macosx_10_15_x86_64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp37-cp37m-macosx_10_15_x86_64.whl
  • Upload date:
  • Size: 470.2 kB
  • Tags: CPython 3.7m, macOS 10.15+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp37-cp37m-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 96b7db0343ab31daaf022901d201d934bd2f39b6ba2e4e58aa76e6e429dd7a49
MD5 f785587992596d8d9561ce8e1ab47a04
BLAKE2b-256 2c3cf123540c3574238c7ea2d5e1c598f95c7b6e2bfb5c9a41a212c3e8cb987e

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp36-cp36m-win_amd64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp36-cp36m-win_amd64.whl
  • Upload date:
  • Size: 363.4 kB
  • Tags: CPython 3.6m, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp36-cp36m-win_amd64.whl
Algorithm Hash digest
SHA256 aaf8669fc959b564cff9be5e2e2505c6c699ee8b0e9a099524dfcb457b52d9b7
MD5 dafda2c8b348d5352a59204bc91093d6
BLAKE2b-256 1d81dd01b0e444dd813137b66618049dbe3e29b4f54b304ac1c73eeae90d4f0b

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.

File metadata

File hashes

Hashes for omikuji-0.4.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl
Algorithm Hash digest
SHA256 5008d1d0f289afb568922501ac96aa1d8d923f7840d115bb50cd9e130c3d1ef9
MD5 5ed77971c25ab38afa7571d536de72e1
BLAKE2b-256 1d2d0d171b5ec430bd0589555a358a945bb70521dc77748f6f8e4ba32c74408a

See more details on using hashes here.

File details

Details for the file omikuji-0.4.0-cp36-cp36m-macosx_10_15_x86_64.whl.

File metadata

  • Download URL: omikuji-0.4.0-cp36-cp36m-macosx_10_15_x86_64.whl
  • Upload date:
  • Size: 470.2 kB
  • Tags: CPython 3.6m, macOS 10.15+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.8.2 requests/2.22.0 setuptools/45.2.0 requests-toolbelt/0.9.1 tqdm/4.62.3 CPython/3.8.10

File hashes

Hashes for omikuji-0.4.0-cp36-cp36m-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 be2c17a71f2e0f9f75dc2100581958cefaae6f0bb671673e46f454884b76a186
MD5 db5a4023bbb19db5cf3cb018cc69f9d6
BLAKE2b-256 29b7ca295a788445000a1f38c1e542aca6bf5cdbc8b169f2ce4bf5161b8500a9

See more details on using hashes here.

Supported by

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