Skip to main content

chDB is an in-process SQL OLAP Engine powered by ClickHouse

Project description

Build X86 PyPI Downloads Discord Twitter

chDB

chDB is an in-process SQL OLAP Engine powered by ClickHouse [^1] For more details: The birth of chDB

Features

  • In-process SQL OLAP Engine, powered by ClickHouse
  • No need to install ClickHouse
  • Minimized data copy from C++ to Python with python memoryview
  • Input&Output support Parquet, CSV, JSON, Arrow, ORC and 60+more formats, samples
  • Support Python DB API 2.0, example

Arch

Get Started

Get started with chdb using our Installation and Usage Examples


Installation

Currently, chDB supports Python 3.8+ on macOS and Linux (x86_64 and ARM64).

pip install chdb

Usage

Run in command line

python3 -m chdb SQL [OutputFormat]

python3 -m chdb "SELECT 1,'abc'" Pretty

Data Input

The following methods are available to access on-disk and in-memory data formats:

🗂️ Query On File

(Parquet, CSV, JSON, Arrow, ORC and 60+)

You can execute SQL and return desired format data.

import chdb
res = chdb.query('select version()', 'Pretty'); print(res)

Work with Parquet or CSV

# See more data type format in tests/format_output.py
res = chdb.query('select * from file("data.parquet", Parquet)', 'JSON'); print(res)
res = chdb.query('select * from file("data.csv", CSV)', 'CSV');  print(res)
print(f"SQL read {res.rows_read()} rows, {res.bytes_read()} bytes, elapsed {res.elapsed()} seconds")

Pandas dataframe output

# See more in https://clickhouse.com/docs/en/interfaces/formats
chdb.query('select * from file("data.parquet", Parquet)', 'Dataframe')

🗂️ Query On Table

(Pandas DataFrame, Parquet file/bytes, Arrow bytes)

Query On Pandas DataFrame

import chdb.dataframe as cdf
import pandas as pd
# Join 2 DataFrames
df1 = pd.DataFrame({'a': [1, 2, 3], 'b': ["one", "two", "three"]})
df2 = pd.DataFrame({'c': [1, 2, 3], 'd': ["①", "②", "③"]})
ret_tbl = cdf.query(sql="select * from __tbl1__ t1 join __tbl2__ t2 on t1.a = t2.c",
                  tbl1=df1, tbl2=df2)
print(ret_tbl)
# Query on the DataFrame Table
print(ret_tbl.query('select b, sum(a) from __table__ group by b'))

🗂️ Query with Stateful Session

from chdb import session as chs

## Create DB, Table, View in temp session, auto cleanup when session is deleted.
sess = chs.Session()
sess.query("CREATE DATABASE IF NOT EXISTS db_xxx ENGINE = Atomic")
sess.query("CREATE TABLE IF NOT EXISTS db_xxx.log_table_xxx (x String, y Int) ENGINE = Log;")
sess.query("INSERT INTO db_xxx.log_table_xxx VALUES ('a', 1), ('b', 3), ('c', 2), ('d', 5);")
sess.query(
    "CREATE VIEW db_xxx.view_xxx AS SELECT * FROM db_xxx.log_table_xxx LIMIT 4;"
)
print("Select from view:\n")
print(sess.query("SELECT * FROM db_xxx.view_xxx", "Pretty"))

see also: test_stateful.py.

🗂️ Query with Python DB-API 2.0

import chdb.dbapi as dbapi
print("chdb driver version: {0}".format(dbapi.get_client_info()))

conn1 = dbapi.connect()
cur1 = conn1.cursor()
cur1.execute('select version()')
print("description: ", cur1.description)
print("data: ", cur1.fetchone())
cur1.close()
conn1.close()

🗂️ Query with UDF (User Defined Functions)

from chdb.udf import chdb_udf
from chdb import query

@chdb_udf()
def sum_udf(lhs, rhs):
    return int(lhs) + int(rhs)

print(query("select sum_udf(12,22)"))

