Skip to main content

Fast kd-tree implementation with OpenMP-enabled queries

Project description

https://github.com/storpipfugl/pykdtree/actions/workflows/deploy-wheels.yml/badge.svg?branch=master

pykdtree

Objective

pykdtree is a kd-tree implementation for fast nearest neighbour search in Python. The aim is to be the fastest implementation around for common use cases (low dimensions and low number of neighbours) for both tree construction and queries.

The implementation is based on scipy.spatial.cKDTree and libANN by combining the best features from both and focus on implementation efficiency.

The interface is similar to that of scipy.spatial.cKDTree except only Euclidean distance measure is supported.

Queries are optionally multithreaded using OpenMP.

Installation

Pykdtree can be installed via pip:

pip install pykdtree

Or, if in a conda-based environment, with conda from the conda-forge channel:

conda install -c conda-forge pykdtree

Note that by default these packages (the binary wheels on PyPI and the binary package on conda-forge) are only built with OpenMP for linux platforms. To attempt to build from source with OpenMP support do:

export USE_OMP="probe"
pip install --no-binary pykdtree pykdtree

This may not work on some systems that don’t have OpenMP installed. See the below development instructions for more guidance. Disabling OpenMP can be accomplished by setting USE_OMP to "0" in the above commands.

Development Installation

If you wish to contribute to pykdtree then it is a good idea to install from source so you can quickly see the effects of your changes. By default pykdtree is built with OpenMP enabled queries on unix-like systems. On linux this is done using libgomp. On OSX systems OpenMP is provided using the clang compiler (conda environments use a separate compiler).

$ cd <pykdtree_dir>
$ pip install -e .

This installs pykdtree in an “editable” mode where changes to the Python files are automatically reflected when running a new python interpreter instance (ex. running a python script that uses pykdtree). It does not automatically rebuild or recompile the .mako templates and .pyx Cython code in pykdtree. Editing these files requires running the pykdtree/render_template.py script and then rerunning the pip command above to recompile the Cython files.

If installation fails with undefined compiler flags or you want to use another OpenMP implementation you may need to modify setup.py or specify additional pip command line flags to match the library locations on your system.

Building without OpenMP support is controlled by the USE_OMP environment variable

$ cd <pykdtree_dir>
$ export USE_OMP=0
$ pip install -e .

Note evironment variables are by default not exported when using sudo so in this case do

$ USE_OMP=0 sudo -E pip install -e .

Control OpenMP usage

The USE_OMP variable can be set to one of a couple different options. If set to "probe", the installation process (setup.py) will attempt to determine what variant of OpenMP is available based on the compiler being used, the platform being run on, and the Python environment being run with. It will then use the flags specified by one of the other USE_OMP modes. Note that in the case of MacOS, it will also try to identify if OpenMP is available from macports or homebrew and include the necessary include and library paths.

If set to "gcc" or "gomp" then compiler and linking flags will be set appropriately for “GNU OpenMP” (gomp) library. If set to "clang" or "omp" then the flags will be set to support the “omp” library. If set to "msvc" then flags will be set for the Microsoft Visual C++ compiler’s OpenMP variant. For backwards compatibility the previous "1" has the same behavior as "probe". As mentioned above "0" can be used to disable any detection of OpenMP or attempt to compile with it.

Usage

The usage of pykdtree is similar to scipy.spatial.cKDTree so for now refer to its documentation

>>> from pykdtree.kdtree import KDTree
>>> kd_tree = KDTree(data_pts)
>>> dist, idx = kd_tree.query(query_pts, k=8)

The number of threads to be used in OpenMP enabled queries can be controlled with the standard OpenMP environment variable OMP_NUM_THREADS.

The leafsize argument (number of data points per leaf) for the tree creation can be used to control the memory overhead of the kd-tree. pykdtree uses a default leafsize=16. Increasing leafsize will reduce the memory overhead and construction time but increase query time.

pykdtree accepts data in double precision (numpy.float64) or single precision (numpy.float32) floating point. If data of another type is used an internal copy in double precision is made resulting in a memory overhead. If the kd-tree is constructed on single precision data the query points must be single precision as well.

