Skip to main content

A neuron morphology IO library

Project description

MorphIO Build Status

Table of content

Installation

Dependencies

To build MorphIO from sources, the following dependencies are required:

  • cmake >= 3.2
  • libhdf5-dev
  • A C++11 compiler

Debian:

sudo apt install cmake libhdf5-dev

Red Hat:

sudo yum install cmake3.x86_64 hdf5-devel.x86_64

Max OS:

brew install hdf5 cmake

BB5

source /opt/rh/rh-python36/enable
module load gcc/5.4.0 nix/cmake/3.9.6

Installation instructions

Install as a C++ library

For manual installation:

git clone git@github.com:bluebrain/morphio.git --recursive
cd morphio
mkdir build && cd build
cmake ..
make

To use the installed library:

find_package(MorphIO REQUIRED)

target_link_libraries(mylib MorphIO::morphio)

Install as a Python package

The python binding can directly be installed using pip:

pip install morphio

Introduction

MorphIO is a library for reading and writing neuron morphology files. It supports the following formats:

  • SWC
  • ASC (aka. neurolucida)
  • H5 v1
  • H5 v2

It provides 3 classes that are the starting point of every morphology analysis:

  • Soma: contains the information related to the soma

  • Section: a section is the succession of points between two bifurcation. To the bare minimum the Section object will contain the section type, the position and diameter of each point.

  • Morphology: the morphology object will contain general information about the loaded cell but will also provide accessors to the different section.

One important concept is that MorphIO is splitted into a read-only part and a read/write one.

Quick summary

C++ vs Python:

  • C++ accessors become python properties
  • style: C++ functions are camel case while python ones are snake case

Include/imports

  • C++ mutable
#include <morphio/morphology.h>
#include <morphio/section.h>
#include <morphio/soma.h>
  • Python mutable
from morphio import Morphology, Section, Soma
  • C++ immutable
#include <morphio/mut/morphology.h>
#include <morphio/mut/section.h>
#include <morphio/mut/soma.h>
  • Python immutable
from morphio.mut import Morphology, Section, Soma

Read-only API

The read-only API aims at providing better performances as its internal data representation is contiguous in memory. All accessors return immutable objects.

Internally, in this API the morphology object is in fact where all data are stored. The Soma and Section classes are lightweight classes that provide views on the Morphology data.

For more convenience, all section data are accessed through properties, such as:

points = section.points
diameters = section.diameters

C++

In C++ the API is available under the morphio/mut namespace:

#include <morphio/mut/morphology.h>
#include <morphio/mut/section.h>
#include <morphio/mut/soma.h>

Python

In Python the API is available under the morphio.mut module:

from morphio.mut import Morphology, Section, Soma

Mutable Read/Write API

C++

#include <morphio/morphology.h>
#include <morphio/section.h>

int main()
{
    auto m = morphio::Morphology("sample.asc");

    auto roots = m.rootSections();

    auto first_root = roots[0];

    // iterate on sections starting at first_root
    for(auto it = first_root.depth_begin(); it != first_root.depth_end(); ++it) {
        const morphio::Section &section = (*it);

        std::cout << "Section type: " << section.type() << std::endl;
        std::cout << "Section id: " << section.id() << std::endl;
        std::cout << "Parent section id: " << section.parent().id() << std::endl;
        std::cout << "Number of child sections: " << section.children().size() << std::endl;
        std::cout << "X - Y - Z - Diameter" << std::endl;
        for(int i = 0; i<section.points().size(); ++i) {
            std::cout <<
                section.points()[i][0] << ' ' <<
                section.points()[i][1] << ' ' <<
                section.points()[i][2] << ' ' <<
                section.diameters()[i] << std::endl;
        }

        std::cout << std::endl;
    }
}

Python

from morphio import Morphology

m = Morphology("sample.asc")
roots = m.rootSections
first_root = roots[0]