Some notes on chDB Python UDF(User Defined Function) decorator.

  1. The function should be stateless. So, only UDFs are supported, not UDAFs(User Defined Aggregation Function).
  2. Default return type is String. If you want to change the return type, you can pass in the return type as an argument. The return type should be one of the following: https://clickhouse.com/docs/en/sql-reference/data-types
  3. The function should take in arguments of type String. As the input is TabSeparated, all arguments are strings.
  4. The function will be called for each line of input. Something like this:
    def sum_udf(lhs, rhs):
        return int(lhs) + int(rhs)
    
    for line in sys.stdin:
        args = line.strip().split('\t')
        lhs = args[0]
        rhs = args[1]
        print(sum_udf(lhs, rhs))
        sys.stdout.flush()
    
  5. The function should be pure python function. You SHOULD import all python modules used IN THE FUNCTION.
    def func_use_json(arg):
        import json
        ...
    
  6. Python interpertor used is the same as the one used to run the script. Get from sys.executable

see also: test_udf.py.

🗂️ Python Table Engine

Query on Pandas DataFrame

import chdb
import pandas as pd
df = pd.DataFrame(
    {
        "a": [1, 2, 3, 4, 5, 6],
        "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"],
    }
)

chdb.query("SELECT b, sum(a) FROM Python(df) GROUP BY b ORDER BY b").show()

Query on Arrow Table

import chdb
import pyarrow as pa
arrow_table = pa.table(
    {
        "a": [1, 2, 3, 4, 5, 6],
        "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"],
    }
)

chdb.query(
    "SELECT b, sum(a) FROM Python(arrow_table) GROUP BY b ORDER BY b", "debug"
).show()

Query on chdb.PyReader class instance

  1. You must inherit from chdb.PyReader class and implement the read method.
  2. The read method should:
    1. return a list of lists, the first demension is the column, the second dimension is the row, the columns order should be the same as the first arg col_names of read.
    2. return an empty list when there is no more data to read.
    3. be stateful, the cursor should be updated in the read method.
  3. An optional get_schema method can be implemented to return the schema of the table. The prototype is def get_schema(self) -> List[Tuple[str, str]]:, the return value is a list of tuples, each tuple contains the column name and the column type. The column type should be one of the following: https://clickhouse.com/docs/en/sql-reference/data-types
import chdb

class myReader(chdb.PyReader):
    def __init__(self, data):
        self.data = data
        self.cursor = 0
        super().__init__(data)

    def read(self, col_names, count):
        print("Python func read", col_names, count, self.cursor)
        if self.cursor >= len(self.data["a"]):
            return []
        block = [self.data[col] for col in col_names]
        self.cursor += len(block[0])
        return block

reader = myReader(
    {
        "a": [1, 2, 3, 4, 5, 6],
        "b": ["tom", "jerry", "auxten", "tom", "jerry", "auxten"],
    }
)

chdb.query(
    "SELECT b, sum(a) FROM Python(reader) GROUP BY b ORDER BY b"
).show()

see also: test_query_py.py.

Limitations

  1. Column types supported: pandas.Series, pyarrow.array, chdb.PyReader
  2. Data types supported: Int, UInt, Float, String, Date, DateTime, Decimal
  3. Python Object type will be converted to String
  4. Pandas DataFrame performance is all of the best, Arrow Table is better than PyReader

For more examples, see examples and tests.


Demos and Examples

Benchmark

Documentation

Events

Contributing

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated. There are something you can help:

  • Help test and report bugs
  • Help improve documentation
  • Help improve code quality and performance

Bindings

We welcome bindings for other languages, please refer to bindings for more details.

Paper

License

Apache 2.0, see LICENSE for more information.

Acknowledgments

chDB is mainly based on ClickHouse [^1] for trade mark and other reasons, I named it chDB.

Contact


[^1]: ClickHouse® is a trademark of ClickHouse Inc. All trademarks, service marks, and logos mentioned or depicted are the property of their respective owners. The use of any third-party trademarks, brand names, product names, and company names does not imply endorsement, affiliation, or association with the respective owners.

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

chdb-2.2.0b0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ ARM64

chdb-2.2.0b0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.2.0b0-cp312-cp312-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.12 macOS 11.0+ ARM64