Benchmarks

Comparison with scipy.spatial.cKDTree and libANN. This benchmark is on geospatial 3D data with 10053632 data points and 4276224 query points. The results are indexed relative to the construction time of scipy.spatial.cKDTree. A leafsize of 10 (scipy.spatial.cKDTree default) is used.

Note: libANN is not thread safe. In this benchmark libANN is compiled with “-O3 -funroll-loops -ffast-math -fprefetch-loop-arrays” in order to achieve optimum performance.

Operation

scipy.spatial.cKDTree

libANN

pykdtree

pykdtree 4 threads

Construction

100

304

96

96

query 1 neighbour

1267

294

223

70

Total 1 neighbour

1367

598

319

166

query 8 neighbours

2193

625

449

143

Total 8 neighbours

2293

929

545

293

Looking at the combined construction and query this gives the following performance improvement relative to scipy.spatial.cKDTree

Neighbours

libANN

pykdtree

pykdtree 4 threads

1

129%

329%

723%

8

147%

320%

682%

Note: mileage will vary with the dataset at hand and computer architecture.

Test

Run the unit tests using pytest

$ cd <pykdtree_dir>
$ pytest

Installing on AppVeyor

Pykdtree requires the “stdint.h” header file which is not available on certain versions of Windows or certain Windows compilers including those on the continuous integration platform AppVeyor. To get around this the header file(s) can be downloaded and placed in the correct “include” directory. This can be done by adding the anaconda/missing-headers.ps1 script to your repository and running it the install step of appveyor.yml:

# install missing headers that aren’t included with MSVC 2008 # https://github.com/omnia-md/conda-recipes/pull/524 - “powershell ./appveyor/missing-headers.ps1”

In addition to this, AppVeyor does not support OpenMP so this feature must be turned off by adding the following to appveyor.yml in the environment section:

environment:
global:

# Don’t build with openmp because it isn’t supported in appveyor’s compilers USE_OMP: “0”

Changelog

v1.3.6 : Fix Python 3.11 compatibility and build Python 3.11 wheels

v1.3.5 : Build Python 3.10 wheels and other CI updates

v1.3.4 : Fix Python 3.9 wheels not being built for linux

v1.3.3 : Add compatibility to python 3.9

v1.3.2 : Change OSX installation to not use OpenMP without conda interpreter

v1.3.1 : Fix masking in the “query” method introduced in 1.3.0

v1.3.0 : Keyword argument “mask” added to “query” method. OpenMP compilation now works for MS Visual Studio compiler

v1.2.2 : Build process fixes

v1.2.1 : Fixed OpenMP thread safety issue introduced in v1.2.0

v1.2.0 : 64 and 32 bit MSVC Windows support added

v1.1.1 : Same as v1.1 release due to incorrect pypi release

v1.1 : Build process improvements. Add data attribute to kdtree class for scipy interface compatibility

v1.0 : Switched license from GPLv3 to LGPLv3

v0.3 : Avoid zipping of installed egg

v0.2 : Reduced memory footprint. Can now handle single precision data internally avoiding copy conversion to double precision. Default leafsize changed from 10 to 16 as this reduces the memory footprint and makes it a cache line multiplum (negligible if any query performance observed in benchmarks). Reduced memory allocation for leaf nodes. Applied patch for building on OS X.

v0.1 : Initial version.

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

pykdtree-1.3.7.tar.gz (84.5 kB view details)

Uploaded Source

Built Distributions

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

pykdtree-1.3.7-cp311-cp311-win_amd64.whl (49.2 kB view details)

Uploaded CPython 3.11Windows x86-64