# iterate on sections starting at first_root
for section in first_root.iter():
    print("Section type: {}".format(section.type))
    print("Section id: {}".format(section.id))
    print("Parent section id: {}".format(section.parent.id))
    print("Number of child sections: {}".format(len(section.children)))
    print("X - Y - Z - Diameter")

    for point, diameter in zip(section.points, section.diameters):
        print('{} - {}'.format(point, diameter))

Creating morphologies with the mutable API

Here is a simple example to create a morphology from scratch and writing it to disk

#include <morphio/mut/morphology.h>

int main()
{
    morphio::mut::Morphology morpho;
    morpho.soma()->points() = {{0, 0, 0}, {1, 1, 1}};
    morpho.soma()->diameters() = {1, 1};

    std::shared_ptr<morphio::mut::Section> section = morpho.appendRootSection(
        morphio::Property::PointLevel(
            {{2, 2, 2}, {3, 3, 3}}, // x,y,z coordinates of each point
            {4, 4}, // diameter of each point
            {5, 5}),
        morphio::SectionType::SECTION_AXON); // (optional) perimeter of each point

    std::shared_ptr<morphio::mut::Section> childSection = section.appendSection(
        morphio::Property::PointLevel(
            {{3, 3, 3}, {4, 4, 4}},
            {4, 4},
            {5, 5}),
        morphio::SectionType::SECTION_AXON);

    // Writing the file in the 3 formats
    morpho.write("outfile.asc");
    morpho.write("outfile.swc");
    morpho.write("outfile.h5");
}

Mutable Python

Reading morphologies

from morphio.mut import Morphology

m = Morphology("sample.asc")
roots = m.root_sections
first_root = roots[0]

# iterate on sections starting at first_root
for section in m.iter(first_root):
    print("Section type: {}".format(section.type))
    print("Section id: {}".format(section.id))
    if not m.is_root(section):
        print("Parent section id: {}".format(m.parent(section)))
    print("Number of child sections: {}".format(len(m.children(section))))
    print("X - Y - Z - Diameter")

    for point, diameter in zip(section.points, section.diameters):
        print('{} - {}'.format(point, diameter))

Creating morphologies

Here is a simple example to create a morphology from scratch and writing it to disk

from morphio.mut import Morphology
from morphio import SectionType, PointLevel

morpho = Morphology()
morpho.soma.points = [[0, 0, 0], [1, 1, 1]]
morpho.soma.diameters = [1, 1]

section = morpho.append_root_section(
    PointLevel(
        [[2, 2, 2], [3, 3, 3]],  # x, y, z coordinates of each point
        [4, 4],  # diameter of each point
        [5, 5]),
    SectionType.axon)  # (optional) perimeter of each point

child_section = section.append_section(
    PointLevel(
        [[3, 3, 3], [4, 4, 4]],
        [4, 4],
        [5, 5])) # section type is omitted -> parent section type will be used

morpho.write("outfile.asc")
morpho.write("outfile.swc")
morpho.write("outfile.h5")

Opening flags

When opening the file, modifier flags can be passed to alter the morphology representation. The following flags are supported:

  • morphio::NO_MODIFIER: This is the default flag, it will do nothing.
  • morphio::TWO_POINTS_SECTIONS: Each section gets reduce to a line made of the first and last point.
  • morphio::SOMA_SPHERE: The soma is reduced to a sphere which is the center of gravity of the real soma.
  • morphio::NO_DUPLICATES: The duplicate point are not present. It means the first point of each section is no longer the last point of the parent section.
  • morphio::NRN_ORDER: Neurite are reordered according to the NEURON simulator ordering

Multiple flags can be passed by using the standard bit flag manipulation (works the same way in C++ and Python): C++:

#include <morphio/Morphology.h>
Morphology("myfile.asc", options=morphio::NO_DUPLICATES|morphio::NRN_ORDER)

Python:

from morphio import Morphology, Option
Morphology("myfile.asc", options=Option.no_duplicates|Option.nrn_order)