chdb-2.2.0b0-cp312-cp312-macosx_10_15_x86_64.whl (102.6 MB view details)

Uploaded CPython 3.12 macOS 10.15+ x86-64

chdb-2.2.0b0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ ARM64

chdb-2.2.0b0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.2.0b0-cp311-cp311-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.11 macOS 11.0+ ARM64

chdb-2.2.0b0-cp311-cp311-macosx_10_15_x86_64.whl (102.6 MB view details)

Uploaded CPython 3.11 macOS 10.15+ x86-64

chdb-2.2.0b0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ ARM64

chdb-2.2.0b0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64 manylinux: glibc 2.5+ x86-64

chdb-2.2.0b0-cp310-cp310-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.10 macOS 11.0+ ARM64

chdb-2.2.0b0-cp310-cp310-macosx_10_15_x86_64.whl (102.6 MB view details)

Uploaded CPython 3.10 macOS 10.15+ x86-64

chdb-2.2.0b0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.9 manylinux: glibc 2.17+ ARM64

chdb-2.2.0b0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

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

chdb-2.2.0b0-cp39-cp39-macosx_11_0_arm64.whl (78.1 MB view details)

Uploaded CPython 3.9 macOS 11.0+ ARM64

chdb-2.2.0b0-cp39-cp39-macosx_10_15_x86_64.whl (102.6 MB view details)

Uploaded CPython 3.9 macOS 10.15+ x86-64

chdb-2.2.0b0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (113.8 MB view details)

Uploaded CPython 3.8 manylinux: glibc 2.17+ ARM64

chdb-2.2.0b0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (140.7 MB view details)

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

chdb-2.2.0b0-cp38-cp38-macosx_10_15_x86_64.whl (102.6 MB view details)

Uploaded CPython 3.8 macOS 10.15+ x86-64

File details