pykdtree-1.3.7-cp311-cp311-manylinux_2_24_x86_64.whl (269.3 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.24+ x86-64

pykdtree-1.3.7-cp311-cp311-manylinux_2_24_i686.whl (259.5 kB view details)

Uploaded CPython 3.11manylinux: glibc 2.24+ i686

pykdtree-1.3.7-cp311-cp311-macosx_10_9_universal2.whl (103.4 kB view details)

Uploaded CPython 3.11macOS 10.9+ universal2 (ARM64, x86-64)

pykdtree-1.3.7-cp310-cp310-win_amd64.whl (50.3 kB view details)

Uploaded CPython 3.10Windows x86-64

pykdtree-1.3.7-cp310-cp310-manylinux_2_24_x86_64.whl (267.8 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.24+ x86-64

pykdtree-1.3.7-cp310-cp310-manylinux_2_24_i686.whl (261.1 kB view details)

Uploaded CPython 3.10manylinux: glibc 2.24+ i686

pykdtree-1.3.7-cp310-cp310-macosx_11_0_x86_64.whl (62.4 kB view details)

Uploaded CPython 3.10macOS 11.0+ x86-64

pykdtree-1.3.7-cp39-cp39-win_amd64.whl (51.4 kB view details)

Uploaded CPython 3.9Windows x86-64

pykdtree-1.3.7-cp39-cp39-manylinux_2_24_x86_64.whl (276.0 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.24+ x86-64

pykdtree-1.3.7-cp39-cp39-manylinux_2_24_i686.whl (268.0 kB view details)

Uploaded CPython 3.9manylinux: glibc 2.24+ i686

pykdtree-1.3.7-cp39-cp39-macosx_11_0_x86_64.whl (62.6 kB view details)

Uploaded CPython 3.9macOS 11.0+ x86-64

pykdtree-1.3.7-cp38-cp38-win_amd64.whl (51.2 kB view details)

Uploaded CPython 3.8Windows x86-64

pykdtree-1.3.7-cp38-cp38-manylinux_2_24_x86_64.whl (289.1 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.24+ x86-64

pykdtree-1.3.7-cp38-cp38-manylinux_2_24_i686.whl (279.9 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.24+ i686

pykdtree-1.3.7-cp38-cp38-macosx_10_15_x86_64.whl (61.8 kB view details)

Uploaded CPython 3.8macOS 10.15+ x86-64

pykdtree-1.3.7-cp37-cp37m-win_amd64.whl (50.3 kB view details)

Uploaded CPython 3.7mWindows x86-64

pykdtree-1.3.7-cp37-cp37m-manylinux_2_24_x86_64.whl (270.8 kB view details)

Uploaded CPython 3.7mmanylinux: glibc 2.24+ x86-64

pykdtree-1.3.7-cp37-cp37m-manylinux_2_24_i686.whl (261.7 kB view details)

Uploaded CPython 3.7mmanylinux: glibc 2.24+ i686

pykdtree-1.3.7-cp37-cp37m-macosx_10_15_x86_64.whl (61.0 kB view details)

Uploaded CPython 3.7mmacOS 10.15+ x86-64

File details

Details for the file pykdtree-1.3.7.tar.gz.

File metadata

  • Download URL: pykdtree-1.3.7.tar.gz
  • Upload date:
  • Size: 84.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.2

File hashes

Hashes for pykdtree-1.3.7.tar.gz
Algorithm Hash digest
SHA256 9106174a0b0ce5097516c0f0a27fbaf4c12da2fd35dbd59b1a64bfd57319ecd5
MD5 20b696332427b4e37e7d1b57396809b1
BLAKE2b-256 22c46bc4ed87946a197431ac22e78fec602995b819914bbd86759a0407409531

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: pykdtree-1.3.7-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 49.2 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.2

File hashes

Hashes for pykdtree-1.3.7-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 192b7006e0658b3e261b66bc7e8dadabdb245dbb2d462ad0d761897ad9bd814e
MD5 8a014a70605ba8ba1b4cc2c2b57e8746
BLAKE2b-256 46c1a9313488810e254b1bf825d880c6114a5102c38ebc47e64348ac13426b52

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp311-cp311-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp311-cp311-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 ade9296c66620ad4fd4b4301f778a7eb7b2d7e5d981ee481de83664143a93ac1
MD5 9bd78c18a700c136535a9a6e8d5acef1
BLAKE2b-256 7c8fe13d20a89c7d9326b68d2b25e84712af018a3f272f15539d5736348a9d02

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp311-cp311-manylinux_2_24_i686.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp311-cp311-manylinux_2_24_i686.whl
Algorithm Hash digest
SHA256 e0c013705cdd1a27a5d1c109f67974f9de4eb2a4ebb01c1ad9930b641385124b
MD5 cfc70bab6fd47dbd50a98cdcf4d1ad7a
BLAKE2b-256 0ba4858611cfc2ebe76492e1db96f6ddcb2558f7b3222cfb7cb3875b77d17360

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp311-cp311-macosx_10_9_universal2.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp311-cp311-macosx_10_9_universal2.whl
Algorithm Hash digest
SHA256 4d13c32c0911fb408813bbd74a52503e926e76152f2959ef554fef99328c9fd2
MD5 7c1a0feb62ca1e3c57ecf824f8b7b13b
BLAKE2b-256 00848bb2cfd6eec9c94f03f4ed7141561187e852522d179beed671757d28fc0d

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: pykdtree-1.3.7-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 50.3 kB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.2

File hashes

Hashes for pykdtree-1.3.7-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 87ea71d72892aa08db383f8d69d6fac92e8b42a0980dfcaff8080fec41fb7294
MD5 a6810513215a9d44a67bcd3cb261ccc0
BLAKE2b-256 406f82fd69d34434b65671ed9adae6d18074bb81058a37f3af035c1839d5b4f3

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp310-cp310-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp310-cp310-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 40521fba7365c88c554946e13fefe83eab355f48666d384ffa6f7f89c8354d02
MD5 8d719ff6e00017d76003e6d2aae570a5
BLAKE2b-256 5b0b056cbd832d173cce49cc1f8a5b14441b4d50eeffda239572b225a262b967

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp310-cp310-manylinux_2_24_i686.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp310-cp310-manylinux_2_24_i686.whl
Algorithm Hash digest
SHA256 e15c1242f102779ffaaf1dbacae9925826e5d5569a45fce3bbafd19140f31a58
MD5 a21005752e07c71a946966beace292de
BLAKE2b-256 e22f5173c532a349421c7e2aac5c96d321d221bd75af48554d4528fd1d4c22ce

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp310-cp310-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp310-cp310-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 0ec13062f15aa28890f1860ea6761f7a26c7a2468c5789f7506acd8d16ee9705
MD5 6a79ac3248ff1ea5d4e66d9536124080
BLAKE2b-256 9c78c461610a8446f50aff67f6786287e1a9a5a73dec228e0f87d7ae9237c3cc

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: pykdtree-1.3.7-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 51.4 kB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.2

File hashes

Hashes for pykdtree-1.3.7-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 834447c11d59bed0a2f4213c9208d6c6736414e55a0eca0506a75038f911ed7f
MD5 593f71eb11475fbb5b9fbb9236e3090a
BLAKE2b-256 d8f6f0ee9f2e4b1fb6e2bbdd0d4b8d810cd744c9e9376d798b5db745fcecb02d

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp39-cp39-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp39-cp39-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 27e293f1d994c879219c1278b80a1b91175c42479e494383e62e9dd3872c9192
MD5 0c1e7d12507ab9744d8f63aec1c9ef47
BLAKE2b-256 521af63b7b525fde3c7dbf672dfdd3b7ed96280c5ffdf87a3e02fb08626be2ac

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp39-cp39-manylinux_2_24_i686.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp39-cp39-manylinux_2_24_i686.whl
Algorithm Hash digest
SHA256 435a0631bdd348d0b4506b2ab326db93e426842fe653ec67b388d7709d2cf182
MD5 f06843c8bdaf02d173803b6f1712dd4d
BLAKE2b-256 d2d3b95892404e1d7207adae5b6493b09442d931adc69a92df29bdc2f7d3bf92

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp39-cp39-macosx_11_0_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp39-cp39-macosx_11_0_x86_64.whl
Algorithm Hash digest
SHA256 936ea2a58f78694774850d8093b6f55fb88a3664527521c192dafc3d6cb994fa
MD5 b64ba351f28313f66b53e91b282319a6
BLAKE2b-256 0ca7662f40107eafaac6e4643df1cc7406cfaee9553ef79fbbbd92b4cbd02b19

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: pykdtree-1.3.7-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 51.2 kB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.2

File hashes

Hashes for pykdtree-1.3.7-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 d7877d4919ccaa28f323cd22f4686b2158a8ac06ce42a20fc03ad258d3cb4a9f
MD5 bb8f121021685f53050b0e14a15365dd
BLAKE2b-256 1bfd335c311904d89cb9af21c066c89b3e5be945580802ffabc7a8b4828d5dab

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp38-cp38-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp38-cp38-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 89cbda9edb87c6d987183c2e92d3e4a746d6c4687c7a73d48fb29d648e1af485
MD5 cd928792d4cbd07222fa3e04d8071991
BLAKE2b-256 533329d468f09aae78d83fc9b7a5ca7fe7aea1e5e76e26ab7c0fba2d6130b971

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp38-cp38-manylinux_2_24_i686.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp38-cp38-manylinux_2_24_i686.whl
Algorithm Hash digest
SHA256 f8b7556d31b93f0960580ec860b0ecd0da45a03932430c6b28b14649a7049a42
MD5 e1b6ff47f076150fdf79ca336f64ba24
BLAKE2b-256 5434b56d59e2df596d12fb72664515dd2ab1e88811af4a7e62fc7403be53c7bd

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp38-cp38-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp38-cp38-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 881e3316b5b693eec451143a8456ec824b9e090f8ea9b916a51391807679e878
MD5 6f00b5678eb7795b3741b90d098f64fe
BLAKE2b-256 e649c59fc4bb11a974be036d84c6b74dd887c141a15533d8859e7a0ddabde187

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp37-cp37m-win_amd64.whl.

File metadata

  • Download URL: pykdtree-1.3.7-cp37-cp37m-win_amd64.whl
  • Upload date:
  • Size: 50.3 kB
  • Tags: CPython 3.7m, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.11.2

File hashes

Hashes for pykdtree-1.3.7-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 aec79d1a5f871f1837fa5722ca38a403bb06bbb61f70e51658af9561ae09f81b
MD5 6ae9d7da146853b1ae06d9cd663870c7
BLAKE2b-256 121850bc2dc4a5d43ec9b450a45111726a0a6b3a817735aa51b7714affbdced6

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp37-cp37m-manylinux_2_24_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp37-cp37m-manylinux_2_24_x86_64.whl
Algorithm Hash digest
SHA256 9cd2d8f75b1a4b7e5ea4de16c438ff89acb23506c637aa6f8162f43e1ee7fbc9
MD5 9a46fcec2bf5b1eed2497c1cdcaaadf6
BLAKE2b-256 16bf04544e98536d4a8d8cf3a446b45f15c4e2a77f06dade3e32e18e93998d2d

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp37-cp37m-manylinux_2_24_i686.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp37-cp37m-manylinux_2_24_i686.whl
Algorithm Hash digest
SHA256 3875948f16e49e32532e6f5fda8bc85b336353a8bd10978458bbfda3f4828ebf
MD5 e0cd18444bb9f8f885db517c763e2fc4
BLAKE2b-256 6527b8dd490ff12bc994556e73aa0d6c384b94902fd5b4090ca61d3b60fc4175

See more details on using hashes here.

File details

Details for the file pykdtree-1.3.7-cp37-cp37m-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for pykdtree-1.3.7-cp37-cp37m-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 84d80e7235764a56887d99099bf5737621b2b20209f7c2d545bd8e72ec2dedf7
MD5 9f558a01ca0e017d7bddec7c39bdf711
BLAKE2b-256 e4e9627f3a808f4d5ee8093d900b2f7bd21f81e72944f29edd06e23b27725c7d

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