Mitochondria

It is also possible to read and write mitochondria from/to the h5 files (SWC and ASC are not supported). As mitochondria can be represented as trees, one can define the concept of mitochondrial section similar to neuronal section and end up with a similar API. The morphology object has a mitochondria handle method that exposes the basic methods:

  • root_sections: returns the section ID of the starting mitochondrial section of each mitochondrion.
  • section(id): returns a given mitochondrial section
  • append_section: creates a new mitochondrial section _ depth_begin: a depth first iterator _ breadth_begin: a breadth first iterator _ upstream_begin: an upstream iterator
from morphio.mut import Morphology
from morphio import MitochondriaPointLevel, PointLevel, SectionType

morpho = Morphology()

# A neuronal section that will store mitochondria
section = morpho.append_root_section(
    PointLevel([[2, 2, 2], [3, 3, 3]], [4, 4], [5, 5]),
    SectionType.axon)

# Creating a new mitochondrion
mito_id = morpho.mitochondria.append_section(
    -1,
    MitochondriaPointLevel([section.id, section.id], # section id hosting the mitochondria point
                           [0.5, 0.6], # relative distance between the start of the section and the point
                           [10, 20] # mitochondria diameters
                           ))

# Appending a new mitochondrial section to the previous one
morpho.mitochondria.append_section(
    mito_id, MitochondriaPointLevel([0, 0, 0, 0],
                                    [0.6, 0.7, 0.8, 0.9],
                                    [20, 30, 40, 50]))

# Iteration works the same as iteration on neuronal sections
first_root = morpho.mitochondria.root_sections[0]
for section_id in morpho.mitochondria.depth_begin(first_root):
    section = morpho.mitochondria.section(section_id)
    print('relative_path_length - diameter')
    for relative_path_length, diameter in zip(section.diameters,
                                              section.relative_path_lengths):
        print("{} - {}".format(relative_path_length, diameter))

Reading mithochondria from H5 files:

from morphio import Morphology

morpho = Morphology("file_with_mithochondria.h5")

for mitochondrial_section in morpho.mitochondria.root_sections:
    print('{neurite_id}, {relative_path_lengths}, {diameters}'.format(
          neurite_id=mitochondrial_section.neurite_section_ids,
          relative_path_lengths=mitochondrial_section.relative_path_lengths,
          diameters=mitochondrial_section.diameters))

    print("Number of children: {}".format(len(mitochondrial_section.children)))

Tips

Maximum number of warnings

On can control the maximum number of warnings using the command:

# Will stop displaying warnings after 100 warnings
morphio.set_maximum_warnings(100)

# Will never stop displaying warnings
morphio.set_maximum_warnings(-1)

# Warnings won't be displayed
morphio.set_maximum_warnings(0)

Specification

See https://github.com/BlueBrain/MorphIO/blob/master/doc/specification.md

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

MorphIO-2.3.4-cp38-cp38-manylinux1_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.8

MorphIO-2.3.4-cp38-cp38-manylinux1_i686.whl (2.0 MB view details)

Uploaded CPython 3.8

MorphIO-2.3.4-cp38-cp38-macosx_10_9_x86_64.whl (508.0 kB view details)

Uploaded CPython 3.8 macOS 10.9+ x86-64

MorphIO-2.3.4-cp37-cp37m-manylinux1_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.7m

MorphIO-2.3.4-cp37-cp37m-manylinux1_i686.whl (2.0 MB view details)

Uploaded CPython 3.7m

MorphIO-2.3.4-cp37-cp37m-macosx_10_9_x86_64.whl (496.5 kB view details)

Uploaded CPython 3.7m macOS 10.9+ x86-64

MorphIO-2.3.4-cp36-cp36m-manylinux1_x86_64.whl (2.1 MB view details)

Uploaded CPython 3.6m