Details for the file chdb-2.2.0b0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 372c3851763145de8f00c95a2c4371b3d00e23864b0142f9163346e59cb65231
MD5 eca8e93345445cfbdeb14e80a88f60e5
BLAKE2b-256 17f260f4337332c30b3bef5084f529a172892f83d5b8bbbc5c6dfd709983035d

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 933bc855e77ec5d8361d1c5b8a845a50f21b9ac1d80b78c589f36908d66ae087
MD5 9fa639c74dc7e49c6e70c27dea16de11
BLAKE2b-256 3bc0fc4fe1870a1a329592758f638a4038c4c28b040937d439a102d471f10ca0

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp312-cp312-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp312-cp312-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 93c207cfb3fe5f2278aa1c5ed130ecdfbe49b0bd69a712f19f33e3b9fd88e9ad
MD5 1e8c68146f299f961b34d4074ffbe3bd
BLAKE2b-256 3331f78bff281397b2f237cedc678345e8b42f99f10c71746b13892d78d0ccb3

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp312-cp312-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp312-cp312-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 6c072e67bd32af806790c0d2828b5bbefe05fcd2c365de160a83bbec36971ba6
MD5 a0ca0b5239ada1f1a6fa6b495bae1097
BLAKE2b-256 6f7a40feab86a4bb494b58c197492ea094a2f56efa47da96aef3235f165fc521

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 99322580a2773f9632931abd47eaac79218e63cd6a9d268ae54a1da3f0963eac
MD5 444ff8e142d2786e96a2fba985f3a00d
BLAKE2b-256 75668d19b9013d8733dccf1bf6cc71016a3f9ace567b963a604257d3cde8dade

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 50794ff69c7464192a929df926d4666c9668e2b36488ffe77385874691e62805
MD5 e2ebb39f3ea7b04ae7df169e3ae0d698
BLAKE2b-256 c70d5cfe6ad1facb1e28ac1873950025c4e04954d56795a76a78bab1aeab7eef

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp311-cp311-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp311-cp311-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 91757838db094cd2ba4134726122790760ba411aad8d06b750a233702c990ef0
MD5 1fc5c9145b4c8583d187f96e7f2dc472
BLAKE2b-256 08b831daa5b59d66dba262c49907db3164162bd98b73b2f8e521ee7440f1f542

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp311-cp311-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp311-cp311-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 7acd8dd07de2e30a9c7ddbb77ac78c89c447fc86ac020e5b51d68785ba17d9d1
MD5 fee2177d3d9e6ca974eaa23b9ff29d59
BLAKE2b-256 ae9e6d56494dee1f28691ec7a273dda718993314eebd8a76fb661fccf1421d3a

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 ab0e7ae1b73219d15410dc15309473da89003c044e72c10e695929b091a24dc2
MD5 02e87ae12e1c9c7f8596dd357650845d
BLAKE2b-256 ef512d77108e49885df4c5b6ae2e798cac1b29339195a704b5b8f8d354156940

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 9c23d67259d47731b6b9208620a6b62c5fa09a9480ec65d5a93add3b93e390ef
MD5 98afed5c0780fff7b2a04d463a0dd964
BLAKE2b-256 87ce8002dc3ed042ddbcc7e2cad81eeb6859167fc366f8a46765800e643c2877

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp310-cp310-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp310-cp310-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c22eaaace0fa141a5258738d05586cc9db293b512e666265cd04f06026421627
MD5 9fbb129ab864c5a07eb4b2c614f507d8
BLAKE2b-256 3fad639ebca2ebe33f708b84d067fbd0ef77da7e76f8326ae36ff6b86b4ce691

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp310-cp310-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp310-cp310-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 a313ccb562fbdb20462a3682cf958c7e5a5a79758dc69a1125705676790dd583
MD5 6be2ae40638a2c999c3035030c8dec2f
BLAKE2b-256 fa32b5b81bdae18da2e8934e4130cf01203442956df9dd0f604c88aaade5016b

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 b608a815f0ced62c7aa9fc55e2f904b0a776da18383154d9a926c66e00f93fda
MD5 7cee2843151491a3c71c2fb644b5e03e
BLAKE2b-256 28ecf1ed9738a9bf03678d21fac503df8fb777742376caac5524d2952871250b

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 582150551a39d8fcd41d9a865a26e8b4ec689d091e6a22996e3428a55e6d61e4
MD5 de21ec66c2a71e1f688f351b84787870
BLAKE2b-256 d0f2ec5eb595fb46d0282ca8d6877a2223ff3362a5a77082b18e315277c7432c

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp39-cp39-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp39-cp39-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 8e8d32052277d850ba19a734ceecbbac09bf7af9c97627af2ccb7af243349f3c
MD5 d969d0cec4ceb261819d1e8cad4b3427
BLAKE2b-256 2fb4020530136f836cf4b5f5ad6900499752e56447684633e0c3cd1c9ee10848

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp39-cp39-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp39-cp39-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 56431ae3693635abde6c7ae743d12b7254dad3b1955cefc6eaccf8c0ac24a111
MD5 fdac1b0cbe8929ee35ef15c82ee868e6
BLAKE2b-256 5a892e9c315a1c92180c67390fa324471ab031bf2ba3e2f23656224bf8c17133

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 3dc29783f52eaca483989225bf5e92e818e445887774dfd98b1c9734a5af5a13
MD5 9501929c1b2665c38c8c951507a4072f
BLAKE2b-256 5563d2e55adb45f71202cfcd02da4c1c68ef7c6f138405f1d374b56094d5cb1b

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 259723556b3c69180036f5a00936133027da45bd5040868c9971815e7f11fbd3
MD5 3fad3c14fad01a39c71077db86995983
BLAKE2b-256 f5102cf040dea4f556e9a69b790d38f299310583ad0dd5cdd90a3f29707fa3e5

See more details on using hashes here.

File details

Details for the file chdb-2.2.0b0-cp38-cp38-macosx_10_15_x86_64.whl.

File metadata

File hashes

Hashes for chdb-2.2.0b0-cp38-cp38-macosx_10_15_x86_64.whl
Algorithm Hash digest
SHA256 33551427ca1e96b142c3e21a0a76108c904bae75e30f43eaa66ef26d48b939c6
MD5 b9b48ce828f31e1b3e2caf3109b1a0c5
BLAKE2b-256 453c936528f2efe0644bf6a4d0870b3a4e3562a97f436a19de393958f9c516ce

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