Skip to main content

A Vectorized Dictionary for Python

Project description

phashmap - A Vectorized Python Dict/Set

phashmap is a copy of GetPy(https://github.com/atom-moyer/getpy), to provide the highest performance python dict/set that integrates into the python scientific ecosystem for Linux and Windows.

Installation

pip install phashmap

Linux and Windows build is currently distributed. If you would like to build the package from source you can clone the repo and run python setup.py install. Compilation will require 16gb of ram. I am working on getting that down.

About

GetPy is a thin binding to the Parallel Hashmap (https://github.com/greg7mdp/parallel-hashmap.git) which is the current state of the art unordered map/set with minimal memory overhead and fast runtime speed. The binding layer is supported by PyBind11 (https://github.com/pybind/pybind11.git) which is fast to compile and simple to extend.

How To Use

The gp.Dict and gp.Set objects are designed to maintain a similar interface to the corresponding standard python objects. There are some key differences though, which are necessary for vectorization and other performance considerations.

  1. gp.Dict.__init__ has three arguments key_type, value_type, and default_value. The type arguments are define which compiled data structure will be used under the hood, and the full list of preset combinations of np.dtypes is found with gp.dict_types. You can also specify a default_value at construction which must be castable to the value_type. This is the value returned by the dictionary if a key is not found.

  2. All of getpy.Dict methods support a vectorized interface. Therefore, methods like gp.Dict.__getitem__, gp.Dict.__setitem__, and gp.Dict.__delitem__ can be performed with an np.ndarray. That allows the performance critical for-loop to happen within the compiled c++. Note that some dunder methods cannot be vectorized such as __contains__. Therefore, some keywords like in do not behave as expected. Those methods are renamed without the double underscores to note their deviation from the standard interface.

  3. If a key does not exist, gp.Dict.__getitem__ will return the default_value. If you do not specify the default_value, it will default to the default constructor of your data type (all 0 bits). If you would like to know the difference between a key that does not exist and a key that returns the default value, you should first run gp.contains on your key/array of keys, and then retrieve values corresponding to keys that exist.

  4. There is also a gp.MultiDict object. This object stores multiple unique values per key.

Examples

Simple Example

import numpy as np
import phashmap as gp

key_type = np.dtype('u8')
value_type = np.dtype('u8')

keys = np.random.randint(1, 1000, size=10 ** 2, dtype=key_type)
values = np.random.randint(1, 1000, size=10 ** 2, dtype=value_type)

gp_dict = gp.Dict(key_type, value_type)
gp_dict[keys] = values

Default Example

import numpy as np
import phashmap as gp

key_type = np.dtype('u8')
value_type = np.dtype('u8')

keys = np.random.randint(1, 1000, size=10 ** 2, dtype=key_type)
values = np.random.randint(1, 1000, size=10 ** 2, dtype=value_type)

gp_dict = gp.Dict(key_type, value_type, default_value=42)
gp_dict[keys] = values

random_keys = np.random.randint(1, 1000, size=500, dtype=key_type)
random_values = gp_dict[random_keys]

Byteset Example

import numpy as np
import phashmap as gp

key_type = np.dtype('S8')
value_type = np.dtype('S8')

keys = np.array([np.random.bytes(8) for i in range(10 ** 2)], dtype=key_type)
values = np.array([np.random.bytes(8) for i in range(10 ** 2)], dtype=value_type)

gp_dict = gp.Dict(key_type, value_type)
gp_dict[keys] = values

Multidimensional Example

import numpy as np
import phashmap as gp

key_type = np.dtype('u8')
value_type = np.dtype('u8')

keys = np.random.randint(1, 1000, size=10 ** 2, dtype=key_type).reshape(10, 10)
values = np.random.randint(1, 1000, size=10 ** 2, dtype=value_type).reshape(10, 10)

gp_dict = gp.Dict(key_type, value_type)
gp_dict[keys] = values

Bitpack Example

import numpy as np
import phashmap as gp

key_type = np.dtype('u8')
value_type = np.dtype('u8')

keys = np.random.randint(1, 1000, size=10 ** 2, dtype=np.dtype('u2')).reshape(25, 4).view(key_type)
values = np.random.randint(1, 1000, size=(10 ** 2) / 2, dtype=np.dtype('u4')).reshape(25, 2).view(value_type)

gp_dict = gp.Dict(key_type, value_type)
gp_dict[keys] = values

unpacked_values = gp_dict[keys].view(np.dtype('u4'))

Serialization Example

import numpy as np
import phashmap as gp

key_type = np.dtype('u8')
value_type = np.dtype('u8')

keys = np.random.randint(1, 1000, size=10 ** 1, dtype=key_type)
values = np.random.randint(1, 1000, size=10 ** 1, dtype=value_type)

gp_dict_1 = gp.Dict(key_type, value_type)
gp_dict_1[keys] = values
gp_dict_1.dump('test/test.hashtable.bin')

gp_dict_2 = gp.Dict(key_type, value_type)
gp_dict_2.load('test/test.hashtable.bin')

Supported Data Types

dict_types = {
    (np.dtype('u4'), np.dtype('u1')) : _gp.Dict_u4_u1,
    (np.dtype('u4'), np.dtype('u2')) : _gp.Dict_u4_u2,
    (np.dtype('u4'), np.dtype('u4')) : _gp.Dict_u4_u4,
    (np.dtype('u4'), np.dtype('u8')) : _gp.Dict_u4_u8,
    (np.dtype('u4'), np.dtype('i1')) : _gp.Dict_u4_i1,
    (np.dtype('u4'), np.dtype('i2')) : _gp.Dict_u4_i2,
    (np.dtype('u4'), np.dtype('i4')) : _gp.Dict_u4_i4,
    (np.dtype('u4'), np.dtype('i8')) : _gp.Dict_u4_i8,
    (np.dtype('u4'), np.dtype('f4')) : _gp.Dict_u4_f4,
    (np.dtype('u4'), np.dtype('f8')) : _gp.Dict_u4_f8,
    (np.dtype('u4'), np.dtype('S8')) : _gp.Dict_u4_S8,
    (np.dtype('u4'), np.dtype('S16')) : _gp.Dict_u4_S16,
    (np.dtype('u8'), np.dtype('u1')) : _gp.Dict_u8_u1,
    (np.dtype('u8'), np.dtype('u2')) : _gp.Dict_u8_u2,
    (np.dtype('u8'), np.dtype('u4')) : _gp.Dict_u8_u4,
    (np.dtype('u8'), np.dtype('u8')) : _gp.Dict_u8_u8,
    (np.dtype('u8'), np.dtype('i1')) : _gp.Dict_u8_i1,
    (np.dtype('u8'), np.dtype('i2')) : _gp.Dict_u8_i2,
    (np.dtype('u8'), np.dtype('i4')) : _gp.Dict_u8_i4,
    (np.dtype('u8'), np.dtype('i8')) : _gp.Dict_u8_i8,
    (np.dtype('u8'), np.dtype('f4')) : _gp.Dict_u8_f4,
    (np.dtype('u8'), np.dtype('f8')) : _gp.Dict_u8_f8,
    (np.dtype('u8'), np.dtype('S8')) : _gp.Dict_u8_S8,
    (np.dtype('u8'), np.dtype('S16')) : _gp.Dict_u8_S16,
    (np.dtype('i4'), np.dtype('u1')) : _gp.Dict_i4_u1,
    (np.dtype('i4'), np.dtype('u2')) : _gp.Dict_i4_u2,
    (np.dtype('i4'), np.dtype('u4')) : _gp.Dict_i4_u4,
    (np.dtype('i4'), np.dtype('u8')) : _gp.Dict_i4_u8,
    (np.dtype('i4'), np.dtype('i1')) : _gp.Dict_i4_i1,
    (np.dtype('i4'), np.dtype('i2')) : _gp.Dict_i4_i2,
    (np.dtype('i4'), np.dtype('i4')) : _gp.Dict_i4_i4,
    (np.dtype('i4'), np.dtype('i8')) : _gp.Dict_i4_i8,
    (np.dtype('i4'), np.dtype('f4')) : _gp.Dict_i4_f4,
    (np.dtype('i4'), np.dtype('f8')) : _gp.Dict_i4_f8,
    (np.dtype('i4'), np.dtype('S8')) : _gp.Dict_i4_S8,
    (np.dtype('i4'), np.dtype('S16')) : _gp.Dict_i4_S16,
    (np.dtype('i8'), np.dtype('u1')) : _gp.Dict_i8_u1,
    (np.dtype('i8'), np.dtype('u2')) : _gp.Dict_i8_u2,
    (np.dtype('i8'), np.dtype('u4')) : _gp.Dict_i8_u4,
    (np.dtype('i8'), np.dtype('u8')) : _gp.Dict_i8_u8,
    (np.dtype('i8'), np.dtype('i1')) : _gp.Dict_i8_i1,
    (np.dtype('i8'), np.dtype('i2')) : _gp.Dict_i8_i2,
    (np.dtype('i8'), np.dtype('i4')) : _gp.Dict_i8_i4,
    (np.dtype('i8'), np.dtype('i8')) : _gp.Dict_i8_i8,
    (np.dtype('i8'), np.dtype('f4')) : _gp.Dict_i8_f4,
    (np.dtype('i8'), np.dtype('f8')) : _gp.Dict_i8_f8,
    (np.dtype('i8'), np.dtype('S8')) : _gp.Dict_i8_S8,
    (np.dtype('i8'), np.dtype('S16')) : _gp.Dict_i8_S16,
    (np.dtype('S8'), np.dtype('u1')) : _gp.Dict_S8_u1,
    (np.dtype('S8'), np.dtype('u2')) : _gp.Dict_S8_u2,
    (np.dtype('S8'), np.dtype('u4')) : _gp.Dict_S8_u4,
    (np.dtype('S8'), np.dtype('u8')) : _gp.Dict_S8_u8,
    (np.dtype('S8'), np.dtype('i1')) : _gp.Dict_S8_i1,
    (np.dtype('S8'), np.dtype('i2')) : _gp.Dict_S8_i2,
    (np.dtype('S8'), np.dtype('i4')) : _gp.Dict_S8_i4,
    (np.dtype('S8'), np.dtype('i8')) : _gp.Dict_S8_i8,
    (np.dtype('S8'), np.dtype('f4')) : _gp.Dict_S8_f4,
    (np.dtype('S8'), np.dtype('f8')) : _gp.Dict_S8_f8,
    (np.dtype('S8'), np.dtype('S8')) : _gp.Dict_S8_S8,
    (np.dtype('S8'), np.dtype('S16')) : _gp.Dict_S8_S16,
    (np.dtype('S16'), np.dtype('u1')) : _gp.Dict_S16_u1,
    (np.dtype('S16'), np.dtype('u2')) : _gp.Dict_S16_u2,
    (np.dtype('S16'), np.dtype('u4')) : _gp.Dict_S16_u4,
    (np.dtype('S16'), np.dtype('u8')) : _gp.Dict_S16_u8,
    (np.dtype('S16'), np.dtype('i1')) : _gp.Dict_S16_i1,
    (np.dtype('S16'), np.dtype('i2')) : _gp.Dict_S16_i2,
    (np.dtype('S16'), np.dtype('i4')) : _gp.Dict_S16_i4,
    (np.dtype('S16'), np.dtype('i8')) : _gp.Dict_S16_i8,
    (np.dtype('S16'), np.dtype('f4')) : _gp.Dict_S16_f4,
    (np.dtype('S16'), np.dtype('f8')) : _gp.Dict_S16_f8,
    (np.dtype('S16'), np.dtype('S8')) : _gp.Dict_S16_S8,
    (np.dtype('S16'), np.dtype('S16')) : _gp.Dict_S16_S16,
}

set_types = {
    np.dtype('u4') : _gp.Set_u4,
    np.dtype('u8') : _gp.Set_u8,
    np.dtype('i4') : _gp.Set_i4,
    np.dtype('i8') : _gp.Set_i8,
    np.dtype('S8') : _gp.Set_S8,
    np.dtype('S16') : _gp.Set_S16,
}

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

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

phashmap-0.0.4-cp313-cp313-win_amd64.whl (3.1 MB view details)

Uploaded CPython 3.13Windows x86-64

phashmap-0.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (92.1 MB view details)

Uploaded CPython 3.13manylinux: glibc 2.17+ x86-64

phashmap-0.0.4-cp312-cp312-win_amd64.whl (3.1 MB view details)

Uploaded CPython 3.12Windows x86-64

phashmap-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (92.2 MB view details)

Uploaded CPython 3.12manylinux: glibc 2.17+ x86-64

phashmap-0.0.4-cp311-cp311-win_amd64.whl (2.9 MB view details)

Uploaded CPython 3.11Windows x86-64

phashmap-0.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (91.0 MB view details)

Uploaded CPython 3.11manylinux: glibc 2.17+ x86-64

phashmap-0.0.4-cp310-cp310-win_amd64.whl (3.1 MB view details)

Uploaded CPython 3.10Windows x86-64

phashmap-0.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (91.0 MB view details)

Uploaded CPython 3.10manylinux: glibc 2.17+ x86-64

phashmap-0.0.4-cp39-cp39-win_amd64.whl (2.4 MB view details)

Uploaded CPython 3.9Windows x86-64

phashmap-0.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (91.0 MB view details)

Uploaded CPython 3.9manylinux: glibc 2.17+ x86-64

phashmap-0.0.4-cp38-cp38-win_amd64.whl (3.0 MB view details)

Uploaded CPython 3.8Windows x86-64

phashmap-0.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (91.0 MB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

phashmap-0.0.4-cp37-cp37m-win_amd64.whl (1.9 MB view details)

Uploaded CPython 3.7mWindows x86-64

phashmap-0.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (97.0 MB view details)

Uploaded CPython 3.7mmanylinux: glibc 2.17+ x86-64

File details

Details for the file phashmap-0.0.4-cp313-cp313-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp313-cp313-win_amd64.whl
  • Upload date:
  • Size: 3.1 MB
  • Tags: CPython 3.13, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp313-cp313-win_amd64.whl
Algorithm Hash digest
SHA256 e3b1a9ac3c8445fab6748e2aedbc26498ba59952149d6911f4c5ebc808f7416a
MD5 f3fed761c591f41df4e0addd80d56015
BLAKE2b-256 61894631523d23159758b1b07602449ced38df98948234bb9a0aadca78f02af1

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 df19597244cd9e7def6aff885c47fc1ba29d1e599692165d4dbd557a3b3488e7
MD5 88fe5215609137363011a9eff325f661
BLAKE2b-256 4fea44efb74ba82d3302e5bffbde644e4bc0ca0074b14c35c52382fcc83baf8f

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp312-cp312-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp312-cp312-win_amd64.whl
  • Upload date:
  • Size: 3.1 MB
  • Tags: CPython 3.12, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp312-cp312-win_amd64.whl
Algorithm Hash digest
SHA256 abd2ea9f1cf5c3f106fad1bf9892987bf8295c3082ab7215d2e739da880b272a
MD5 e406bc9e057a9e6812a65dc3cb7fcf58
BLAKE2b-256 4c5d6d32f0cc4d36a430925a3d3961bdfef8dde6160944986c94619f87ec3196

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 62aa7bda0a885ecb955a137b6737612af0d2a22c4c960ec9a68fe04f192a2c13
MD5 6db73a1ce3ce2e00cbe1c82f00eabe35
BLAKE2b-256 58ebe43dc4f1b1b37cc59fafa06f00410781e6200b5ee64fe0ac701e44f5a6a0

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 2.9 MB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 046b1c5d6353d071952d9e6db4741a2225c1a22bf22963a36a33a78b00eaa41d
MD5 afedfeb9b80d020fca79799d7b9e9c2d
BLAKE2b-256 64f14ff515cd9beca4da6126373f26bce0730016db788a9fbe03735ef0914f42

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 deb58abd1603e2b6927477f8b102811b9576fa50db46f81ce7b4ad9a6273dada
MD5 6baafa8d7c665c436472748f1b0ce112
BLAKE2b-256 438c9c4ff21cf7e45e9df0d6d0e500a536a062de12635923d83d32232f92503a

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp310-cp310-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp310-cp310-win_amd64.whl
  • Upload date:
  • Size: 3.1 MB
  • Tags: CPython 3.10, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp310-cp310-win_amd64.whl
Algorithm Hash digest
SHA256 9bbf0b5f60969f360e0f1ef7940ab4ce8880b8c23b4454eed7b72389dd2cf5c7
MD5 b4adaa811d4e15d030783971f94342c8
BLAKE2b-256 152b512ae5c55fe5ab7691578608bf22643888649c83937e68b796dd6536d249

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 3b32b6bde3ef620bb41bc1abd2c74b1cb9c6329f90021b2f0968ffc2b131b92b
MD5 0f192cfc69ecb6d83e966d681c70debb
BLAKE2b-256 36081f791f060343265ba3933770b22897be1929b92ab635195c2424fc03da16

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp39-cp39-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp39-cp39-win_amd64.whl
  • Upload date:
  • Size: 2.4 MB
  • Tags: CPython 3.9, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp39-cp39-win_amd64.whl
Algorithm Hash digest
SHA256 3c894325b0290444f1924e548051699d2cc391b12f0e2b3885966c6352762e9a
MD5 5963cc7c17e858a93ee9ad4f4e09a1ab
BLAKE2b-256 5da29585ca135bce664afb32d0987435d1a11c8d5abf5d40678b42b4689eed91

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6eca97fb399a5a2a7b17d28dd4b83f548dceb19a374741b09bc21540e7a671a2
MD5 72c0612d1a53800a77906de7364821b4
BLAKE2b-256 894d58c57814120b15d0895933c01faa9549378a9b5b5307796a9ebc9748f66b

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp38-cp38-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp38-cp38-win_amd64.whl
  • Upload date:
  • Size: 3.0 MB
  • Tags: CPython 3.8, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp38-cp38-win_amd64.whl
Algorithm Hash digest
SHA256 23b17647795ef015045e0f0670f26e8f6fa71f4569e12006e4c7c2e9b78812c6
MD5 418643123db54c0cb7d0ace63c0c0c3c
BLAKE2b-256 e653d5bd3ef0b95b0d189328ee7d2fde06a8327dd5917b7f21d48ada807fb49d

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fca8f838a721f85136dac3576901933289fe1922dd6392a081196575c7505b0b
MD5 f677da8c48e3906d112b9b5d26e52f1f
BLAKE2b-256 ed67e09b831da78edaef40ec909d99b37eb32b2538831d397ca73b4ffac1f98b

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp37-cp37m-win_amd64.whl.

File metadata

  • Download URL: phashmap-0.0.4-cp37-cp37m-win_amd64.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: CPython 3.7m, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/5.1.1 CPython/3.11.9

File hashes

Hashes for phashmap-0.0.4-cp37-cp37m-win_amd64.whl
Algorithm Hash digest
SHA256 3866eac56fa54c1b00bf2db4e4d26e3d14db95dc87b8fd285747536ff7f188ac
MD5 707a57b44be4a8cff4e4c2f55c03aefa
BLAKE2b-256 277cba9af670a3139483864e776258fc577b2db90e71784e3310d37619e028b9

See more details on using hashes here.

File details

Details for the file phashmap-0.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for phashmap-0.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 46e0e2b61b0999eb7d6e682bcaf2b79940a0b6f8935d977d853bdd8015fadce9
MD5 808a5f5eda46c6d301d02a2c17b02ff8
BLAKE2b-256 362e25d0c96def802725965acb5b93be383ed8d1f467256d3c822c93a6df34d6

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