MorphIO-2.3.4-cp36-cp36m-manylinux1_i686.whl (2.0 MB view details)

Uploaded CPython 3.6m

MorphIO-2.3.4-cp36-cp36m-macosx_10_9_x86_64.whl (496.4 kB view details)

Uploaded CPython 3.6m macOS 10.9+ x86-64

MorphIO-2.3.4-cp27-cp27mu-manylinux1_x86_64.whl (2.1 MB view details)

Uploaded CPython 2.7mu

MorphIO-2.3.4-cp27-cp27mu-manylinux1_i686.whl (2.0 MB view details)

Uploaded CPython 2.7mu

MorphIO-2.3.4-cp27-cp27m-macosx_10_9_x86_64.whl (499.9 kB view details)

Uploaded CPython 2.7m macOS 10.9+ x86-64

File details

Details for the file MorphIO-2.3.4-cp38-cp38-manylinux1_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp38-cp38-manylinux1_x86_64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: CPython 3.8
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp38-cp38-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 bbb3689d70ab4485883a3c70a2fbdc79bd7ca5f56118708576217bd3bdcf093d
MD5 274eddf21ea3bc2b6d46e05c5107c5fe
BLAKE2b-256 da8131aa10ae2a6d482584c5ff13c64a8923a4fb6de1944e93993f660f9d6c95

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp38-cp38-manylinux1_i686.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp38-cp38-manylinux1_i686.whl
  • Upload date:
  • Size: 2.0 MB
  • Tags: CPython 3.8
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp38-cp38-manylinux1_i686.whl
Algorithm Hash digest
SHA256 673470825765bbfee9d4014b998bb92ec12bf0bfa225838dfb808a01d9881ed9
MD5 81a05db570ae7075e4757d6f6b0a9b60
BLAKE2b-256 97a8508afd5f7c71d5d205e78c7567638efdef0d98b1b80515ebbebadc53ebcf

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp38-cp38-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp38-cp38-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 508.0 kB
  • Tags: CPython 3.8, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.8.1

File hashes

Hashes for MorphIO-2.3.4-cp38-cp38-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 a29da6ec77354b1900d6852ec161fd248d9058a87bce1f779112edc9a06c62dc
MD5 83fc2ccbad2c3669c6855d84ae012045
BLAKE2b-256 d77a689d40e6f4b1cbbf6055cdccb409456091815a06756056fe4c023df99409

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp37-cp37m-manylinux1_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp37-cp37m-manylinux1_x86_64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: CPython 3.7m
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp37-cp37m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 144a91db460fc0bc22e4d5c3b0461aeab32ab4b3e9f8fead8532f76827dbe33c
MD5 ed9eb846c146f5217ed7eaca7b2ee13d
BLAKE2b-256 7249a6d5bc2ad7febeda77e17fb94c9d5360c4e9a17f28e3768f3658c3552290

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp37-cp37m-manylinux1_i686.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp37-cp37m-manylinux1_i686.whl
  • Upload date:
  • Size: 2.0 MB
  • Tags: CPython 3.7m
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp37-cp37m-manylinux1_i686.whl
Algorithm Hash digest
SHA256 b918cc9d7e539d8eb47e7c6dc71c446d2ce2fcfcf67f00a9cd69f6b12e2d736f
MD5 c1692038ec9e789ffda97ac82da0eeaa
BLAKE2b-256 3ce010a30b90d7f9b7f52245eefdf86575658b41e4d473a160d9c12303c2c14e

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp37-cp37m-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp37-cp37m-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 496.5 kB
  • Tags: CPython 3.7m, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.7.6

File hashes

Hashes for MorphIO-2.3.4-cp37-cp37m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 87e3f32ecdb2c61644917c92cab11cd0d0476325867ea7f9cdf555c36e487dc0
MD5 591b3d97dd723b4ba348a156645cef81
BLAKE2b-256 04323c7e9a805db42fdd8db2b6acd42440458365fd2b36cd2297845ce442e5f2

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp36-cp36m-manylinux1_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp36-cp36m-manylinux1_x86_64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: CPython 3.6m
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp36-cp36m-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 6f77ac4015ce18f7234d62a8faf93a27a532f88fb14adb9d769dcf97a571753a
MD5 22d8a5bab3f5f7256fff7be62f82898e
BLAKE2b-256 4f4122123658079792853b8e1763e5aab146a9697221959d591dda2047bdab32

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp36-cp36m-manylinux1_i686.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp36-cp36m-manylinux1_i686.whl
  • Upload date:
  • Size: 2.0 MB
  • Tags: CPython 3.6m
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp36-cp36m-manylinux1_i686.whl
Algorithm Hash digest
SHA256 f3f903d2f288625addc3dd1c25b9f14d13f8cb45dc839f332d6b8571e8e2f09a
MD5 5d029c863e21f836d400749a5985807b
BLAKE2b-256 999fead5f740bf003a8f7d26890e8d7ced04320d1fe7eb791c03a526bbbab3fe

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp36-cp36m-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp36-cp36m-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 496.4 kB
  • Tags: CPython 3.6m, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.1.1 pkginfo/1.5.0.1 requests/2.22.0 setuptools/45.1.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/3.6.8

File hashes

Hashes for MorphIO-2.3.4-cp36-cp36m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 fedc5673170b9787c42bbd149f9486ff8cacc0ba2c0162854729bd1afb730b14
MD5 2bfa857b2e0cd0adc28c7e033e36a8da
BLAKE2b-256 a2b85b901baec4c604024cb7960e219e1d995224dbd7f6ffdf8e19e710569d91

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp27-cp27mu-manylinux1_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp27-cp27mu-manylinux1_x86_64.whl
  • Upload date:
  • Size: 2.1 MB
  • Tags: CPython 2.7mu
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp27-cp27mu-manylinux1_x86_64.whl
Algorithm Hash digest
SHA256 2f557ba2f98cacb77871e93557f8a9d3b39dad61091e3d6a5cfe69e2a0a50e1d
MD5 026ae88fbedfc94d377bb521145ff21b
BLAKE2b-256 efb336d98dcae22be0595074c0266705cab939e06a4c064bd53238466e2c863c

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp27-cp27mu-manylinux1_i686.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp27-cp27mu-manylinux1_i686.whl
  • Upload date:
  • Size: 2.0 MB
  • Tags: CPython 2.7mu
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.12

File hashes

Hashes for MorphIO-2.3.4-cp27-cp27mu-manylinux1_i686.whl
Algorithm Hash digest
SHA256 bafe73ef25a4e62dc1e9dbe00b1d043dc05ad6131f9df88f423afaa84236fae2
MD5 f829a8886a9b24d260fac9c2daf79e39
BLAKE2b-256 7fbbf57fc09be905ea58e55fe895b0b41859c2326aa9efdfd605439d7fe5d83b

See more details on using hashes here.

File details

Details for the file MorphIO-2.3.4-cp27-cp27m-macosx_10_9_x86_64.whl.

File metadata

  • Download URL: MorphIO-2.3.4-cp27-cp27m-macosx_10_9_x86_64.whl
  • Upload date:
  • Size: 499.9 kB
  • Tags: CPython 2.7m, macOS 10.9+ x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/1.15.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/44.0.0 requests-toolbelt/0.9.1 tqdm/4.41.1 CPython/2.7.17

File hashes

Hashes for MorphIO-2.3.4-cp27-cp27m-macosx_10_9_x86_64.whl
Algorithm Hash digest
SHA256 3f8ec783d3e0f877a1550539908eb87d9675507ce2fd84074ab1acfecf1ba123
MD5 3320a7d238ea53e98261074031ea51a1
BLAKE2b-256 68f7d589a31aea14c542396d8a768f35bf0947e8b43ecbad7d24928c088bfac7

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