diff --git a/.github/workflows/publish-docs.yaml b/.github/workflows/publish-docs.yaml new file mode 100644 index 00000000..198c6784 --- /dev/null +++ b/.github/workflows/publish-docs.yaml @@ -0,0 +1,59 @@ +name: Deploy Docs to GitHub Pages + +on: + push: + branches: [main] + pull_request: + branches: [main] + workflow_dispatch: + +# Allow this job to clone the repo and create a page deployment +permissions: + contents: read + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} + steps: + - name: Checkout + uses: actions/checkout@v3 + + - uses: conda-incubator/setup-miniconda@v2 + with: + python-version: "3.11" + mamba-version: "*" + channels: conda-forge + channel-priority: true + + - name: Install package and dependencies + run: | + pip install git+https://github.com/funkelab/funlib.learn.torch + python -m pip install -e .[docs] + + - name: Build documentation + run: sphinx-build docs/source docs/build/html -W -b html + + - name: Upload Pages Artifact + uses: actions/upload-pages-artifact@v2 + with: + path: docs/build/html + retention-days: 90 + + deploy: + if: github.ref == 'refs/heads/main' + needs: build + # Deploy to the github-pages environment + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + + runs-on: ubuntu-latest + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/.gitignore b/.gitignore index 9a04fce9..faf9a330 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ net_iter* .idea *.hdf *.h5 +docs/_build/ # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 00000000..ba8911bb --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +sample_data.zarr diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/_images/tutorial_batch_provider_10_0.png b/docs/_images/tutorial_batch_provider_10_0.png deleted file mode 100644 index 0ccc3cc2..00000000 Binary files a/docs/_images/tutorial_batch_provider_10_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_11_0.png b/docs/_images/tutorial_batch_provider_11_0.png deleted file mode 100644 index ea20ab19..00000000 Binary files a/docs/_images/tutorial_batch_provider_11_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_1_0.png b/docs/_images/tutorial_batch_provider_1_0.png deleted file mode 100644 index 00b67d36..00000000 Binary files a/docs/_images/tutorial_batch_provider_1_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_2_0.png b/docs/_images/tutorial_batch_provider_2_0.png deleted file mode 100644 index 8ce3d91b..00000000 Binary files a/docs/_images/tutorial_batch_provider_2_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_4_1.png b/docs/_images/tutorial_batch_provider_4_1.png deleted file mode 100644 index 1141dc11..00000000 Binary files a/docs/_images/tutorial_batch_provider_4_1.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_5_0.png b/docs/_images/tutorial_batch_provider_5_0.png deleted file mode 100644 index 40ec0ebe..00000000 Binary files a/docs/_images/tutorial_batch_provider_5_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_6_0.png b/docs/_images/tutorial_batch_provider_6_0.png deleted file mode 100644 index 154f429b..00000000 Binary files a/docs/_images/tutorial_batch_provider_6_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_7_0.png b/docs/_images/tutorial_batch_provider_7_0.png deleted file mode 100644 index 73a88e42..00000000 Binary files a/docs/_images/tutorial_batch_provider_7_0.png and /dev/null differ diff --git a/docs/_images/tutorial_batch_provider_8_0.png b/docs/_images/tutorial_batch_provider_8_0.png deleted file mode 100644 index 51f49409..00000000 Binary files a/docs/_images/tutorial_batch_provider_8_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_10_0.png b/docs/_images/tutorial_simple_pipeline_10_0.png deleted file mode 100644 index e7fa3f00..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_10_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_11_0.png b/docs/_images/tutorial_simple_pipeline_11_0.png deleted file mode 100644 index ecaf3631..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_11_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_12_0.png b/docs/_images/tutorial_simple_pipeline_12_0.png deleted file mode 100644 index c6e80a28..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_12_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_13_0.png b/docs/_images/tutorial_simple_pipeline_13_0.png deleted file mode 100644 index 4f0dc9f5..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_13_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_14_0.png b/docs/_images/tutorial_simple_pipeline_14_0.png deleted file mode 100644 index a6fb4551..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_14_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_15_0.png b/docs/_images/tutorial_simple_pipeline_15_0.png deleted file mode 100644 index 2e6857e9..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_15_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_16_0.png b/docs/_images/tutorial_simple_pipeline_16_0.png deleted file mode 100644 index c478f38c..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_16_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_17_0.png b/docs/_images/tutorial_simple_pipeline_17_0.png deleted file mode 100644 index 546f9656..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_17_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_18_0.png b/docs/_images/tutorial_simple_pipeline_18_0.png deleted file mode 100644 index 8f40397f..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_18_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_1_0.png b/docs/_images/tutorial_simple_pipeline_1_0.png deleted file mode 100644 index 00b67d36..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_1_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_20_0.png b/docs/_images/tutorial_simple_pipeline_20_0.png deleted file mode 100644 index ca178019..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_20_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_21_0.png b/docs/_images/tutorial_simple_pipeline_21_0.png deleted file mode 100644 index d436ac06..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_21_0.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_22_8.png b/docs/_images/tutorial_simple_pipeline_22_8.png deleted file mode 100644 index 40692f8f..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_22_8.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_22_9.png b/docs/_images/tutorial_simple_pipeline_22_9.png deleted file mode 100644 index e1bf06e3..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_22_9.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_23_14.png b/docs/_images/tutorial_simple_pipeline_23_14.png deleted file mode 100644 index e1bf06e3..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_23_14.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_5_1.png b/docs/_images/tutorial_simple_pipeline_5_1.png deleted file mode 100644 index 9a00b555..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_5_1.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_7_1.png b/docs/_images/tutorial_simple_pipeline_7_1.png deleted file mode 100644 index 749aec84..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_7_1.png and /dev/null differ diff --git a/docs/_images/tutorial_simple_pipeline_9_0.png b/docs/_images/tutorial_simple_pipeline_9_0.png deleted file mode 100644 index 5f084926..00000000 Binary files a/docs/_images/tutorial_simple_pipeline_9_0.png and /dev/null differ diff --git a/docs/_modules/gunpowder/array.html b/docs/_modules/gunpowder/array.html deleted file mode 100644 index 48ca0bda..00000000 --- a/docs/_modules/gunpowder/array.html +++ /dev/null @@ -1,555 +0,0 @@ - - - - - - - - - - - gunpowder.array — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.array

-from .freezable import Freezable
-from copy import deepcopy
-from gunpowder.coordinate import Coordinate
-from gunpowder.roi import Roi
-import logging
-import numpy as np
-import copy
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Array(Freezable): - '''A numpy array with a specification describing the data. - - Args: - - data (array-like): - - The data to be stored in the array. Will be converted to a numpy - array, if necessary. - - spec (:class:`ArraySpec`, optional): - - A spec describing the data. - - attrs (``dict``, optional): - - Optional attributes to describe this array. - ''' - - def __init__(self, data, spec=None, attrs=None): - - self.spec = deepcopy(spec) - self.data = np.asarray(data) - self.attrs = attrs - - if attrs is None: - self.attrs = {} - - if ( - spec is not None and - spec.roi is not None and - spec.voxel_size is not None): - - for d in range(len(spec.voxel_size)): - assert spec.voxel_size[d]*data.shape[-spec.roi.dims()+d] == spec.roi.get_shape()[d], \ - "ROI %s does not align with voxel size %s * data shape %s"%(spec.roi, spec.voxel_size, data.shape) - if spec.roi.get_offset()[d] is not None: - assert spec.roi.get_offset()[d] % spec.voxel_size[d] == 0,\ - "ROI offset %s must be a multiple of voxel size %s"\ - % (spec.roi.get_offset(), spec.voxel_size) - - if spec.dtype is not None: - assert data.dtype == spec.dtype, \ - "data dtype %s does not match spec dtype %s" % (data.dtype, spec.dtype) - - self.freeze() - -
[docs] def crop(self, roi, copy=True): - '''Create a cropped copy of this Array. - - Args: - - roi (:class:`Roi`): - - ROI in world units to crop to. - - copy (``bool``): - - Make a copy of the data. - ''' - - assert self.spec.roi.contains(roi), ( - "Requested crop ROI (%s) doesn't fit in array (%s)" % - (roi, self.spec.roi)) - - if self.spec.roi == roi and not copy: - return self - - voxel_size = self.spec.voxel_size - data_roi = (roi - self.spec.roi.get_offset())/voxel_size - slices = data_roi.get_bounding_box() - - while len(slices) < len(self.data.shape): - slices = (slice(None),) + slices - - data = self.data[slices] - if copy: - data = np.array(data) - - spec = deepcopy(self.spec) - attrs = deepcopy(self.attrs) - spec.roi = deepcopy(roi) - return Array(data, spec, attrs)
- -
[docs] def merge(self, array, copy_from_self=False, copy=False): - '''Merge this array with another one. The resulting array will have the - size of the larger one, with values replaced from ``array``. - - This only works if one of the two arrays is contained in the other. In - this case, ``array`` will overwrite values in ``self`` (unless - ``copy_from_self`` is set to ``True``). - - A copy will only be made if necessary or ``copy`` is set to ``True``. - ''' - # It is unclear how to merge arrays in all cases. Consider a 10x10 array, - # you crop out a 5x5 area, do a shift augment, and attempt to merge. - # What does that mean? specs have changed. It should be a new key. - raise NotImplementedError("Merge function should not be used!") - - self_roi = self.spec.roi - array_roi = array.spec.roi - - assert self_roi.contains(array_roi) or array_roi.contains(self_roi), \ - "Can not merge arrays that are not contained in each other." - - assert self.spec.voxel_size == array.spec.voxel_size, \ - "Can not merge arrays with different voxel sizes." - - # make sure self contains array - if not self_roi.contains(array_roi): - return array.merge(self, not copy_from_self, copy) - - # -> here we know that self contains array - - # simple case, self overwrites all of array - if copy_from_self: - return self if not copy else deepcopy(self) - - # -> here we know that copy_from_self == False - - # simple case, ROIs are the same - if self_roi == array_roi: - return array if not copy else deepcopy(array) - - # part of self have to be replaced, a copy is needed - merged = deepcopy(self) - - voxel_size = self.spec.voxel_size - data_roi = (array_roi - self_roi.get_offset())/voxel_size - slices = data_roi.get_bounding_box() - - while len(slices) < len(self.data.shape): - slices = (slice(None),) + slices - - merged.data[slices] = array.data - - return merged
- - def __repr__(self): - return str(self.spec) - -
[docs] def copy(self): - '''Create a copy of this array.''' - return copy.deepcopy(self)
- - -
[docs]class ArrayKey(Freezable): - '''A key to identify arrays in requests, batches, and across nodes. - - Used as key in :class:`BatchRequest` and :class:`Batch` to retrieve array - specs or arrays. - - Args: - - identifier (``string``): - - A unique, human readable identifier for this array key. Will be - used in log messages and to look up arrays in requests and batches. - Should be upper case (like ``RAW``, ``GT_LABELS``). The identifier - is unique: Two array keys with the same identifier will refer to - the same array. - ''' - - def __init__(self, identifier): - self.identifier = identifier - self.hash = hash(identifier) - self.freeze() - logger.debug("Registering array key %s", self) - setattr(ArrayKeys, self.identifier, self) - - def __eq__(self, other): - return hasattr(other, 'identifier') and self.identifier == other.identifier - - def __hash__(self): - return self.hash - - def __repr__(self): - return self.identifier
- -class ArrayKeys: - '''Convenience access to all created :class:``ArrayKey``s. A key generated - with:: - - raw = ArrayKey('RAW') - - can be retrieved as:: - - ArrayKeys.RAW - ''' - pass -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/array_spec.html b/docs/_modules/gunpowder/array_spec.html deleted file mode 100644 index 11beb94b..00000000 --- a/docs/_modules/gunpowder/array_spec.html +++ /dev/null @@ -1,441 +0,0 @@ - - - - - - - - - - - gunpowder.array_spec — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.array_spec

-import copy
-from .coordinate import Coordinate
-from .freezable import Freezable
-
-
[docs]class ArraySpec(Freezable): - '''Contains meta-information about an array. This is used by - :class:`BatchProviders<BatchProvider>` to communicate the arrays they - offer, as well as by :class:`Arrays<Array>` to describe the data they - contain. - - Attributes: - - roi (:class:`Roi`): - - The region of interested represented by this array spec. Can be - ``None`` for :class:`BatchProviders<BatchProvider>` that allow - requests for arrays everywhere, but will always be set for array - specs that are part of a :class:`Array`. - - voxel_size (:class:`Coordinate`): - - The size of the spatial axises in world units. - - interpolatable (``bool``): - - Whether the values of this array can be interpolated. - - nonspatial (``bool``, optional): - - If set, this array does not represent spatial data (e.g., a list of - labels for samples in a batch). ``roi`` and ``voxel_size`` have to - be ``None``. No consistency checks will be performed. - - dtype (``np.dtype``): - - The data type of the array. - ''' - - def __init__( - self, - roi=None, - voxel_size=None, - interpolatable=None, - nonspatial=False, - dtype=None, - placeholder=False): - - self.roi = roi - self.voxel_size = None if voxel_size is None else Coordinate(voxel_size) - self.interpolatable = interpolatable - self.nonspatial = nonspatial - self.dtype = dtype - self.placeholder = placeholder - - if nonspatial: - assert roi is None, "Non-spatial arrays can not have a ROI" - assert voxel_size is None, "Non-spatial arrays can not " \ - "have a voxel size" - - self.freeze() - -
[docs] def copy(self): - '''Create a copy of this spec.''' - return copy.deepcopy(self)
- - def __eq__(self, other): - - if isinstance(other, self.__class__): - return self.__dict__ == other.__dict__ - return NotImplemented - - def __ne__(self, other): - - if isinstance(other, self.__class__): - return not self.__eq__(other) - return NotImplemented - - def __repr__(self): - r = "" - r += "ROI: " + str(self.roi) + ", " - r += "voxel size: " + str(self.voxel_size) + ", " - r += "interpolatable: " + str(self.interpolatable) + ", " - r += "non-spatial: " + str(self.nonspatial) + ", " - r += "dtype: " + str(self.dtype) + ", " - r += "placeholder: " + str(self.placeholder) - return r
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/batch.html b/docs/_modules/gunpowder/batch.html deleted file mode 100644 index 509aac84..00000000 --- a/docs/_modules/gunpowder/batch.html +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - - - - - - gunpowder.batch — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.batch

-from copy import copy as shallow_copy
-import logging
-import multiprocessing
-import warnings
-
-from .freezable import Freezable
-from .profiling import ProfilingStats
-from .array import Array, ArrayKey
-from .graph import Graph, GraphKey
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Batch(Freezable): - '''Contains the requested batch as a collection of :class:`Arrays<Array>` - and :class:`Graph` that is passed through the pipeline from sources to - sinks. - - This collection mimics a dictionary. Items can be added with:: - - batch = Batch() - batch[array_key] = Array(...) - batch[graph_key] = Graph(...) - - Here, ``array_key`` and ``graph_key`` are :class:`ArrayKey` and - :class:`GraphKey`. The items can be queried with:: - - array = batch[array_key] - graph = batch[graph_key] - - Furthermore, pairs of keys/values can be iterated over using - ``batch.items()``. - - To access only arrays or graphs, use the dictionaries ``batch.arrays`` - or ``batch.graphs``, respectively. - - Attributes: - - arrays (dict from :class:`ArrayKey` to :class:`Array`): - - Contains all arrays that have been requested for this batch. - - graphs (dict from :class:`GraphKey` to :class:`Graph`): - - Contains all graphs that have been requested for this batch. - ''' - - __next_id = multiprocessing.Value('L') - - @staticmethod - def get_next_id(): - with Batch.__next_id.get_lock(): - next_id = Batch.__next_id.value - Batch.__next_id.value += 1 - return next_id - - def __init__(self): - - self.id = Batch.get_next_id() - self.profiling_stats = ProfilingStats() - self.arrays = {} - self.graphs = {} - self.affinity_neighborhood = None - self.loss = None - self.iteration = None - - self.freeze() - - def __setitem__(self, key, value): - - if isinstance(value, Array): - assert isinstance(key, ArrayKey), ( - "Only a ArrayKey is allowed as key for an Array value.") - self.arrays[key] = value - - elif isinstance(value, Graph): - assert isinstance( - key, GraphKey - ), f"Only a GraphKey is allowed as key for Graph value." - self.graphs[key] = value - - else: - raise RuntimeError( - "Only Array or Graph can be set in a %s."%type(self).__name__) - - def __getitem__(self, key): - - if isinstance(key, ArrayKey): - return self.arrays[key] - - elif isinstance(key, GraphKey): - return self.graphs[key] - - else: - raise RuntimeError( - "Only ArrayKey or GraphKey can be used as keys in a " - "%s."%type(self).__name__) - - def __len__(self): - - return len(self.arrays) + len(self.graphs) - - def __contains__(self, key): - - if isinstance(key, ArrayKey): - return key in self.arrays - - elif isinstance(key, GraphKey): - return key in self.graphs - - else: - raise RuntimeError( - "Only ArrayKey or GraphKey can be used as keys in a " - "%s. Key %s is a %s"%(type(self).__name__, key, type(key).__name__)) - - def __delitem__(self, key): - - if isinstance(key, ArrayKey): - del self.arrays[key] - - elif isinstance(key, GraphKey): - del self.graphs[key] - - else: - raise RuntimeError( - "Only ArrayKey or GraphKey can be used as keys in a " - "%s."%type(self).__name__) - - @property - def points(self): - warnings.warn( - "points are depricated. Please use graphs", DeprecationWarning - ) - return self.graphs - -
[docs] def items(self): - '''Provides a generator iterating over key/value pairs.''' - - for (k, v) in self.arrays.items(): - yield k, v - for (k, v) in self.graphs.items(): - yield k, v
- -
[docs] def get_total_roi(self): - '''Get the union of all the array ROIs in the batch.''' - - total_roi = None - - for collection_type in [self.arrays, self.graphs]: - for (key, obj) in collection_type.items(): - if total_roi is None: - total_roi = obj.spec.roi - else: - total_roi = total_roi.union(obj.spec.roi) - - return total_roi
- - def __repr__(self): - - r = "\n" - for collection_type in [self.arrays, self.graphs]: - for (key, obj) in collection_type.items(): - r += "\t%s: %s\n"%(key, obj.spec) - return r - -
[docs] def crop(self, request, copy=False): - '''Crop batch to meet the given request.''' - - cropped = Batch() - cropped.profiling_stats = self.profiling_stats - cropped.loss = self.loss - cropped.iteration = self.iteration - - for key, val in request.items(): - assert key in self, "%s not contained in this batch" % key - if val.roi is None: - cropped[key] = self[key] - else: - if isinstance(key, GraphKey): - cropped[key] = self[key].crop(val.roi) - else: - cropped[key] = self[key].crop(val.roi, copy) - - return cropped
- -
[docs] def merge(self, batch, merge_profiling_stats=True): - '''Merge this batch (``a``) with another batch (``b``). - - This creates a new batch ``c`` containing arrays and graphs from - both batches ``a`` and ``b``: - - * Arrays or Graphs that exist in either ``a`` or ``b`` will be - referenced in ``c`` (not copied). - - * Arrays or Graphs that exist in both batches will keep only - a reference to the version in ``b`` in ``c``. - - All other cases will lead to an exception. - ''' - - merged = shallow_copy(self) - - for key, val in batch.items(): - # TODO: What is the goal of `val.spec.roi is None`? Why should that - # mean that the key in merged gets overwritten? - if key not in merged or val.spec.roi is None: - merged[key] = val - elif key in merged: - merged[key] = val - - if merge_profiling_stats: - merged.profiling_stats.merge_with(batch.profiling_stats) - if batch.loss is not None: - merged.loss = batch.loss - if batch.iteration is not None: - merged.iteration = batch.iteration - - return merged
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/batch_request.html b/docs/_modules/gunpowder/batch_request.html deleted file mode 100644 index 37e995ab..00000000 --- a/docs/_modules/gunpowder/batch_request.html +++ /dev/null @@ -1,486 +0,0 @@ - - - - - - - - - - - gunpowder.batch_request — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.batch_request

-import copy
-from .provider_spec import ProviderSpec
-from .roi import Roi
-from .array import ArrayKey
-from .array_spec import ArraySpec
-from .graph import GraphKey
-from .graph_spec import GraphSpec
-
-import time
-
-
-
[docs]class BatchRequest(ProviderSpec): - """A collection of (possibly partial) :class:`ArraySpec` and - :class:`GraphSpec` forming a request. - - Inherits from :class:`ProviderSpec`. - - See :ref:`sec_requests_batches` for how to use a batch request to obtain a - batch. - - Additional Kwargs: - - random_seed (``int``): - - The random seed that will be associated with this batch to - guarantee deterministic and repeatable batch requests. - - """ - - def __init__(self, *args, random_seed=None, **kwargs): - self._random_seed = ( - random_seed if random_seed is not None else int(time.time() * 1e6) - ) - super().__init__(*args, **kwargs) - -
[docs] def add(self, key, shape, voxel_size=None, directed=None, placeholder=False): - """Convenience method to add an array or graph spec by providing only - the shape of a ROI (in world units). - - A ROI with zero-offset will be generated. If more than one request is - added, the ROIs with smaller shapes will be shifted to be centered in - the largest one. - - Args: - - key (:class:`ArrayKey` or :class:`GraphKey`): - - The key for which to add a spec. - - shape (:class:`Coordinate`): - - A tuple containing the shape of the desired roi - - voxel_size (:class:`Coordinate`): - - A tuple contening the voxel sizes for each corresponding - dimension - """ - - if isinstance(key, ArrayKey): - spec = ArraySpec(placeholder=placeholder) - elif isinstance(key, GraphKey): - spec = GraphSpec(placeholder=placeholder, directed=directed) - else: - raise RuntimeError("Only ArrayKey or GraphKey can be added.") - - spec.roi = Roi((0,) * len(shape), shape) - - if voxel_size is not None: - spec.voxel_size = voxel_size - - self[key] = spec - self.__center_rois()
- - def copy(self): - """Create a copy of this request.""" - return copy.deepcopy(self) - - @property - def random_seed(self): - return self._random_seed % (2 ** 32) - - def _update_random_seed(self): - self._random_seed = hash((self._random_seed + 1) ** 2) - - def __center_rois(self): - """Ensure that all ROIs are centered around the same location.""" - - total_roi = self.get_total_roi() - if total_roi is None: - return - - center = total_roi.get_center() - - for specs_type in [self.array_specs, self.graph_specs]: - for key in specs_type: - roi = specs_type[key].roi - specs_type[key].roi = roi.shift(center - roi.get_center()) - - def merge(self, request): - """Merge another request with current request""" - - assert isinstance(request, BatchRequest) - - merged = self.copy() - - for key, spec in request.items(): - if key not in merged: - merged[key] = spec - else: - if isinstance(spec, ArraySpec) and merged[key].nonspatial: - merged[key] = spec - else: - merged[key].roi = merged[key].roi.union(spec.roi) - - return merged - - def __eq__(self, other): - """ - Override equality check to allow batche requests with different - seeds to still be checked. Otherwise equality check should - never succeed. - """ - - if isinstance(other, self.__class__): - other_dict = copy.deepcopy(other.__dict__) - self_dict = copy.deepcopy(self.__dict__) - other_dict.pop("_random_seed") - self_dict.pop("_random_seed") - return self_dict == other_dict - return NotImplemented
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/caffe/nodes/predict.html b/docs/_modules/gunpowder/caffe/nodes/predict.html deleted file mode 100644 index 2dc1c864..00000000 --- a/docs/_modules/gunpowder/caffe/nodes/predict.html +++ /dev/null @@ -1,429 +0,0 @@ - - - - - - - - - - - gunpowder.caffe.nodes.predict — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.caffe.nodes.predict
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.caffe.nodes.predict

-import copy
-import logging
-import os
-
-from gunpowder.caffe.net_io_wrapper import NetIoWrapper
-from gunpowder.ext import caffe
-from gunpowder.nodes.generic_predict import GenericPredict
-from gunpowder.array import ArrayKey, Array
-
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Predict(GenericPredict): - '''Augments a batch with network predictions. - - Args: - - prototxt (``string``): - - Filename of the network prototxt. - - weights (``string``): - - Filename of the network weights. - - inputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of input layers in the network to array - keys. - - outputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of output layers in the network to - array keys. New arrays will be generated by this node for each - entry (if requested downstream). - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - Used to set the specs of generated arrays (``outputs``). This is - useful to set the ``voxel_size``, for example, if they differ from - the voxel size of the input arrays. Only fields that are not - ``None`` in the given :class:`ArraySpec` will be used. - - use_gpu (``int`` or ``None``, optional): - - Which GPU to use. Set to ``None`` for CPU mode. - ''' - - def __init__( - self, - prototxt, - weights, - inputs, - outputs, - array_specs=None, - use_gpu=None): - - super(Predict, self).__init__( - inputs, - outputs, - array_specs, - spawn_subprocess=True) - for f in [prototxt, weights]: - if not os.path.isfile(f): - raise RuntimeError("%s does not exist"%f) - self.prototxt = prototxt - self.weights = weights - self.inputs = inputs - self.outputs = outputs - self.use_gpu = use_gpu - - def start(self): - - logger.info("Initializing solver...") - - if self.use_gpu is not None: - - logger.debug("Predict process: using GPU %d"%self.use_gpu) - caffe.enumerate_devices(False) - caffe.set_devices((self.use_gpu,)) - caffe.set_mode_gpu() - caffe.select_device(self.use_gpu, False) - - self.net = caffe.Net(self.prototxt, self.weights, caffe.TEST) - self.net_io = NetIoWrapper(self.net, self.outputs.keys()) - - def predict(self, batch, request): - - self.net_io.set_inputs({ - input_name: batch.arrays[array_key].data - for input_name, array_key in self.inputs.items() - }) - - self.net.forward() - output = self.net_io.get_outputs() - - for output_name, array_key in self.outputs.items(): - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - output[output_name][0], # strip #batch dimension - spec) - - return batch
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/caffe/nodes/train.html b/docs/_modules/gunpowder/caffe/nodes/train.html deleted file mode 100644 index 41004abb..00000000 --- a/docs/_modules/gunpowder/caffe/nodes/train.html +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - - - - - - gunpowder.caffe.nodes.train — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.caffe.nodes.train
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.caffe.nodes.train

-import logging
-import numpy as np
-
-from gunpowder.caffe.net_io_wrapper import NetIoWrapper
-from gunpowder.ext import caffe
-from gunpowder.nodes.generic_train import GenericTrain
-from gunpowder.array import Array, ArrayKey
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Train(GenericTrain): - '''Caffe implementation of :class:`gunpowder.nodes.Train`. - - Args: - - solver_parameters (:class:`SolverParameters`): - - Parameters of the solver to use for training, contains the network - description as well. - - inputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from names of input layers in the network to - array keys. - - outputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of output layers in the network to array - keys. New arrays will be generated by this node for each entry (if - requested downstream). - - gradients (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of output layers in the network to array - keys. New arrays containing the gradient of an output with respect - to the loss will be generated by this node for each entry (if - requested downstream). - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - Used to set the array specs of generated arrays (see ``outputs`` - and ``gradients``). This is useful to set the ``voxel_size``, for - example, if they differ from the voxel size of the input arrays. - Only fields that are not ``None`` in the given :class:`ArraySpec` - will be used. - - use_gpu (``int`` or ``None``, optional): - - Which GPU to use. Set to ``None`` for CPU mode. - ''' - - def __init__( - self, - solver_parameters, - inputs, - outputs, - gradients, - array_specs=None, - use_gpu=None): - - super(Train, self).__init__( - inputs, - outputs, - gradients, - array_specs, - spawn_subprocess=True) - self.solver_parameters = solver_parameters - self.use_gpu = use_gpu - self.solver = None - self.net_io = None - - def start(self): - - logger.info("Initializing solver...") - - if self.use_gpu is not None: - - logger.debug("Train process: using GPU %d", self.use_gpu) - caffe.enumerate_devices(False) - caffe.set_devices((self.use_gpu,)) - caffe.set_mode_gpu() - caffe.select_device(self.use_gpu, False) - - self.solver = caffe.get_solver(self.solver_parameters) - if self.solver_parameters.resume_from is not None: - logger.debug( - "Train process: restoring solver state from %s", - self.solver_parameters.resume_from) - self.solver.restore(self.solver_parameters.resume_from) - - names_net_outputs = self.outputs.keys() + self.gradients.keys() - self.net_io = NetIoWrapper(self.solver.net, names_net_outputs) - - def train_step(self, batch, request): - - data = {} - for input_name, network_input in self.inputs.items(): - if isinstance(network_input, ArrayKey): - if network_input in batch.arrays: - data[input_name] = batch.arrays[network_input].data - else: - logger.warn("batch does not contain %s, input %s will not " - "be set", network_input, input_name) - elif isinstance(network_input, np.ndarray): - data[input_name] = network_input - elif isinstance(network_input, str): - data[input_name] = getattr(batch, network_input) - else: - raise Exception( - "Unknown network input type {}, can't be given to " - "network".format(network_input)) - self.net_io.set_inputs(data) - - loss = self.solver.step(1) - # self.__consistency_check() - - requested_outputs = { - name: array_key - for name, array_key in self.outputs.items() - if array_key in request.array_specs } - - if requested_outputs: - - output = self.net_io.get_outputs() - - for output_name, array_key in requested_outputs.items(): - - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - output[output_name][0], # strip #batch dimension - spec) - - requested_gradients = { - name: array_key - for name, array_key in self.gradients.items() - if array_key in request.array_specs } - - if requested_gradients: - - diffs = self.net_io.get_output_diffs() - - for output_name, array_key in requested_gradients.items(): - - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - diffs[output_name][0], # strip #batch dimension - spec) - - batch.loss = loss - batch.iteration = self.solver.iter - - def __consistency_check(self): - - diffs = self.net_io.get_output_diffs() - for k in diffs: - assert not np.isnan(diffs[k]).any(), "Detected NaN in output diff " + k
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/caffe/solver_parameters.html b/docs/_modules/gunpowder/caffe/solver_parameters.html deleted file mode 100644 index 2724a756..00000000 --- a/docs/_modules/gunpowder/caffe/solver_parameters.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - - - - gunpowder.caffe.solver_parameters — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.caffe.solver_parameters
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.caffe.solver_parameters

-from gunpowder.ext import caffe, NoSuchModule
-
-try:
-    class SolverParameters(caffe.SolverParameter):
-        '''Wrapper of the caffe's ``SolverParameter`` class.
-
-        Attributes:
-
-            train_net (``string``):
-
-                The network to train.
-
-            base_lr (``float``):
-
-                The initial learning rate.
-
-            snapshot (``int``):
-
-                Weight snapshot interval in iterations.
-
-            snapshot_prefix (``string``)
-
-                Prefix of snapshot files.
-
-            type (``string``):
-
-                Optimizer type, e.g., ``Adam``
-
-                For ``Adam``, the following parameters can be set as attributes
-                of this class: ``momentum`` (``float``), ``momentum2``
-                (``float``), ``delta`` (``float``), ``weight_decay``
-                (``float``), ``lr_policy`` (``string``), ``gamma`` (``float``),
-                ``power`` (``float``).
-
-            resume_from (``string`` or ``None``):
-
-                Weight snapshot file to resume training from.
-
-            train_state (training stages):
-
-                Used to set the current trainig stage (if used during
-                construction of the network).
-        '''
-        pass
-except:
-
[docs] class SolverParameters(NoSuchModule): - '''Wrapper of the caffe's ``SolverParameter`` class. - - Attributes: - - train_net (``string``): - - The network to train. - - base_lr (``float``): - - The initial learning rate. - - snapshot (``int``): - - Weight snapshot interval in iterations. - - snapshot_prefix (``string``) - - Prefix of snapshot files. - - type (``string``): - - Optimizer type, e.g., ``Adam`` - - For ``Adam``, the following parameters can be set as attributes - of this class: ``momentum`` (``float``), ``momentum2`` - (``float``), ``delta`` (``float``), ``weight_decay`` - (``float``), ``lr_policy`` (``string``), ``gamma`` (``float``), - ``power`` (``float``). - - resume_from (``string`` or ``None``): - - Weight snapshot file to resume training from. - - train_state (training stages): - - Used to set the current trainig stage (if used during - construction of the network). - ''' - def __init__(self): - super(SolverParameters, self).__init__('caffe')
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/coordinate.html b/docs/_modules/gunpowder/coordinate.html deleted file mode 100644 index 005cf399..00000000 --- a/docs/_modules/gunpowder/coordinate.html +++ /dev/null @@ -1,538 +0,0 @@ - - - - - - - - - - - gunpowder.coordinate — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.coordinate

-import numbers
-
-
[docs]class Coordinate(tuple): - '''A ``tuple`` of integers. - - Allows the following element-wise operators: addition, subtraction, - multiplication, division, absolute value, and negation. This allows to - perform simple arithmetics with coordinates, e.g.:: - - shape = Coordinate((2, 3, 4)) - voxel_size = Coordinate((10, 5, 1)) - size = shape*voxel_size # == Coordinate((20, 15, 4)) - ''' - - def __new__(cls, array_like): - return super(Coordinate, cls).__new__( - cls, - [ - int(x) - if x is not None - else None - for x in array_like]) - - def dims(self): - return len(self) - - def __neg__(self): - - return Coordinate( - -a - if a is not None - else None - for a in self) - - def __abs__(self): - - return Coordinate( - abs(a) - if a is not None - else None - for a in self) - - def __add__(self, other): - - assert isinstance(other, tuple), f"can only add Coordinate or tuples to Coordinate. {type(other)} is invalid" - assert self.dims() == len(other), "can only add Coordinate of equal dimensions" - - return Coordinate( - a+b - if a is not None and b is not None - else None - for a, b in zip(self, other)) - - def __sub__(self, other): - - assert isinstance(other, tuple), f"can only subtract Coordinate or tuples to Coordinate. {type(other)} is invalid" - assert self.dims() == len(other), "can only subtract Coordinate of equal dimensions" - - return Coordinate( - a-b - if a is not None and b is not None - else None - for a, b in zip(self, other)) - - def __mul__(self, other): - - if isinstance(other, tuple): - - assert self.dims() == len(other), "can only multiply Coordinate of equal dimensions" - - return Coordinate( - a*b - if a is not None and b is not None - else None - for a,b in zip(self, other)) - - elif isinstance(other, numbers.Number): - - return Coordinate( - a*other - if a is not None - else None - for a in self) - - else: - - raise TypeError("multiplication of Coordinate with type %s not supported" %type(other)) - - def __div__(self, other): - - if isinstance(other, tuple): - - assert self.dims() == len(other), "can only divide Coordinate of equal dimensions" - - return Coordinate( - a/b - if a is not None and b is not None - else None - for a,b in zip(self, other)) - - elif isinstance(other, numbers.Number): - - return Coordinate( - a/other - if a is not None - else None - for a in self) - - else: - - raise TypeError("division of Coordinate with type %s not supported" % type(other)) - - def __truediv__(self, other): - - if isinstance(other, tuple): - - assert self.dims() == len(other), "can only divide Coordinate of equal dimensions" - - return Coordinate( - a/b - if a is not None and b is not None - else None - for a,b in zip(self, other)) - - elif isinstance(other, numbers.Number): - - return Coordinate( - a/other - if a is not None - else None - for a in self) - - else: - - raise TypeError("division of Coordinate with type %s not supported" % type(other)) - - def __floordiv__(self, other): - - if isinstance(other, tuple): - - assert self.dims() == len(other), "can only divide Coordinate of equal dimensions" - - return Coordinate( - a//b - if a is not None and b is not None - else None - for a,b in zip(self, other)) - - elif isinstance(other, numbers.Number): - - return Coordinate( - a//other - if a is not None - else None - for a in self) - - else: - - raise TypeError("division of Coordinate with type %s not supported" % type(other)) - - def __mod__(self, other): - - if isinstance(other, tuple): - - assert self.dims() == len(other), "can only mod Coordinate of equal dimensions" - - return Coordinate( - a%b - if a is not None and b is not None - else None - for a,b in zip(self, other)) - - elif isinstance(other, numbers.Number): - - return Coordinate( - a%other - if a is not None - else None - for a in self) - - else: - - raise TypeError("mod of Coordinate with type %s not supported" % type(other))
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/graph.html b/docs/_modules/gunpowder/graph.html deleted file mode 100644 index 9b2c1054..00000000 --- a/docs/_modules/gunpowder/graph.html +++ /dev/null @@ -1,1018 +0,0 @@ - - - - - - - - - - - gunpowder.graph — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.graph

-from .graph_spec import GraphSpec
-from .roi import Roi
-from .freezable import Freezable
-
-import numpy as np
-import networkx as nx
-
-from copy import deepcopy
-from typing import Dict, Optional, Set, Iterator, Any
-import logging
-import itertools
-import warnings
-
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Node(Freezable): - """ - A stucture representing each node in a Graph. - - Args: - - id (``int``): - - A unique identifier for this Node - - location (``np.ndarray``): - - A numpy array containing a nodes location - - Optional attrs (``dict``, str -> ``Any``): - - A dictionary containing a mapping from attribute to value. - Used to store any extra attributes associated with the - Node such as color, size, etc. - - Optional temporary (bool): - - A tag to mark a node as temporary. Some operations such - as `trim` might make new nodes that are just biproducts - of viewing the data with a limited scope. These nodes - are only guaranteed to have an id different from those - in the same Graph, but may have conflicts if you request - multiple graphs from the same source with different rois. - """ - - def __init__( - self, - id: int, - location: np.ndarray, - temporary: bool = False, - attrs: Optional[Dict[str, Any]] = None, - ): - self.__attrs = attrs if attrs is not None else {} - self.attrs["id"] = id - self.location = location - # purpose is to keep track of nodes that were created during - # processing and do not have a corresponding node in the original source - self.attrs["temporary"] = temporary - self.freeze() - - def __getattr__(self, attr): - if "__" not in attr: - return self.attrs[attr] - else: - return super().__getattr__(attr) - - def __setattr__(self, attr, value): - if "__" not in attr: - self.attrs[attr] = value - else: - super().__setattr__(attr, value) - - @property - def location(self): - location = self.attrs["location"] - return location - - @location.setter - def location(self, new_location): - assert isinstance(new_location, np.ndarray) - self.attrs["location"] = new_location - - @property - def id(self): - return self.attrs["id"] - - @property - def original_id(self): - return self.id if not self.temporary else None - - @property - def temporary(self): - return self.attrs["temporary"] - - @property - def attrs(self): - return self.__attrs - - @property - def all(self): - return self.attrs - - @classmethod - def from_attrs(cls, attrs: Dict[str, Any]): - node_id = attrs["id"] - location = attrs["location"] - temporary = attrs.get("temporary", False) - return cls( - id=node_id, location=location, temporary=temporary, attrs=attrs - ) - - def __str__(self): - return f"Node({self.temporary}) ({self.id}) at ({self.location})" - - def __repr__(self): - return str(self) - - def __eq__(self, other): - return isinstance(other, Node) and self.id == other.id - - def __hash__(self): - return hash(self.id)
- - -
[docs]class Edge(Freezable): - """ - A structure representing edges in a graph. - - Args: - - u (``int``) - - The id of the 'u' node of this edge - - v (``int``) - - the id of the `v` node of this edge - """ - - def __init__(self, u: int, v: int, attrs: Optional[Dict[str, Any]] = None): - self.__u = u - self.__v = v - self.__attrs = attrs if attrs is not None else {} - self.freeze() - - @property - def u(self): - return self.__u - - @property - def v(self): - return self.__v - - @property - def all(self): - return self.__attrs - - def __iter__(self): - return iter([self.u, self.v]) - - def __str__(self): - return f"({self.u}, {self.v})" - - def __repr__(self): - return f"({self.u}, {self.v})" - - def __eq__(self, other): - return self.u == other.u and self.v == other.v - - def __hash__(self): - return hash((self.u, self.v)) - - def directed_eq(self, other): - return self.u == other.u and self.v == other.v - - def undirected_eq(self, other): - return set([self.u, self.v]) == set([other.u, other.v])
- - -
[docs]class Graph(Freezable): - """A structure containing a list of :class:`Node`, a list of :class:`Edge`, - and a specification describing the data. - - Args: - - nodes (``iterator``, :class:`Node`): - - An iterator containing Vertices. - - edges (``iterator``, :class:`Edge`): - - An iterator containing Edges. - - spec (:class:`GraphSpec`): - - A spec describing the data. - """ - - def __init__(self, nodes: Iterator[Node], edges: Iterator[Edge], spec: GraphSpec): - self.__spec = spec - self.__graph = self.create_graph(nodes, edges) - - @property - def spec(self): - return self.__spec - - @spec.setter - def spec(self, new_spec): - self.__spec = new_spec - - @property - def directed(self): - return ( - self.spec.directed - if self.spec.directed is not None - else self.__graph.is_directed() - ) - - def create_graph(self, nodes: Iterator[Node], edges: Iterator[Edge]): - if self.__spec.directed is None: - logger.debug( - "Trying to create a Graph without specifying directionality. Using default Directed!" - ) - graph = nx.DiGraph() - elif self.__spec.directed: - graph = nx.DiGraph() - else: - graph = nx.Graph() - - for node in nodes: - node.location = node.location.astype(self.spec.dtype) - - vs = [(v.id, v.all) for v in nodes] - graph.add_nodes_from(vs) - graph.add_edges_from([(e.u, e.v, e.all) for e in edges]) - return graph - - @property - def nodes(self): - for node_id, node_attrs in self.__graph.nodes.items(): - v = Node.from_attrs(node_attrs) - if not np.issubdtype(v.location.dtype, self.spec.dtype): - raise Exception( - f"expected location to have dtype {self.spec.dtype} but it had {v.location.dtype}" - ) - yield v - - def num_vertices(self): - return self.__graph.number_of_nodes() - - def num_edges(self): - return self.__graph.number_of_edges() - - @property - def edges(self): - for (u, v), attrs in self.__graph.edges.items(): - yield Edge(u, v, attrs) - - def neighbors(self, node): - if self.directed: - for neighbor in self.__graph.successors(node.id): - yield Node.from_attrs(self.__graph.nodes[neighbor]) - if self.directed: - for neighbor in self.__graph.predecessors(node.id): - yield Node.from_attrs(self.__graph.nodes[neighbor]) - else: - for neighbor in self.__graph.neighbors(node.id): - yield Node.from_attrs(self.__graph.nodes[neighbor]) - - def __str__(self): - string = "Vertices:\n" - for node in self.nodes: - string += f"{node}\n" - string += "Edges:\n" - for edge in self.edges: - string += f"{edge}\n" - return string - - def __repr__(self): - return str(self) - -
[docs] def node(self, id: int): - """ - Get node with a specific id - """ - attrs = self.__graph.nodes[id] - return Node.from_attrs(attrs)
- - def contains(self, node_id: int): - return node_id in self.__graph.nodes - -
[docs] def remove_node(self, node: Node, retain_connectivity=False): - """ - Remove a node. - - retain_connectivity: preserve removed nodes neighboring edges. - Given graph: a->b->c, removing `b` without retain_connectivity - would leave us with two connected components, {'a'} and {'b'}. - removing 'b' with retain_connectivity flag set to True would - leave us with the graph: a->c, and only one connected component - {a, c}, thus preserving the connectivity of 'a' and 'c' - """ - if retain_connectivity: - predecessors = self.predecessors(node) - successors = self.successors(node) - - for pred_id in predecessors: - for succ_id in successors: - if pred_id != succ_id: - self.add_edge(Edge(pred_id, succ_id)) - self.__graph.remove_node(node.id)
- -
[docs] def add_node(self, node: Node): - """ - Adds a node to the graph. - If a node exists with the same id as the node you are adding, - its attributes will be overwritten. - """ - node.location = node.location.astype(self.spec.dtype) - self.__graph.add_node(node.id, **node.all)
- -
[docs] def remove_edge(self, edge: Edge): - """ - Remove an edge from the graph. - """ - self.__graph.remove_edge(edge.u, edge.v)
- -
[docs] def add_edge(self, edge: Edge): - """ - Adds an edge to the graph. - If an edge exists with the same u and v, its attributes - will be overwritten. - """ - self.__graph.add_edge(edge.u, edge.v, **edge.all)
- - def copy(self): - return deepcopy(self) - -
[docs] def crop(self, roi: Roi): - """ - Will remove all nodes from self that are not contained in `roi` except for - "dangling" nodes. This means that if there are nodes A, B s.t. there - is an edge (A, B) and A is contained in `roi` but B is not, the edge (A, B) - is considered contained in the `roi` and thus node B will be kept as a - "dangling" node. - - Note there is a helper function `trim` that will remove B and replace it with - a node at the intersection of the edge (A, B) and the bounding box of `roi`. - - Args: - - roi (:class:`Roi`): - - ROI in world units to crop to. - """ - - cropped = self.copy() - - contained_nodes = set([v.id for v in cropped.nodes if roi.contains(v.location)]) - all_contained_edges = set( - [ - e - for e in cropped.edges - if e.u in contained_nodes or e.v in contained_nodes - ] - ) - fully_contained_edges = set( - [ - e - for e in all_contained_edges - if e.u in contained_nodes and e.v in contained_nodes - ] - ) - partially_contained_edges = all_contained_edges - fully_contained_edges - contained_edge_nodes = set(list(itertools.chain(*all_contained_edges))) - all_nodes = contained_edge_nodes | contained_nodes - dangling_nodes = all_nodes - contained_nodes - - for node in list(cropped.nodes): - if node.id not in all_nodes: - cropped.remove_node(node) - for edge in list(cropped.edges): - if edge not in all_contained_edges: - cropped.remove_edge(edge) - - cropped.spec.roi = roi - return cropped
- - def shift(self, offset): - for node in self.nodes: - node.location += offset - - def new_graph(self): - if self.directed(): - return nx.DiGraph() - else: - return nx.Graph() - -
[docs] def trim(self, roi: Roi): - """ - Create a copy of self and replace "dangling" nodes with contained nodes. - - A "dangling" node is defined by: Let A, B be nodes s.t. there exists an - edge (A, B) and A is contained in `roi` but B is not. Edge (A, B) is considered - contained, and thus B is kept as a "dangling" node. - """ - - trimmed = self.copy() - - contained_nodes = set([v.id for v in trimmed.nodes if roi.contains(v.location)]) - all_contained_edges = set( - [ - e - for e in trimmed.edges - if e.u in contained_nodes or e.v in contained_nodes - ] - ) - fully_contained_edges = set( - [ - e - for e in all_contained_edges - if e.u in contained_nodes and e.v in contained_nodes - ] - ) - partially_contained_edges = all_contained_edges - fully_contained_edges - contained_edge_nodes = set(list(itertools.chain(*all_contained_edges))) - all_nodes = contained_edge_nodes | contained_nodes - dangling_nodes = all_nodes - contained_nodes - - next_node = 0 if len(all_nodes) == 0 else max(all_nodes) + 1 - - trimmed._handle_boundaries( - partially_contained_edges, - contained_nodes, - roi, - node_id=itertools.count(next_node), - ) - - for node in trimmed.nodes: - assert roi.contains( - node.location - ), f"Failed to properly contain node {node.id} at {node.location}" - - return trimmed
- - def _handle_boundaries( - self, - crossing_edges: Iterator[Edge], - contained_nodes: Set[int], - roi: Roi, - node_id: Iterator[int], - ): - nodes_to_remove = set([]) - for e in crossing_edges: - u, v = self.node(e.u), self.node(e.v) - u_in = u.id in contained_nodes - v_in, v_out = (u, v) if u_in else (v, u) - in_location, out_location = (v_in.location, v_out.location) - new_location = self._roi_intercept(in_location, out_location, roi) - if not all(np.isclose(new_location, in_location)): - # use deepcopy because modifying this node should not modify original - new_attrs = deepcopy(v_out.attrs) - new_attrs["id"] = next(node_id) - new_attrs["location"] = new_location - new_attrs["temporary"] = True - new_v = Node.from_attrs(new_attrs) - new_e = Edge( - u=v_in.id if u_in else new_v.id, v=new_v.id if u_in else v_in.id - ) - self.add_node(new_v) - self.add_edge(new_e) - nodes_to_remove.add(v_out) - for node in nodes_to_remove: - self.remove_node(node) - - def _roi_intercept( - self, inside: np.ndarray, outside: np.ndarray, bb: Roi - ) -> np.ndarray: - """ - Given two points, one inside a bounding box and one outside, - get the intercept between the line and the bounding box. - """ - - offset = outside - inside - distance = np.linalg.norm(offset) - assert not np.isclose(distance, 0), f"Inside and Outside are the same location" - direction = offset / distance - - # `offset` can be 0 on some but not all axes leaving a 0 in the denominator. - # `inside` can be on the bounding box, leaving a 0 in the numerator. - # `x/0` throws a division warning, `0/0` throws an invalid warning (both are fine here) - with np.errstate(divide="ignore", invalid="ignore"): - bb_x = np.asarray( - [ - (np.asarray(bb.get_begin()) - inside) / offset, - (np.asarray(bb.get_end()) - inside) / offset, - ], - dtype=self.spec.dtype, - ) - - with np.errstate(invalid="ignore"): - s = np.min(bb_x[np.logical_and((bb_x >= 0), (bb_x <= 1))]) - - new_location = inside + s * distance * direction - upper = np.array(bb.get_end(), dtype=self.spec.dtype) - new_location = np.clip( - new_location, bb.get_begin(), upper - upper * np.finfo(self.spec.dtype).eps - ) - return new_location - -
[docs] def merge(self, other, copy_from_self=False, copy=False): - """ - Merge this graph with another. The resulting graph will have the Roi - of the larger one. - - This only works if one of the two graphs contains the other. - In this case, ``other`` will overwrite edges and nodes with the same - ID in ``self`` (unless ``copy_from_self`` is set to ``True``). - Vertices and edges in ``self`` that are contained in the Roi of ``other`` - will be removed (vice versa for ``copy_from_self``) - - A copy will only be made if necessary or ``copy`` is set to ``True``. - """ - - # It is unclear how to merge points in all cases. Consider a 10x10 graph, - # you crop out a 5x5 area, do a shift augment, and attempt to merge. - # What does that mean? specs have changed. It should be a new key. - raise NotImplementedError("Merge function should not be used!") - - self_roi = self.spec.roi - other_roi = other.spec.roi - - assert self_roi.contains(other_roi) or other_roi.contains( - self_roi - ), "Can not merge graphs that are not contained in each other." - - # make sure self contains other - if not self_roi.contains(other_roi): - return other.merge(self, not copy_from_self, copy) - - # edges and nodes in addition are guaranteed to be in merged - base = other if copy_from_self else self - addition = self if copy_from_self else other - - if copy: - merged = deepcopy(base) - else: - merged = base - - for node in list(merged.nodes): - if merged.spec.roi.contains(node.location): - merged.remove_node(node) - for edge in list(merged.edges): - if merged.spec.roi.contains( - merged.node(edge.u) - ) or merged.spec.roi.contains(merged.node(edge.v)): - merged.remove_edge(edge) - for node in addition.nodes: - merged.add_node(node) - for edge in addition.edges: - merged.add_edge(edge) - - return merged
- -
[docs] def to_nx_graph(self): - """ - returns a pure networkx graph containing data from - this Graph. - """ - return deepcopy(self.__graph)
- -
[docs] @classmethod - def from_nx_graph(cls, graph, spec): - """ - Create a gunpowder graph from a networkx graph - """ - if spec.directed is None: - spec.directed = graph.is_directed() - g = cls([], [], spec) - g.__graph = graph - return g
- -
[docs] def relabel_connected_components(self): - """ - create a new attribute "component" for each node - in this Graph - """ - for i, wcc in enumerate(self.connected_components): - for node in wcc: - self.__graph.nodes[node]["component"] = i
- - @property - def connected_components(self): - if not self.directed: - return nx.connected_components(self.__graph) - else: - return nx.weakly_connected_components(self.__graph) - - def in_degree(self): - return self.__graph.in_degree() - - def successors(self, node): - if self.directed: - return self.__graph.successors(node.id) - else: - return self.__graph.neighbors(node.id) - - def predecessors(self, node): - if self.directed: - return self.__graph.predecessors(node.id) - else: - return self.__graph.neighbors(node.id)
- - -
[docs]class GraphKey(Freezable): - """A key to identify graphs in requests, batches, and across - nodes. - - Used as key in :class:`BatchRequest` and :class:`Batch` to retrieve specs - or graphs. - - Args: - - identifier (``string``): - - A unique, human readable identifier for this graph key. Will be - used in log messages and to look up graphs in requests and batches. - Should be upper case (like ``CENTER_GRAPH``). The identifier is - unique: Two graph keys with the same identifier will refer to the - same graph. - """ - - def __init__(self, identifier): - self.identifier = identifier - self.hash = hash(identifier) - self.freeze() - logger.debug("Registering graph type %s", self) - setattr(GraphKeys, self.identifier, self) - - def __eq__(self, other): - return hasattr(other, "identifier") and self.identifier == other.identifier - - def __hash__(self): - return self.hash - - def __repr__(self): - return self.identifier
- - -class GraphKeys: - """Convenience access to all created :class:`GraphKey`s. A key generated - with:: - - centers = GraphKey('CENTER_GRAPH') - - can be retrieved as:: - - GraphKeys.CENTER_GRAPH - """ - - pass -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/graph_spec.html b/docs/_modules/gunpowder/graph_spec.html deleted file mode 100644 index c7638099..00000000 --- a/docs/_modules/gunpowder/graph_spec.html +++ /dev/null @@ -1,415 +0,0 @@ - - - - - - - - - - - gunpowder.graph_spec — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.graph_spec

-import numpy as np
-
-import copy
-
-from .freezable import Freezable
-
-
-
[docs]class GraphSpec(Freezable): - """Contains meta-information about a graph. This is used by - :class:`BatchProviders<BatchProvider>` to communicate the graphs they - offer, as well as by :class:`Graph` to describe the data they contain. - - Attributes: - - roi (:class:`Roi`): - - The region of interested represented by this graph. - - directed (``bool``, optional): - - Whether the graph is directed or not. - - dtype (``dtype``, optional): - - The data type of the "location" attribute. - Currently only supports np.float32. - """ - - def __init__(self, roi=None, directed=None, dtype=np.float32, placeholder=False): - - self.roi = roi - self.directed = directed - self.dtype = dtype - self.placeholder = placeholder - - self.freeze() - -
[docs] def copy(self): - """Create a copy of this spec.""" - return copy.deepcopy(self)
- - def __eq__(self, other): - - if isinstance(other, self.__class__): - return self.__dict__ == other.__dict__ - return NotImplemented - - def __ne__(self, other): - - if isinstance(other, self.__class__): - return not self.__eq__(other) - return NotImplemented - - def __repr__(self): - r = "" - r += "ROI: " + str(self.roi) + ", " - r += "dtype: " + str(self.dtype) + ", " - r += "directed: " + str(self.directed) + ", " - r += "placeholder: " + str(self.placeholder) - return r
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/add_affinities.html b/docs/_modules/gunpowder/nodes/add_affinities.html deleted file mode 100644 index 344c0f8f..00000000 --- a/docs/_modules/gunpowder/nodes/add_affinities.html +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.add_affinities — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.add_affinities
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.add_affinities

-import logging
-import numpy as np
-
-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-from gunpowder.batch_request import BatchRequest
-from gunpowder.batch import Batch
-from gunpowder.coordinate import Coordinate
-
-logger = logging.getLogger(__name__)
-
-
-def seg_to_affgraph(seg,nhood):
-    # constructs an affinity graph from a segmentation
-    # assume affinity graph is represented as:
-    # shape = (e, z, y, x)
-    # nhood.shape = (edges, 3)
-    shape = seg.shape
-    nEdge = nhood.shape[0]
-    aff = np.zeros((nEdge,)+shape,dtype=np.int32)
-
-    for e in range(nEdge):
-        aff[e, \
-            max(0,-nhood[e,0]):min(shape[0],shape[0]-nhood[e,0]), \
-            max(0,-nhood[e,1]):min(shape[1],shape[1]-nhood[e,1]), \
-            max(0,-nhood[e,2]):min(shape[2],shape[2]-nhood[e,2])] = \
-                        (seg[max(0,-nhood[e,0]):min(shape[0],shape[0]-nhood[e,0]), \
-                            max(0,-nhood[e,1]):min(shape[1],shape[1]-nhood[e,1]), \
-                            max(0,-nhood[e,2]):min(shape[2],shape[2]-nhood[e,2])] == \
-                         seg[max(0,nhood[e,0]):min(shape[0],shape[0]+nhood[e,0]), \
-                            max(0,nhood[e,1]):min(shape[1],shape[1]+nhood[e,1]), \
-                            max(0,nhood[e,2]):min(shape[2],shape[2]+nhood[e,2])] ) \
-                        * ( seg[max(0,-nhood[e,0]):min(shape[0],shape[0]-nhood[e,0]), \
-                            max(0,-nhood[e,1]):min(shape[1],shape[1]-nhood[e,1]), \
-                            max(0,-nhood[e,2]):min(shape[2],shape[2]-nhood[e,2])] > 0 ) \
-                        * ( seg[max(0,nhood[e,0]):min(shape[0],shape[0]+nhood[e,0]), \
-                            max(0,nhood[e,1]):min(shape[1],shape[1]+nhood[e,1]), \
-                            max(0,nhood[e,2]):min(shape[2],shape[2]+nhood[e,2])] > 0 )
-
-    return aff
-
-
-
[docs]class AddAffinities(BatchFilter): - '''Add an array with affinities for a given label array and neighborhood to - the batch. Affinity values are created one for each voxel and entry in the - neighborhood list, i.e., for each voxel and each neighbor of this voxel. - Values are 1 iff both labels (of the voxel and the neighbor) are equal and - non-zero. - - Args: - - affinity_neighborhood (``list`` of array-like): - - List of offsets for the affinities to consider for each voxel. - - labels (:class:`ArrayKey`): - - The array to read the labels from. - - affinities (:class:`ArrayKey`): - - The array to generate containing the affinities. - - labels_mask (:class:`ArrayKey`, optional): - - The array to use as a mask for ``labels``. Affinities connecting at - least one masked out label will be masked out in - ``affinities_mask``. If not given, ``affinities_mask`` will contain - ones everywhere (if requested). - - unlabelled (:class:`ArrayKey`, optional): - - A binary array to indicate unlabelled areas with 0. Affinities from - labelled to unlabelled voxels are set to 0, affinities between - unlabelled voxels are masked out (they will not be used for - training). - - affinities_mask (:class:`ArrayKey`, optional): - - The array to generate containing the affinitiy mask, as derived - from parameter ``labels_mask``. - ''' - - def __init__( - self, - affinity_neighborhood, - labels, - affinities, - labels_mask=None, - unlabelled=None, - affinities_mask=None, - dtype=np.uint8): - - self.affinity_neighborhood = np.array(affinity_neighborhood) - self.labels = labels - self.unlabelled = unlabelled - self.labels_mask = labels_mask - self.affinities = affinities - self.affinities_mask = affinities_mask - self.dtype = dtype - - def setup(self): - - assert self.labels in self.spec, ( - "Upstream does not provide %s needed by " - "AddAffinities"%self.labels) - - voxel_size = self.spec[self.labels].voxel_size - - dims = self.affinity_neighborhood.shape[1] - self.padding_neg = Coordinate( - min([0] + [a[d] for a in self.affinity_neighborhood]) - for d in range(dims) - )*voxel_size - - self.padding_pos = Coordinate( - max([0] + [a[d] for a in self.affinity_neighborhood]) - for d in range(dims) - )*voxel_size - - logger.debug("padding neg: " + str(self.padding_neg)) - logger.debug("padding pos: " + str(self.padding_pos)) - - spec = self.spec[self.labels].copy() - if spec.roi is not None: - spec.roi = spec.roi.grow(self.padding_neg, -self.padding_pos) - spec.dtype = self.dtype - - self.provides(self.affinities, spec) - if self.affinities_mask: - self.provides(self.affinities_mask, spec) - self.enable_autoskip() - - def prepare(self, request): - - if self.labels_mask: - assert ( - request[self.labels].roi == - request[self.labels_mask].roi),( - "requested GT label roi %s and GT label mask roi %s are not " - "the same."%( - request[self.labels].roi, - request[self.labels_mask].roi)) - - if self.unlabelled: - assert ( - request[self.labels].roi == - request[self.unlabelled].roi),( - "requested GT label roi %s and GT unlabelled mask roi %s are not " - "the same."%( - request[self.labels].roi, - request[self.unlabelled].roi)) - - deps = BatchRequest() - - # grow labels ROI to accomodate padding - labels_roi = request[self.affinities].roi.grow( - -self.padding_neg, - self.padding_pos) - deps[self.labels] = request[self.affinities].copy() - deps[self.labels].dtype = None - deps[self.labels].roi = labels_roi - - if self.labels_mask: - deps[self.labels_mask] = deps[self.labels].copy() - if self.unlabelled: - deps[self.unlabelled] = deps[self.labels].copy() - - return deps - - def process(self, batch, request): - outputs = Batch() - - affinities_roi = request[self.affinities].roi - - logger.debug("computing ground-truth affinities from labels") - - affinities = seg_to_affgraph( - batch.arrays[self.labels].data.astype(np.int32), - self.affinity_neighborhood - ).astype(self.dtype) - - # crop affinities to requested ROI - offset = affinities_roi.get_offset() - shift = -offset - self.padding_neg - crop_roi = affinities_roi.shift(shift) - crop_roi /= self.spec[self.labels].voxel_size - crop = crop_roi.get_bounding_box() - - logger.debug("cropping with " + str(crop)) - affinities = affinities[(slice(None),)+crop] - - spec = self.spec[self.affinities].copy() - spec.roi = affinities_roi - outputs.arrays[self.affinities] = Array(affinities, spec) - - if self.affinities_mask and self.affinities_mask in request: - - if self.labels_mask: - - logger.debug("computing ground-truth affinities mask from " - "labels mask") - affinities_mask = seg_to_affgraph( - batch.arrays[self.labels_mask].data.astype(np.int32), - self.affinity_neighborhood) - affinities_mask = affinities_mask[(slice(None),)+crop] - - else: - - affinities_mask = np.ones_like(affinities) - - if self.unlabelled: - - # 1 for all affinities between unlabelled voxels - unlabelled = (1 - batch.arrays[self.unlabelled].data) - unlabelled_mask = seg_to_affgraph( - unlabelled.astype(np.int32), - self.affinity_neighborhood) - unlabelled_mask = unlabelled_mask[(slice(None),)+crop] - - # 0 for all affinities between unlabelled voxels - unlabelled_mask = (1 - unlabelled_mask) - - # combine with mask - affinities_mask = affinities_mask*unlabelled_mask - - affinities_mask = affinities_mask.astype(affinities.dtype) - outputs.arrays[self.affinities_mask] = Array(affinities_mask, spec) - - else: - - if self.labels_mask is not None: - logger.warning("GT labels does have a mask, but affinities " - "mask is not requested.") - - # Should probably have a better way of handling arbitrary batch attributes - batch.affinity_neighborhood = self.affinity_neighborhood - - return outputs
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/balance_labels.html b/docs/_modules/gunpowder/nodes/balance_labels.html deleted file mode 100644 index ce58854e..00000000 --- a/docs/_modules/gunpowder/nodes/balance_labels.html +++ /dev/null @@ -1,525 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.balance_labels — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.balance_labels
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.balance_labels

-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-from gunpowder.batch_request import BatchRequest
-from collections.abc import Iterable
-import itertools
-import logging
-import numpy as np
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class BalanceLabels(BatchFilter): - '''Creates a scale array to balance the loss between class labels. - - Note that this only balances loss weights per-batch and does not accumulate - statistics about class balance across batches. - - Args: - - labels (:class:`ArrayKey`): - - An array containing binary or integer labels. - - scales (:class:`ArrayKey`): - - A array with scales to be created. This new array will have the - same ROI and resolution as ``labels``. - - mask (:class:`ArrayKey`, optional): - - An optional mask (or list of masks) to consider for balancing. - Every voxel marked with a 0 will not contribute to the scaling and - will have a scale of 0 in ``scales``. - - slab (``tuple`` of ``int``, optional): - - A shape specification to perform the balancing in slabs of this - size. -1 can be used to refer to the actual size of the label - array. For example, a slab of:: - - (2, -1, -1, -1) - - will perform the balancing for every each slice ``[0:2,:]``, - ``[2:4,:]``, ... individually. - - num_classes(``int``, optional): - - The number of classes. Labels will be expected to be in the - interval [0, ``num_classes``). Defaults to 2 for binary - classification. - - clipmin (``float``, optional): - - Clip class fraction to clipmin when calculating class weights. - Defaults to 0.05. Set to None if you do not want to clip min values. - - clipmax (``float``, optional): - - Clip class fraction to clipmax when calculating class weights. - Defaults to 0.95. Set to None, if you do not want to clip max - values. - - ''' - - def __init__(self, labels, scales, mask=None, slab=None, num_classes=2, - clipmin=0.05, clipmax=0.95): - - self.labels = labels - self.scales = scales - if mask is None: - self.masks = [] - elif not isinstance(mask, Iterable): - self.masks = [mask] - else: - self.masks = mask - - self.slab = slab - self.num_classes = num_classes - self.clipmin = clipmin - self.clipmax = clipmax - - - def setup(self): - - assert self.labels in self.spec, ( - "Asked to balance labels %s, which are not provided."%self.labels) - - for mask in self.masks: - assert mask in self.spec, ( - "Asked to apply mask %s to balance labels, but mask is not " - "provided."%mask) - - spec = self.spec[self.labels].copy() - spec.dtype = np.float32 - self.provides(self.scales, spec) - self.enable_autoskip() - - def prepare(self, request): - - deps = BatchRequest() - deps[self.labels] = request[self.scales] - for mask in self.masks: - deps[mask] = request[self.scales] - return deps - - def process(self, batch, request): - - labels = batch.arrays[self.labels] - - assert len(np.unique(labels.data)) <= self.num_classes, ( - "Found more unique labels than classes in %s."%self.labels) - assert 0 <= np.min(labels.data) < self.num_classes, ( - "Labels %s are not in [0, num_classes)."%self.labels) - assert 0 <= np.max(labels.data) < self.num_classes, ( - "Labels %s are not in [0, num_classes)."%self.labels) - - # initialize error scale with 1s - error_scale = np.ones(labels.data.shape, dtype=np.float32) - - # set error_scale to 0 in masked-out areas - for key in self.masks: - mask = batch.arrays[key] - assert labels.data.shape == mask.data.shape, ( - "Shape of mask %s %s does not match %s %s"%( - mask, - mask.data.shape, - self.labels, - labels.data.shape)) - error_scale *= mask.data - - if not self.slab: - slab = error_scale.shape - else: - # slab with -1 replaced by shape - slab = tuple( - m if s == -1 else s - for m, s in zip(error_scale.shape, self.slab)) - - slab_ranges = ( - range(0, m, s) - for m, s in zip(error_scale.shape, slab)) - - for start in itertools.product(*slab_ranges): - slices = tuple( - slice(start[d], start[d] + slab[d]) - for d in range(len(slab))) - self.__balance( - labels.data[slices], - error_scale[slices]) - - spec = self.spec[self.scales].copy() - spec.roi = labels.spec.roi - batch.arrays[self.scales] = Array(error_scale, spec) - - def __balance(self, labels, scale): - - # in the masked-in area, compute the fraction of per-class samples - masked_in = scale.sum() - classes, counts = np.unique(labels[np.nonzero(scale)], return_counts=True) - fracs = counts.astype(float) / masked_in if masked_in > 0 else np.zeros(counts.size) - if self.clipmin is not None or self.clipmax is not None: - np.clip(fracs, self.clipmin, self.clipmax, fracs) - - # compute the class weights - w_sparse = 1.0 / float(self.num_classes) / fracs - w = np.zeros(self.num_classes) - w[classes] = w_sparse - - # scale the masked-in scale with the class weights - scale *= np.take(w, labels)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/batch_filter.html b/docs/_modules/gunpowder/nodes/batch_filter.html deleted file mode 100644 index e08f1d9e..00000000 --- a/docs/_modules/gunpowder/nodes/batch_filter.html +++ /dev/null @@ -1,609 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.batch_filter — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.batch_filter
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.batch_filter

-import copy
-import logging
-
-from .batch_provider import BatchProvider
-from gunpowder.batch_request import BatchRequest
-from gunpowder.profiling import Timing
-
-logger = logging.getLogger(__name__)
-
-
-class BatchFilterError(Exception):
-
-    def __init__(self, batch_filter, msg):
-        self.batch_filter = batch_filter
-        self.msg = msg
-
-    def __str__(self):
-
-        return f"Error in {self.batch_filter.name()}: {self.msg}"
-
-
-
[docs]class BatchFilter(BatchProvider): - """Convenience wrapper for :class:`BatchProviders<BatchProvider>` with - exactly one input provider. - - By default, a node of this class will expose the same :class:`ProviderSpec` - as the upstream provider. You can modify the provider spec by calling - :func:`provides` and :func:`updates` in :func:`setup`. - - Subclasses need to implement at least :func:`process` to modify a passed - batch (downstream). Optionally, the following methods can be implemented: - - :func:`setup` - - Initialize this filter. Called after setup of the DAG. All upstream - providers will be set up already. - - :func:`teardown` - - Destruct this filter, free resources, stop worker processes. - - :func:`prepare` - - Prepare for a batch request. Always called before each - :func:`process`. Used to communicate dependencies. - """ - - @property - def remove_placeholders(self): - if not hasattr(self, '_remove_placeholders'): - return False - return self._remove_placeholders - - def get_upstream_provider(self): - if len(self.get_upstream_providers()) != 1: - raise BatchFilterError( - self, - "BatchFilters need to have exactly one upstream provider, " - f"this one has {len(self.get_upstream_providers())}: " - f"({[b.name() for b in self.get_upstream_providers()]}") - return self.get_upstream_providers()[0] - -
[docs] def updates(self, key, spec): - """Update an output provided by this :class:`BatchFilter`. - - Implementations should call this in their :func:`setup` method, which - will be called when the pipeline is build. - - Args: - - key (:class:`ArrayKey` or :class:`GraphKey`): - - The array or point set key this filter updates. - - spec (:class:`ArraySpec` or :class:`GraphSpec`): - - The updated spec of the array or point set. - """ - - if key not in self.spec: - raise BatchFilterError( - self, - f"BatchFilter {self} is trying to change the spec for {key}, " - f"but {key} is not provided upstream. Upstream offers: " - f"{self.get_upstream_provider().spec}") - self.spec[key] = copy.deepcopy(spec) - self.updated_items.append(key) - - logger.debug("%s updates %s with %s" % (self.name(), key, spec))
- -
[docs] def enable_autoskip(self, skip=True): - """Enable automatic skipping of this :class:`BatchFilter`, based on - given :func:`updates` and :func:`provides` calls. Has to be called in - :func:`setup`. - - By default, :class:`BatchFilters<BatchFilter>` are not skipped - automatically, regardless of what they update or provide. If autskip is - enabled, :class:`BatchFilters<BatchFilter>` will only be run if the - request contains at least one key reported earlier with - :func:`updates` or :func:`provides`. - """ - - self._autoskip_enabled = skip
- - def _init_spec(self): - # default for BatchFilters is to provide the same as upstream - if not hasattr(self, "_spec") or self._spec is None: - if len(self.get_upstream_providers()) != 0: - self._spec = copy.deepcopy(self.get_upstream_provider().spec) - else: - self._spec = None - - def internal_teardown(self): - - logger.debug("Resetting spec of %s", self.name()) - self._spec = None - self._updated_items = [] - - self.teardown() - - @property - def updated_items(self): - """Get a list of the keys that are updated by this `BatchFilter`. - - This list is only available after the pipeline has been build. Before - that, it is empty. - """ - - if not hasattr(self, "_updated_items"): - self._updated_items = [] - - return self._updated_items - - @property - def autoskip_enabled(self): - - if not hasattr(self, "_autoskip_enabled"): - self._autoskip_enabled = False - - return self._autoskip_enabled - - def provide(self, request): - - skip = self.__can_skip(request) - - timing_prepare = Timing(self, "prepare") - timing_prepare.start() - - downstream_request = request.copy() - - if not skip: - dependencies = self.prepare(request) - if isinstance(dependencies, BatchRequest): - upstream_request = request.merge(dependencies) - elif dependencies is None: - upstream_request = request.copy() - else: - raise BatchFilterError( - self, - f"This BatchFilter returned a {type(dependencies)}! " - "Supported return types are: `BatchRequest` containing your exact " - "dependencies or `None`, indicating a dependency on the full request.") - self.remove_provided(upstream_request) - else: - upstream_request = request.copy() - self.remove_provided(upstream_request) - - timing_prepare.stop() - - batch = self.get_upstream_provider().request_batch(upstream_request) - - timing_process = Timing(self, "process") - timing_process.start() - - if not skip: - if dependencies is not None: - dependencies.remove_placeholders() - node_batch = batch.crop(dependencies) - else: - node_batch = batch - downstream_request.remove_placeholders() - processed_batch = self.process(node_batch, downstream_request) - if processed_batch is None: - processed_batch = node_batch - batch = batch.merge(processed_batch, merge_profiling_stats=False).crop( - downstream_request - ) - - timing_process.stop() - - batch.profiling_stats.add(timing_prepare) - batch.profiling_stats.add(timing_process) - - return batch - - def __can_skip(self, request): - """Check if this filter needs to be run for the given request.""" - - if not self.autoskip_enabled: - return False - - for key, spec in request.items(): - if spec.placeholder: - continue - if key in self.provided_items: - return False - if key in self.updated_items: - return False - - return True - -
[docs] def setup(self): - """To be implemented in subclasses. - - Called during initialization of the DAG. Callees can assume that all - upstream providers are set up already. - - In setup, call :func:`provides` or :func:`updates` to announce the - arrays and points provided or changed by this node. - """ - pass
- -
[docs] def prepare(self, request): - """To be implemented in subclasses. - - Prepare for a batch request. Should return a :class:`BatchRequest` of - needed dependencies. If None is returned, it will be assumed that all - of request is needed. - """ - return None
- -
[docs] def process(self, batch, request): - """To be implemented in subclasses. - - Filter a batch, will be called after :func:`prepare`. Should return a - :class:`Batch` containing modified Arrays and Graphs. Keys in the returned - batch will replace the associated data in the original batch. If None is - returned it is assumed that the batch has been modified in place. ``request`` - is the same as passed to :func:`prepare`, provided for convenience. - - Args: - - batch (:class:`Batch`): - - The batch received from upstream to be modified by this node. - - request (:class:`BatchRequest`): - - The request this node received. The updated batch should meet - this request. - """ - raise BatchFilterError( - self, - "does not implement 'process'")
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/batch_provider.html b/docs/_modules/gunpowder/nodes/batch_provider.html deleted file mode 100644 index a95190bd..00000000 --- a/docs/_modules/gunpowder/nodes/batch_provider.html +++ /dev/null @@ -1,713 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.batch_provider — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.batch_provider
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.batch_provider

-import numpy as np
-
-import copy
-import logging
-import random
-
-from gunpowder.coordinate import Coordinate
-from gunpowder.points_spec import PointsSpec
-from gunpowder.provider_spec import ProviderSpec
-from gunpowder.array import ArrayKey
-from gunpowder.array_spec import ArraySpec
-from gunpowder.graph import GraphKey
-from gunpowder.graph_spec import GraphSpec
-
-logger = logging.getLogger(__name__)
-
-
-class BatchRequestError(Exception):
-
-    def __init__(self, provider, request, batch):
-        self.provider = provider
-        self.request = request
-        self.batch = batch
-
-    def __str__(self):
-
-        return \
-            f"Exception in {self.provider.name()} while processing request" \
-            f"{self.request} \n" \
-            "Batch returned so far:\n" \
-            f"{self.batch}"
-
-
[docs]class BatchProvider(object): - '''Superclass for all nodes in a `gunpowder` graph. - - A :class:`BatchProvider` provides :class:`Batches<Batch>` containing - :class:`Arrays<Array>` and/or :class:`Graph`. The available data is - specified in a :class:`ProviderSpec` instance, accessible via :attr:`spec`. - - To create a new node, subclass this class and implement (at least) - :func:`setup` and :func:`provide`. - - A :class:`BatchProvider` can be linked to any number of other - :class:`BatchProviders<BatchProvider>` upstream. If your node accepts - exactly one upstream provider, consider subclassing :class:`BatchFilter` - instead. - ''' - - def add_upstream_provider(self, provider): - self.get_upstream_providers().append(provider) - return provider - - def remove_upstream_providers(self): - self.upstream_providers = [] - - def get_upstream_providers(self): - if not hasattr(self, 'upstream_providers'): - self.upstream_providers = [] - return self.upstream_providers - - @property - def remove_placeholders(self): - if not hasattr(self, '_remove_placeholders'): - return True - return self._remove_placeholders - -
[docs] def setup(self): - '''To be implemented in subclasses. - - Called during initialization of the DAG. Callees can assume that all - upstream providers are set up already. - - In setup, call :func:`provides` to announce the arrays and points - provided by this node. - ''' - raise NotImplementedError("Class %s does not implement 'setup'"%self.name())
- -
[docs] def teardown(self): - '''To be implemented in subclasses. - - Called during destruction of the DAG. Subclasses should use this to - stop worker processes, if they used some. - ''' - pass
- -
[docs] def provides(self, key, spec): - '''Introduce a new output provided by this :class:`BatchProvider`. - - Implementations should call this in their :func:`setup` method, which - will be called when the pipeline is build. - - Args: - - key (:class:`ArrayKey` or :class:`GraphKey`): - - The array or point set key provided. - - spec (:class:`ArraySpec` or :class:`GraphSpec`): - - The spec of the array or point set provided. - ''' - - logger.debug("Current spec of %s:\n%s", self.name(), self.spec) - - if self.spec is None: - self._spec = ProviderSpec() - - assert key not in self.spec, ( - "Node %s is trying to add spec for %s, but is already " - "provided."%(type(self).__name__, key)) - - self.spec[key] = copy.deepcopy(spec) - self.provided_items.append(key) - - logger.debug("%s provides %s with spec %s", self.name(), key, spec)
- - def _init_spec(self): - if not hasattr(self, '_spec'): - self._spec = None - - def internal_teardown(self): - - logger.debug("Resetting spec of %s", self.name()) - self._spec = None - self._provided_items = [] - - self.teardown() - - @property - def spec(self): - '''Get the :class:`ProviderSpec` of this :class:`BatchProvider`. - - Note that the spec is only available after the pipeline has been build. - Before that, it is ``None``. - ''' - self._init_spec() - return self._spec - - @property - def provided_items(self): - '''Get a list of the keys provided by this :class:`BatchProvider`. - - This list is only available after the pipeline has been build. Before - that, it is empty. - ''' - - if not hasattr(self, '_provided_items'): - self._provided_items = [] - - return self._provided_items - - def remove_provided(self, request): - '''Remove keys from `request` that are provided by this - :class:`BatchProvider`. - ''' - - for key in self.provided_items: - if key in request: - del request[key] - -
[docs] def request_batch(self, request): - '''Request a batch from this provider. - - Args: - - request (:class:`BatchRequest`): - - A request containing (possibly partial) - :class:`ArraySpecs<ArraySpec>` and - :class:`GraphSpecs<GraphSpec>`. - ''' - - batch = None - - try: - - request._update_random_seed() - - self.set_seeds(request) - - logger.debug("%s got request %s", self.name(), request) - - self.check_request_consistency(request) - - upstream_request = request.copy() - if self.remove_placeholders: - upstream_request.remove_placeholders() - batch = self.provide(upstream_request) - - request.remove_placeholders() - - self.check_batch_consistency(batch, request) - - self.remove_unneeded(batch, request) - - logger.debug("%s provides %s", self.name(), batch) - - except Exception as e: - - raise BatchRequestError(self, request, batch) from e - - return batch
- - def set_seeds(self, request): - seed = request.random_seed - random.seed(seed) - # augment uses numpy for its randomness - np.random.seed(seed) - - def check_request_consistency(self, request): - - for (key, request_spec) in request.items(): - - assert key in self.spec, "%s: Asked for %s which this node does not provide"%(self.name(), key) - assert ( - isinstance(request_spec, ArraySpec) or - isinstance(request_spec, PointsSpec) or - isinstance(request_spec, GraphSpec)), ("spec for %s is of type" - "%s"%( - key, - type(request_spec))) - - provided_spec = self.spec[key] - - provided_roi = provided_spec.roi - request_roi = request_spec.roi - - if provided_roi is not None: - assert provided_roi.contains(request_roi), "%s: %s's ROI %s outside of my ROI %s"%(self.name(), key, request_roi, provided_roi) - - if isinstance(key, ArrayKey): - - if request_spec.voxel_size is not None: - assert provided_spec.voxel_size == request_spec.voxel_size, "%s: voxel size %s requested for %s, but this node provides %s"%( - self.name(), - request_spec.voxel_size, - key, - provided_spec.voxel_size) - - if ( - request_roi is not None and - provided_spec.voxel_size is not None): - - for d in range(request_roi.dims()): - assert request_roi.get_shape()[d]%provided_spec.voxel_size[d] == 0, \ - "in request %s, dimension %d of request %s is not a multiple of voxel_size %d"%( - request, - d, - key, - provided_spec.voxel_size[d]) - - if isinstance(key, GraphKey): - - if request_spec.directed is not None: - assert request_spec.directed == provided_spec.directed, ( - f"asked for {key}: directed={request_spec.directed} but " - f"{self.name()} provides directed={provided_spec.directed}" - ) - def check_batch_consistency(self, batch, request): - - for (array_key, request_spec) in request.array_specs.items(): - - assert array_key in batch.arrays, "%s requested, but %s did not provide it."%(array_key,self.name()) - array = batch.arrays[array_key] - assert array.spec.roi == request_spec.roi, "%s ROI %s requested, but ROI %s provided by %s."%( - array_key, - request_spec.roi, - array.spec.roi, - self.name() - ) - assert array.spec.voxel_size == self.spec[array_key].voxel_size, ( - "voxel size of %s announced, but %s " - "delivered for %s"%( - self.spec[array_key].voxel_size, - array.spec.voxel_size, - array_key)) - # ensure that the spatial dimensions are the same (other dimensions - # on top are okay, e.g., for affinities) - if request_spec.roi is not None: - dims = request_spec.roi.dims() - data_shape = Coordinate(array.data.shape[-dims:]) - voxel_size = self.spec[array_key].voxel_size - assert data_shape == request_spec.roi.get_shape()/voxel_size, "%s ROI %s requested, but size of array is %s*%s=%s provided by %s."%( - array_key, - request_spec.roi, - data_shape, - voxel_size, - data_shape*voxel_size, - self.name() - ) - if request_spec.dtype is not None: - assert batch[array_key].data.dtype == request_spec.dtype, \ - "dtype of array %s (%s) does not match requested dtype %s by %s" % ( - array_key, - batch[array_key].data.dtype, - request_spec.dtype, - self.name()) - - for (graph_key, request_spec) in request.graph_specs.items(): - - assert graph_key in batch.graphs, "%s requested, but %s did not provide it."%(graph_key,self.name()) - graph = batch.graphs[graph_key] - assert graph.spec.roi == request_spec.roi, "%s ROI %s requested, but ROI %s provided by %s."%( - graph_key, - request_spec.roi, - graph.spec.roi, - self.name()) - - if request_spec.directed is not None: - assert request_spec.directed == graph.directed, ( - f"Recieved {graph_key}: directed={graph.directed} but " - f"{self.name()} should provide directed={request_spec.directed}" - ) - - for node in graph.nodes: - contained = graph.spec.roi.contains(node.location) - dangling = not contained and all( - [ - graph.spec.roi.contains(v.location) - for v in graph.neighbors(node) - ] - ) - assert contained or dangling, ( - f"graph {graph_key} provided by {self.name()} with ROI {graph.spec.roi} " - f"contain point at {node.location} which is neither contained nor " - f"'dangling'" - ) - - def remove_unneeded(self, batch, request): - - batch_keys = set(list(batch.arrays.keys()) + list(batch.graphs.keys())) - for key in batch_keys: - if key not in request: - del batch[key] - - def enable_placeholders(self): - self._remove_placeholders = False - -
[docs] def provide(self, request): - '''To be implemented in subclasses. - - This function takes a :class:`BatchRequest` and should return the - corresponding :class:`Batch`. - - Args: - - request(:class:`BatchRequest`): - - The request to process. - ''' - raise NotImplementedError("Class %s does not implement 'provide'"%self.name())
- - def name(self): - return type(self).__name__ - - def __repr__(self): - - return self.name() + ", providing: " + str(self.spec)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/crop.html b/docs/_modules/gunpowder/nodes/crop.html deleted file mode 100644 index 44df8b6d..00000000 --- a/docs/_modules/gunpowder/nodes/crop.html +++ /dev/null @@ -1,444 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.crop — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.nodes.crop

-import copy
-import logging
-
-from .batch_filter import BatchFilter
-from gunpowder.coordinate import Coordinate
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Crop(BatchFilter): - '''Limits provided ROIs by either giving a new :class:`Roi` or crop - fractions from either face of the provided ROI. - - Args: - - key (:class:`ArrayKey` or :class:`GraphKey`): - - The key of the array or points set to modify. - - roi (:class:`Roi` or ``None``): - - The ROI to crop to. - - fraction_negative (``tuple`` of ``float``): - - Relative crop starting from the negative end of the provided ROI. - - fraction_positive (``tuple`` of ``float``): - - Relative crop starting from the positive end of the provided ROI. - ''' - - def __init__( - self, - key, - roi=None, - fraction_negative=None, - fraction_positive=None): - - if roi is not None and ( - fraction_positive is not None or - fraction_negative is not None): - raise RuntimeError( - "'roi' and 'fraction_...' arguments can not be given together") - - if (roi, fraction_positive, fraction_negative) == (None, None, None): - raise RuntimeError( - "One of 'roi' and 'fraction_...' has to be given") - - if fraction_negative is not None and fraction_positive is None: - fraction_positive = (0.0,)*len(fraction_negative) - if fraction_positive is not None and fraction_negative is None: - fraction_negative = (0.0,)*len(fraction_positive) - - self.key = key - self.roi = roi - self.fraction_negative = fraction_negative - self.fraction_positive = fraction_positive - - def setup(self): - - spec = self.spec[self.key] - - if self.roi is not None: - - assert spec.roi.contains(self.roi), ( - "Crop ROI is not contained in upstream ROI.") - - cropped_roi = self.roi - - else: - - total_fraction = tuple( - n + p - for n, p in zip(self.fraction_negative, self.fraction_positive) - ) - if max(total_fraction) >= 1: - raise RuntimeError("Sum of crop fractions exeeds 1") - - crop_positive = spec.roi.get_shape()*self.fraction_positive - crop_negative = spec.roi.get_shape()*self.fraction_negative - cropped_roi = spec.roi.grow( - -crop_positive, - -crop_negative) - - spec.roi = cropped_roi - self.updates(self.key, spec) - - def process(self, batch, request): - pass
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/csv_points_source.html b/docs/_modules/gunpowder/nodes/csv_points_source.html deleted file mode 100644 index 40a97d5b..00000000 --- a/docs/_modules/gunpowder/nodes/csv_points_source.html +++ /dev/null @@ -1,492 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.csv_points_source — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.csv_points_source
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.csv_points_source

-import numpy as np
-import logging
-from gunpowder.batch import Batch
-from gunpowder.coordinate import Coordinate
-from gunpowder.nodes.batch_provider import BatchProvider
-from gunpowder.graph import Node, Graph
-from gunpowder.graph_spec import GraphSpec
-from gunpowder.profiling import Timing
-from gunpowder.roi import Roi
-
-logger = logging.getLogger(__name__)
-
-
[docs]class CsvPointsSource(BatchProvider): - '''Read a set of points from a comma-separated-values text file. Each line - in the file represents one point, e.g. z y x (id) - - Args: - - filename (``string``): - - The file to read from. - - points (:class:`GraphKey`): - - The key of the points set to create. - - points_spec (:class:`GraphSpec`, optional): - - An optional :class:`GraphSpec` to overwrite the points specs - automatically determined from the CSV file. This is useful to set - the :class:`Roi` manually. - - scale (scalar or array-like): - - An optional scaling to apply to the coordinates of the points read - from the CSV file. This is useful if the points refer to voxel - positions to convert them to world units. - - ndims (``int``): - - If ``ndims`` is None, all values in one line are considered as the - location of the point. If positive, only the first ``ndims`` are used. - If negative, all but the last ``-ndims`` are used. - - id_dim (``int``): - - Each line may optionally contain an id for each point. This parameter - specifies its location, has to come after the position values. - ''' - - def __init__(self, filename, points, points_spec=None, scale=None, - ndims=None, id_dim=None): - - self.filename = filename - self.points = points - self.points_spec = points_spec - self.scale = scale - self.ndims = ndims - self.id_dim = id_dim - self.data = None - - def setup(self): - - self._parse_csv() - - if self.points_spec is not None: - - self.provides(self.points, self.points_spec) - return - - min_bb = Coordinate(np.floor(np.amin(self.data[:,:self.ndims], 0))) - max_bb = Coordinate(np.ceil(np.amax(self.data[:,:self.ndims], 0)) + 1) - - roi = Roi(min_bb, max_bb - min_bb) - - self.provides(self.points, GraphSpec(roi=roi)) - - def provide(self, request): - - timing = Timing(self) - timing.start() - - min_bb = request[self.points].roi.get_begin() - max_bb = request[self.points].roi.get_end() - - logger.debug( - "CSV points source got request for %s", - request[self.points].roi) - - point_filter = np.ones((self.data.shape[0],), dtype=np.bool) - for d in range(self.ndims): - point_filter = np.logical_and(point_filter, self.data[:,d] >= min_bb[d]) - point_filter = np.logical_and(point_filter, self.data[:,d] < max_bb[d]) - - points_data = self._get_points(point_filter) - points_spec = GraphSpec(roi=request[self.points].roi.copy()) - - batch = Batch() - batch.graphs[self.points] = Graph(points_data, [], points_spec) - - timing.stop() - batch.profiling_stats.add(timing) - - return batch - - def _get_points(self, point_filter): - - filtered = self.data[point_filter][:,:self.ndims] - - if self.id_dim is not None: - ids = self.data[point_filter][:,self.id_dim] - else: - ids = np.arange(len(self.data))[point_filter] - - return [ - Node(id=i, location=p) - for i, p in zip(ids, filtered) - ] - - def _parse_csv(self): - '''Read one point per line. If ``ndims`` is None, all values in one line - are considered as the location of the point. If positive, only the - first ``ndims`` are used. If negative, all but the last ``-ndims`` are - used. - ''' - - with open(self.filename, "r") as f: - self.data = np.array( - [[float(t.strip(",")) for t in line.split()] for line in f], - dtype=np.float32, - ) - - if self.ndims is None: - self.ndims = self.data.shape[1] - - if self.scale is not None: - self.data[:,:self.ndims] *= self.scale
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/daisy_request_blocks.html b/docs/_modules/gunpowder/nodes/daisy_request_blocks.html deleted file mode 100644 index c82f2a9d..00000000 --- a/docs/_modules/gunpowder/nodes/daisy_request_blocks.html +++ /dev/null @@ -1,494 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.daisy_request_blocks — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.daisy_request_blocks
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.daisy_request_blocks

-from gunpowder.batch import Batch
-from gunpowder.ext import daisy
-from gunpowder.nodes.batch_filter import BatchFilter
-from gunpowder.roi import Roi
-import logging
-import multiprocessing
-import time
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class DaisyRequestBlocks(BatchFilter): - '''Iteratively requests batches similar to ``reference`` from upstream - providers, with their ROIs set to blocks distributed by ``daisy``. - - The ROIs of the array or point specs in the reference can be set to either - the block's ``read_roi`` or ``write_roi``, see parameter ``roi_map``. - - The batch request to this node has to be empty, as there is no guarantee - that this node will get to process all chunks required to fulfill a - particular batch request. - - Args: - - reference (:class:`BatchRequest`): - - A reference :class:`BatchRequest`. This request will be shifted - according to blocks distributed by ``daisy``. - - roi_map (``dict`` from :class:`ArrayKey` or :class:`GraphKey` to - ``string``): - - A map indicating which daisy block ROI (``read_roi`` or - ``write_roi``) to use for which item in the reference request. - - num_workers (``int``, optional): - - If set to >1, upstream requests are made in parallel with that - number of workers. - - block_done_callback (function, optional): - - If given, will be called with arguments ``(block, start, - duration)`` for each block that was processed. ``start`` and - ``duration`` will be given in seconds, as in ``start = - time.time()`` and ``duration = time.time() - start``, right before - and after a block gets processed. - - This callback can be used to log blocks that have successfully - finished processing, which can be used in ``check_function`` of - ``daisy.run_blockwise`` to skip already processed blocks in - repeated runs. - ''' - - def __init__( - self, - reference, - roi_map, - num_workers=1, - block_done_callback=None): - - self.reference = reference - self.roi_map = roi_map - self.num_workers = num_workers - self.block_done_callback = block_done_callback - - if num_workers > 1: - self.request_queue = multiprocessing.Queue(maxsize=0) - - def provide(self, request): - - empty_request = (len(request) == 0) - if not empty_request: - raise RuntimeError( - "requests made to DaisyRequestBlocks have to be empty") - - if self.num_workers > 1: - - self.workers = [ - multiprocessing.Process(target=self.__get_chunks) - for _ in range(self.num_workers) - ] - - for worker in self.workers: - worker.start() - - for worker in self.workers: - worker.join() - - else: - - self.__get_chunks() - - return Batch() - - def __get_chunks(self): - - daisy_client = daisy.Client() - - while True: - - block = daisy_client.acquire_block() - - if block is None: - return - - logger.info("Processing block %s", block) - start = time.time() - - chunk_request = self.reference.copy() - - for key, reference_spec in self.reference.items(): - - roi_type = self.roi_map.get(key, None) - - if roi_type is None: - raise RuntimeError( - "roi_map does not map item %s to either 'read_roi' " - "or 'write_roi'" % key) - - if roi_type == 'read_roi': - chunk_request[key].roi = Roi( - block.read_roi.get_offset(), - block.read_roi.get_shape()) - elif roi_type == 'write_roi': - chunk_request[key].roi = Roi( - block.write_roi.get_offset(), - block.write_roi.get_shape()) - else: - raise RuntimeError( - "%s is not a vaid ROI type (read_roi or write_roi)") - - self.get_upstream_provider().request_batch(chunk_request) - - end = time.time() - if self.block_done_callback: - self.block_done_callback(block, start, end - start) - - daisy_client.release_block(block, ret=0)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/defect_augment.html b/docs/_modules/gunpowder/nodes/defect_augment.html deleted file mode 100644 index b7b769d8..00000000 --- a/docs/_modules/gunpowder/nodes/defect_augment.html +++ /dev/null @@ -1,669 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.defect_augment — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.defect_augment
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.defect_augment

-import logging
-import random
-import numpy as np
-
-# imports for deformed slice
-from skimage.draw import line
-from scipy.ndimage.measurements import label
-from scipy.ndimage.interpolation import map_coordinates
-from scipy.ndimage.morphology import binary_dilation
-
-from gunpowder.batch_request import BatchRequest
-from gunpowder.coordinate import Coordinate
-from .batch_filter import BatchFilter
-
-logger = logging.getLogger(__name__)
-
-
[docs]class DefectAugment(BatchFilter): - '''Augment intensity arrays section-wise with artifacts like missing - sections, low-contrast sections, by blending in artifacts drawn from a - separate source, or by deforming a section. - - Args: - - intensities (:class:`ArrayKey`): - - The key of the array of intensities to modify. - - prob_missing(``float``): - prob_low_contrast(``float``): - prob_artifact(``float``): - prob_deform(``float``): - - Probabilities of having a missing section, low-contrast section, an - artifact (see param ``artifact_source``) or a deformed slice. The - sum should not exceed 1. Values in missing sections will be set to - 0. - - contrast_scale (``float``, optional): - - By how much to scale the intensities for a low-contrast section, - used if ``prob_low_contrast`` > 0. - - artifact_source (class:`BatchProvider`, optional): - - A gunpowder batch provider that delivers intensities (via - :class:`ArrayKey` ``artifacts``) and an alpha mask (via - :class:`ArrayKey` ``artifacts_mask``), used if ``prob_artifact`` > 0. - - artifacts(:class:`ArrayKey`, optional): - - The key to query ``artifact_source`` for to get the intensities - of the artifacts. - - artifacts_mask(:class:`ArrayKey`, optional): - - The key to query ``artifact_source`` for to get the alpha mask - of the artifacts to blend them with ``intensities``. - - deformation_strength (``int``, optional): - - Strength of the slice deformation in voxels, used if - ``prob_deform`` > 0. The deformation models a fold by shifting the - section contents towards a randomly oriented line in the section. - The line itself will be drawn with a value of 0. - - axis (``int``, optional): - - Along which axis sections are cut. - ''' - - def __init__( - self, - intensities, - prob_missing=0.05, - prob_low_contrast=0.05, - prob_artifact=0.0, - prob_deform=0.0, - contrast_scale=0.1, - artifact_source=None, - artifacts=None, - artifacts_mask=None, - deformation_strength=20, - axis=0): - self.intensities = intensities - self.prob_missing = prob_missing - self.prob_low_contrast = prob_low_contrast - self.prob_artifact = prob_artifact - self.prob_deform = prob_deform - self.contrast_scale = contrast_scale - self.artifact_source = artifact_source - self.artifacts = artifacts - self.artifacts_mask = artifacts_mask - self.deformation_strength = deformation_strength - self.axis = axis - - def setup(self): - - if self.artifact_source is not None: - self.artifact_source.setup() - - def teardown(self): - - if self.artifact_source is not None: - self.artifact_source.teardown() - - # send roi request to data-source upstream - def prepare(self, request): - random.seed(request.random_seed) - deps = BatchRequest() - - # we prepare the augmentations, by determining which slices - # will be augmented by which method - # If one of the slices is augmented with 'deform', - # we prepare these trafos already - # and request a bigger roi from upstream - - prob_missing_threshold = self.prob_missing - prob_low_contrast_threshold = prob_missing_threshold + self.prob_low_contrast - prob_artifact_threshold = prob_low_contrast_threshold + self.prob_artifact - prob_deform_slice = prob_artifact_threshold + self.prob_deform - - spec = request[self.intensities].copy() - roi = spec.roi - logger.debug("downstream request ROI is %s" % roi) - raw_voxel_size = self.spec[self.intensities].voxel_size - - # store the mapping slice to augmentation type in a dict - self.slice_to_augmentation = {} - # store the transformations for deform slice - self.deform_slice_transformations = {} - for c in range((roi / raw_voxel_size).get_shape()[self.axis]): - r = random.random() - - if r < prob_missing_threshold: - logger.debug("Zero-out " + str(c)) - self.slice_to_augmentation[c] = 'zero_out' - - elif r < prob_low_contrast_threshold: - logger.debug("Lower contrast " + str(c)) - self.slice_to_augmentation[c] = 'lower_contrast' - - elif r < prob_artifact_threshold: - logger.debug("Add artifact " + str(c)) - self.slice_to_augmentation[c] = 'artifact' - - elif r < prob_deform_slice: - logger.debug("Add deformed slice " + str(c)) - self.slice_to_augmentation[c] = 'deformed_slice' - # get the shape of a single slice - slice_shape = (roi / raw_voxel_size).get_shape() - slice_shape = slice_shape[:self.axis] + slice_shape[self.axis+1:] - self.deform_slice_transformations[c] = self.__prepare_deform_slice(slice_shape) - - # prepare transformation and - # request bigger upstream roi for deformed slice - if 'deformed_slice' in self.slice_to_augmentation.values(): - - # create roi sufficiently large to feed deformation - logger.debug("before growth: %s" % spec.roi) - growth = Coordinate( - tuple(0 if d == self.axis else raw_voxel_size[d] * self.deformation_strength - for d in range(spec.roi.dims())) - ) - logger.debug("growing request by %s" % str(growth)) - source_roi = roi.grow(growth, growth) - - # update request ROI to get all voxels necessary to perfrom - # transformation - spec.roi = source_roi - logger.debug("upstream request roi is %s" % spec.roi) - - deps[self.intensities] = spec - - def process(self, batch, request): - - assert batch.get_total_roi().dims() == 3, "defectaugment works on 3d batches only" - - raw = batch.arrays[self.intensities] - raw_voxel_size = self.spec[self.intensities].voxel_size - - for c, augmentation_type in self.slice_to_augmentation.items(): - - section_selector = tuple( - slice(None if d != self.axis else c, None if d != self.axis else c+1) - for d in range(raw.spec.roi.dims()) - ) - - if augmentation_type == 'zero_out': - raw.data[section_selector] = 0 - - elif augmentation_type == 'low_contrast': - section = raw.data[section_selector] - - mean = section.mean() - section -= mean - section *= self.contrast_scale - section += mean - - raw.data[section_selector] = section - - elif augmentation_type == 'artifact': - - section = raw.data[section_selector] - - alpha_voxel_size = self.artifact_source.spec[self.artifacts_mask].voxel_size - - assert raw_voxel_size == alpha_voxel_size, ("Can only alpha blend RAW with " - "ALPHA_MASK if both have the same " - "voxel size") - - artifact_request = BatchRequest() - artifact_request.add(self.artifacts, Coordinate(section.shape) * raw_voxel_size, voxel_size=raw_voxel_size) - artifact_request.add(self.artifacts_mask, Coordinate(section.shape) * alpha_voxel_size, voxel_size=raw_voxel_size) - logger.debug("Requesting artifact batch %s", artifact_request) - - artifact_batch = self.artifact_source.request_batch(artifact_request) - artifact_alpha = artifact_batch.arrays[self.artifacts_mask].data - artifact_raw = artifact_batch.arrays[self.artifacts].data - - assert artifact_alpha.dtype == np.float32 - assert artifact_alpha.min() >= 0.0 - assert artifact_alpha.max() <= 1.0 - - raw.data[section_selector] = section*(1.0 - artifact_alpha) + artifact_raw*artifact_alpha - - elif augmentation_type == 'deformed_slice': - - section = raw.data[section_selector].squeeze() - - # set interpolation to cubic, spec interploatable is true, else to 0 - interpolation = 3 if self.spec[self.intensities].interpolatable else 0 - - # load the deformation fields that were prepared for this slice - flow_x, flow_y, line_mask = self.deform_slice_transformations[c] - - # apply the deformation fields - shape = section.shape - section = map_coordinates( - section, (flow_y, flow_x), mode='constant', order=interpolation - ).reshape(shape) - - # things can get smaller than 0 at the boundary, so we clip - section = np.clip(section, 0., 1.) - - # zero-out data below the line mask - section[line_mask] = 0. - - raw.data[section_selector] = section - - # in case we needed to change the ROI due to a deformation augment, - # restore original ROI and crop the array data - if 'deformed_slice' in self.slice_to_augmentation.values(): - old_roi = request[self.intensities].roi - logger.debug("resetting roi to %s" % old_roi) - crop = tuple( - slice(None) if d == self.axis else slice(self.deformation_strength, -self.deformation_strength) - for d in range(raw.spec.roi.dims()) - ) - raw.data = raw.data[crop] - raw.spec.roi = old_roi - - def __prepare_deform_slice(self, slice_shape): - - # grow slice shape by 2 x deformation strength - grow_by = 2 * self.deformation_strength - shape = (slice_shape[0] + grow_by, slice_shape[1] + grow_by) - - # randomly choose fixed x or fixed y with p = 1/2 - fixed_x = random.random() < .5 - if fixed_x: - x0, y0 = 0, np.random.randint(1, shape[1] - 2) - x1, y1 = shape[0] - 1, np.random.randint(1, shape[1] - 2) - else: - x0, y0 = np.random.randint(1, shape[0] - 2), 0 - x1, y1 = np.random.randint(1, shape[0] - 2), shape[1] - 1 - - ## generate the mask of the line that should be blacked out - line_mask = np.zeros(shape, dtype='bool') - rr, cc = line(x0, y0, x1, y1) - line_mask[rr, cc] = 1 - - # generate vectorfield pointing towards the line to compress the image - # first we get the unit vector representing the line - line_vector = np.array([x1 - x0, y1 - y0], dtype='float32') - line_vector /= np.linalg.norm(line_vector) - # next, we generate the normal to the line - normal_vector = np.zeros_like(line_vector) - normal_vector[0] = - line_vector[1] - normal_vector[1] = line_vector[0] - - # make meshgrid - x, y = np.meshgrid(np.arange(shape[1]), np.arange(shape[0])) - # generate the vector field - flow_x, flow_y = np.zeros(shape), np.zeros(shape) - - # find the 2 components where coordinates are bigger / smaller than the line - # to apply normal vector in the correct direction - components, n_components = label(np.logical_not(line_mask).view('uint8')) - assert n_components == 2, "%i" % n_components - neg_val = components[0, 0] if fixed_x else components[-1, -1] - pos_val = components[-1, -1] if fixed_x else components[0, 0] - - flow_x[components == pos_val] = self.deformation_strength * normal_vector[1] - flow_y[components == pos_val] = self.deformation_strength * normal_vector[0] - flow_x[components == neg_val] = - self.deformation_strength * normal_vector[1] - flow_y[components == neg_val] = - self.deformation_strength * normal_vector[0] - - # generate the flow fields - flow_x, flow_y = (x + flow_x).reshape(-1, 1), (y + flow_y).reshape(-1, 1) - - # dilate the line mask - line_mask = binary_dilation(line_mask, iterations=10) - - return flow_x, flow_y, line_mask
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/downsample.html b/docs/_modules/gunpowder/nodes/downsample.html deleted file mode 100644 index ebcd1386..00000000 --- a/docs/_modules/gunpowder/nodes/downsample.html +++ /dev/null @@ -1,430 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.downsample — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.downsample
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.downsample

-from .batch_filter import BatchFilter
-from gunpowder.array import ArrayKey, Array
-from gunpowder.batch_request import BatchRequest
-from gunpowder.batch import Batch
-import logging
-import numbers
-
-logger = logging.getLogger(__name__)
-
-
[docs]class DownSample(BatchFilter): - '''Downsample arrays in a batch by given factors. - - Args: - - source (:class:`ArrayKey`): - - The key of the array to downsample. - - factor (``int`` or ``tuple`` of ``int``): - - The factor to downsample with. - - target (:class:`ArrayKey`): - - The key of the array to store the downsampled ``source``. - ''' - - def __init__(self, source, factor, target): - - assert isinstance(source, ArrayKey) - assert isinstance(target, ArrayKey) - assert ( - isinstance(factor, numbers.Number) or isinstance(factor, tuple)), ( - "Scaling factor should be a number or a tuple of numbers.") - - self.source = source - self.factor = factor - self.target = target - - def setup(self): - - spec = self.spec[self.source].copy() - spec.voxel_size *= self.factor - self.provides(self.target, spec) - self.enable_autoskip() - - def prepare(self, request): - - deps = BatchRequest() - deps[self.source] = request[self.target] - return deps - - def process(self, batch, request): - outputs = Batch() - - # downsample - if isinstance(self.factor, tuple): - slices = tuple( - slice(None, None, k) - for k in self.factor) - else: - slices = tuple( - slice(None, None, self.factor) - for i in range(batch[self.source].spec.roi.dims())) - - logger.debug("downsampling %s with %s", self.source, slices) - - data = batch.arrays[self.source].data[slices] - - # create output array - spec = self.spec[self.target].copy() - spec.roi = request[self.target].roi - outputs.arrays[self.target] = Array(data, spec) - - return outputs
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/dvid_source.html b/docs/_modules/gunpowder/nodes/dvid_source.html deleted file mode 100644 index 3e524b27..00000000 --- a/docs/_modules/gunpowder/nodes/dvid_source.html +++ /dev/null @@ -1,649 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.dvid_source — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.dvid_source
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.dvid_source

-import logging
-import numpy as np
-
-from gunpowder.batch import Batch
-from gunpowder.coordinate import Coordinate
-from gunpowder.ext import dvision
-from gunpowder.profiling import Timing
-from gunpowder.roi import Roi
-from gunpowder.array import Array
-from gunpowder.array_spec import ArraySpec
-from .batch_provider import BatchProvider
-
-logger = logging.getLogger(__name__)
-
-
[docs]class DvidSource(BatchProvider): - '''A DVID array source. - - Provides arrays from DVID servers for each array key given. - - Args: - - hostname (``string``): - - The name of the DVID server. - - port (``int``): - - The port of the DVID server. - - uuid (``string``): - - The UUID of the DVID node to use. - - datasets (``dict``, :class:`ArrayKey` -> ``string``): - - Dictionary mapping array keys to DVID data instance names that this - source offers. - - masks (``dict``, :class:`ArrayKey` -> ``string``, optional): - - Dictionary of array keys to DVID ROI instance names. This will - create binary masks from DVID ROIs. - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - An optional dictionary of array keys to specs to overwrite the - array specs automatically determined from the DVID server. This is - useful to set ``voxel_size``, for example. Only fields that are not - ``None`` in the given :class:`ArraySpec` will be used. - ''' - - def __init__( - self, - hostname, - port, - uuid, - datasets, - masks=None, - array_specs=None): - - self.hostname = hostname - self.port = port - self.url = "http://{}:{}".format(self.hostname, self.port) - self.uuid = uuid - - self.datasets = datasets - self.masks = masks if masks is not None else {} - - self.array_specs = array_specs if array_specs is not None else {} - - self.ndims = None - - def setup(self): - - for array_key, _ in self.datasets.items(): - spec = self.__get_spec(array_key) - self.provides(array_key, spec) - - for array_key, _ in self.masks.items(): - spec = self.__get_mask_spec(array_key) - self.provides(array_key, spec) - - logger.info("DvidSource.spec:\n%s", self.spec) - - def provide(self, request): - - timing = Timing(self) - timing.start() - - batch = Batch() - - for (array_key, request_spec) in request.array_specs.items(): - - logger.debug("Reading %s in %s...", array_key, request_spec.roi) - - voxel_size = self.spec[array_key].voxel_size - - # scale request roi to voxel units - dataset_roi = request_spec.roi/voxel_size - - # shift request roi into dataset - dataset_roi = dataset_roi - self.spec[array_key].roi.get_offset()/voxel_size - - # create array spec - array_spec = self.spec[array_key].copy() - array_spec.roi = request_spec.roi - - # read the data - if array_key in self.datasets: - data = self.__read_array(self.datasets[array_key], dataset_roi) - elif array_key in self.masks: - data = self.__read_mask(self.masks[array_key], dataset_roi) - else: - assert False, ("Encountered a request for %s that is neither a volume " - "nor a mask."%array_key) - - # add array to batch - batch.arrays[array_key] = Array(data, array_spec) - - logger.debug("done") - - timing.stop() - batch.profiling_stats.add(timing) - - return batch - - def __get_info(self, array_key): - - if array_key in self.datasets: - - data = dvision.DVIDDataInstance( - self.hostname, - self.port, - self.uuid, - self.datasets[array_key]) - - elif array_key in self.masks: - - data = dvision.DVIDRegionOfInterest( - self.hostname, - self.port, - self.uuid, - self.masks[array_key]) - - else: - - assert False, ("Encountered a request that is neither a volume " - "nor a mask.") - - return data.info - - def __get_spec(self, array_key): - - info = self.__get_info(array_key) - - roi_min = info['Extended']['MinPoint'] - if roi_min is not None: - roi_min = Coordinate(roi_min[::-1]) - roi_max = info['Extended']['MaxPoint'] - if roi_max is not None: - roi_max = Coordinate(roi_max[::-1]) - - data_roi = Roi( - offset=roi_min, - shape=(roi_max - roi_min)) - data_dims = Coordinate(data_roi.get_shape()) - - if self.ndims is None: - self.ndims = len(data_dims) - else: - assert self.ndims == len(data_dims) - - if array_key in self.array_specs: - spec = self.array_specs[array_key].copy() - else: - spec = ArraySpec() - - if spec.voxel_size is None: - spec.voxel_size = Coordinate(info['Extended']['VoxelSize']) - - if spec.roi is None: - spec.roi = data_roi*spec.voxel_size - - data_dtype = dvision.DVIDDataInstance( - self.hostname, - self.port, - self.uuid, - self.datasets[array_key]).dtype - - if spec.dtype is not None: - assert spec.dtype == data_dtype, ("dtype %s provided in array_specs for %s, " - "but differs from instance %s dtype %s"% - (self.array_specs[array_key].dtype, - array_key, - self.datasets[array_key], - data_dtype)) - else: - spec.dtype = data_dtype - - if spec.interpolatable is None: - - spec.interpolatable = spec.dtype in [ - np.float, - np.float32, - np.float64, - np.float128, - np.uint8 # assuming this is not used for labels - ] - logger.warning("WARNING: You didn't set 'interpolatable' for %s. " - "Based on the dtype %s, it has been set to %s. " - "This might not be what you want.", - array_key, spec.dtype, spec.interpolatable) - - return spec - - def __get_mask_spec(self, mask_key): - - # create initial array spec - - if mask_key in self.array_specs: - spec = self.array_specs[mask_key].copy() - else: - spec = ArraySpec() - - # get voxel size - - if spec.voxel_size is None: - - voxel_size = None - for array_key in self.datasets: - if voxel_size is None: - voxel_size = self.spec[array_key].voxel_size - else: - assert voxel_size == self.spec[array_key].voxel_size, ( - "No voxel size was given for mask %s, and the voxel " - "sizes of the volumes %s are not all the same. I don't " - "know what voxel size to use to create the mask."%( - mask_key, self.datasets.keys())) - - spec.voxel_size = voxel_size - - # get ROI - - if spec.roi is None: - - for array_key in self.datasets: - - roi = self.spec[array_key].roi - - if spec.roi is None: - spec.roi = roi.copy() - else: - spec.roi = roi.union(spec.roi) - - # set interpolatable - - if spec.interpolatable is None: - spec.interpolatable = False - - # set datatype - - if spec.dtype is not None and spec.dtype != np.uint8: - logger.warn("Ignoring dtype in array_spec for %s, only np.uint8 " - "is allowed for masks.", mask_key) - spec.dtype = np.uint8 - - return spec - - def __read_array(self, instance, roi): - - data_instance = dvision.DVIDDataInstance( - self.hostname, - self.port, - self.uuid, - instance) - - return data_instance[roi.get_bounding_box()] - - def __read_mask(self, instance, roi): - - dvid_roi = dvision.DVIDRegionOfInterest( - self.hostname, - self.port, - self.uuid, - instance) - - return dvid_roi[roi.get_bounding_box()] - - def __repr__(self): - - return "DvidSource(hostname={}, port={}, uuid={}".format( - self.hostname, - self.port, - self.uuid)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/elastic_augment.html b/docs/_modules/gunpowder/nodes/elastic_augment.html deleted file mode 100644 index ba7d0d79..00000000 --- a/docs/_modules/gunpowder/nodes/elastic_augment.html +++ /dev/null @@ -1,981 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.elastic_augment — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.elastic_augment
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.elastic_augment

-import logging
-import math
-import numpy as np
-import random
-from scipy import ndimage
-
-from .batch_filter import BatchFilter
-from gunpowder.batch_request import BatchRequest
-from gunpowder.coordinate import Coordinate
-from gunpowder.ext import augment
-from gunpowder.roi import Roi
-from gunpowder.array import ArrayKey
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class ElasticAugment(BatchFilter): - """Elasticly deform a batch. Requests larger batches upstream to avoid data - loss due to rotation and jitter. - - Args: - - control_point_spacing (``tuple`` of ``int``): - - Distance between control points for the elastic deformation, in - voxels per dimension. - - jitter_sigma (``tuple`` of ``float``): - - Standard deviation of control point jitter distribution, in voxels - per dimension. - - rotation_interval (``tuple`` of two ``floats``): - - Interval to randomly sample rotation angles from (0, 2PI). - - prob_slip (``float``): - - Probability of a section to "slip", i.e., be independently moved in - x-y. - - prob_shift (``float``): - - Probability of a section and all following sections to move in x-y. - - max_misalign (``int``): - - Maximal voxels to shift in x and y. Samples will be drawn - uniformly. Used if ``prob_slip + prob_shift`` > 0. - - subsample (``int``): - - Instead of creating an elastic transformation on the full - resolution, create one subsampled by the given factor, and linearly - interpolate to obtain the full resolution transformation. This can - significantly speed up this node, at the expense of having visible - piecewise linear deformations for large factors. Usually, a factor - of 4 can savely by used without noticable changes. However, the - default is 1 (i.e., no subsampling). - - spatial_dims (``int``): - - The number of spatial dimensions in arrays. Spatial dimensions are - assumed to be the last ones and cannot be more than 3 (default). - Set this value here to avoid treating channels as spacial - dimension. If, for example, your array is indexed as ``(c,y,x)`` - (2D plus channels), you would want to set ``spatial_dims=2`` to - perform the elastic deformation only on x and y. - - use_fast_points_transform (``bool``): - - By solving for all of your points simultaneously with the following - 3 step proceedure: - 1) Rasterize nodes into numpy array - 2) Apply elastic transform to array - 3) Read out nodes via center of mass of transformed points - You can gain substantial speed up as opposed to calculating the - elastic transform for each point individually. However this may - lead to nodes being lost during the transform. - - recompute_missing_points (``bool``): - - Whether or not to compute the elastic transform node wise for nodes - that were lossed during the fast elastic transform process. - """ - - def __init__( - self, - control_point_spacing, - jitter_sigma, - rotation_interval, - prob_slip=0, - prob_shift=0, - max_misalign=0, - subsample=1, - spatial_dims=3, - use_fast_points_transform=False, - recompute_missing_points=True, - ): - - self.control_point_spacing = control_point_spacing - self.jitter_sigma = jitter_sigma - self.rotation_start = rotation_interval[0] - self.rotation_max_amount = rotation_interval[1] - rotation_interval[0] - self.prob_slip = prob_slip - self.prob_shift = prob_shift - self.max_misalign = max_misalign - self.subsample = subsample - self.spatial_dims = spatial_dims - self.use_fast_points_transform = use_fast_points_transform - self.recompute_missing_points = recompute_missing_points - - def prepare(self, request): - seed = request.random_seed - random.seed(seed) - # augment uses numpy for its randomness - np.random.seed(seed) - - # get the voxel size - self.voxel_size = self.__get_common_voxel_size(request) - - # get the total ROI of all requests - total_roi = request.get_total_roi() - logger.debug("total ROI is %s" % total_roi) - - # First, get the total ROI of the request in spatial dimensions only. - # Channels and time don't matter. This is our master ROI. - - # get master ROI - master_roi = Roi( - total_roi.get_begin()[-self.spatial_dims :], - total_roi.get_shape()[-self.spatial_dims :], - ) - self.spatial_dims = master_roi.dims() - logger.debug("master ROI is %s" % master_roi) - - # make sure the master ROI aligns with the voxel size - master_roi = master_roi.snap_to_grid(self.voxel_size, mode="grow") - logger.debug("master ROI aligned with voxel size is %s" % master_roi) - - # get master roi in voxels - master_roi_voxels = master_roi / self.voxel_size - logger.debug("master ROI in voxels is %s" % master_roi_voxels) - - # Second, create a master transformation. This is a transformation that - # covers all voxels of the all requested ROIs. The master transformation - # is zero-based. - - # create a transformation with the size of the master ROI in voxels - self.master_transformation = self.__create_transformation( - master_roi_voxels.get_shape() - ) - - # Third, crop out parts of the master transformation for each of the - # smaller requested ROIs. Since these ROIs now have to align with the - # voxel size (which for points does not have to be the case), we also - # remember these smaller ROIs as target_rois in global world units. - - # crop the parts corresponding to the requested ROIs - self.transformations = {} - self.target_rois = {} - deps = BatchRequest() - for key, spec in request.items(): - - spec = spec.copy() - - if spec.roi is None: - continue - - target_roi = Roi( - spec.roi.get_begin()[-self.spatial_dims :], - spec.roi.get_shape()[-self.spatial_dims :], - ) - logger.debug("downstream request spatial ROI for %s is %s", key, target_roi) - - # make sure the target ROI aligns with the voxel grid (which might - # not be the case for points) - target_roi = target_roi.snap_to_grid(self.voxel_size, mode="grow") - logger.debug( - "downstream request spatial ROI aligned with voxel grid for %s " - "is %s", - key, - target_roi, - ) - - # remember target ROI (this is where the transformation will project - # to) - self.target_rois[key] = target_roi - - # get ROI in voxels - target_roi_voxels = target_roi / self.voxel_size - - # get ROI relative to master ROI - target_roi_in_master_roi_voxels = ( - target_roi_voxels - master_roi_voxels.get_begin() - ) - - # crop out relevant part of transformation for this request - transformation = np.copy( - self.master_transformation[ - (slice(None),) + target_roi_in_master_roi_voxels.get_bounding_box() - ] - ) - self.transformations[key] = transformation - - # get ROI of all voxels necessary to perfrom transformation - # - # for that we follow the same transformations to get from the - # request ROI to the target ROI in master ROI in voxels, just in - # reverse - source_roi_in_master_roi_voxels = self.__get_source_roi(transformation) - source_roi_voxels = ( - source_roi_in_master_roi_voxels + master_roi_voxels.get_begin() - ) - source_roi = source_roi_voxels * self.voxel_size - - # transformation is still defined on voxels relative to master ROI - # in voxels (i.e., lowest source coordinate could be 5, but data - # array we get later starts at 0). - # - # shift transformation to be indexed relative to beginning of - # source_roi_voxels - self.__shift_transformation( - -source_roi_in_master_roi_voxels.get_begin(), transformation - ) - - # update upstream request - spec.roi = Roi( - spec.roi.get_begin()[: -self.spatial_dims] - + source_roi.get_begin()[-self.spatial_dims :], - spec.roi.get_shape()[: -self.spatial_dims] - + source_roi.get_shape()[-self.spatial_dims :], - ) - - deps[key] = spec - - logger.debug("upstream request roi for %s = %s" % (key, spec.roi)) - - return deps - - def process(self, batch, request): - - for (array_key, array) in batch.arrays.items(): - - if array_key not in self.target_rois: - continue - - # for arrays, the target ROI and the requested ROI should be the - # same in spatial coordinates - assert ( - self.target_rois[array_key].get_begin() - == request[array_key].roi.get_begin()[-self.spatial_dims :] - ), "Target roi offset {} does not match request roi offset {}".format( - self.target_rois[array_key].get_begin(), - request[array_key].roi.get_begin()[-self.spatial_dims :], - ) - - assert ( - self.target_rois[array_key].get_shape() - == request[array_key].roi.get_shape()[-self.spatial_dims :] - ), "Target roi offset {} does not match request roi offset {}".format( - self.target_rois[array_key].get_shape(), - request[array_key].roi.get_shape()[-self.spatial_dims :], - ) - - # reshape array data into (channels,) + spatial dims - shape = array.data.shape - channel_shape = shape[: -self.spatial_dims] - data = array.data.reshape((-1,) + shape[-self.spatial_dims :]) - - # apply transformation on each channel - data = np.array( - [ - augment.apply_transformation( - data[c], - self.transformations[array_key], - interpolate=self.spec[array_key].interpolatable, - ) - for c in range(data.shape[0]) - ] - ) - - data_roi = request[array_key].roi/self.spec[array_key].voxel_size - array.data = data.reshape(channel_shape + data_roi.get_shape()[-self.spatial_dims:]) - - # restore original ROIs - array.spec.roi = request[array_key].roi - - for (graph_key, graph) in batch.graphs.items(): - - nodes = list(graph.nodes) - - if self.use_fast_points_transform: - missed_nodes = self.__fast_point_projection( - self.transformations[graph_key], - nodes, - graph.spec.roi, - target_roi=self.target_rois[graph_key], - ) - if not self.recompute_missing_points: - for node in set(missed_nodes): - graph.remove_node(node, retain_connectivity=True) - missed_nodes = [] - else: - missed_nodes = nodes - - for node in missed_nodes: - # logger.debug("projecting %s", node.location) - - # get location relative to beginning of upstream ROI - location = node.location - graph.spec.roi.get_begin() - logger.debug("relative to upstream ROI: %s", location) - - # get spatial coordinates of node in voxels - location_voxels = location[-self.spatial_dims :] / self.voxel_size - - # get projected location in transformation data space, this - # yields voxel coordinates relative to target ROI - projected_voxels = self.__project( - self.transformations[graph_key], location_voxels - ) - - logger.debug( - "projected in voxels, relative to target ROI: %s", projected_voxels - ) - - if projected_voxels is None: - logger.debug("node outside of target, skipping") - graph.remove_node(node, retain_connectivity=True) - continue - - # convert to world units (now in float again) - projected = projected_voxels * np.array(self.voxel_size) - - logger.debug( - "projected in world units, relative to target ROI: %s", - projected) - - # get global coordinates - projected += np.array(self.target_rois[graph_key].get_begin()) - - # update spatial coordinates of node location - node.location[-self.spatial_dims:] = projected - - logger.debug("final location: %s", node.location) - - # finally, it can happen that a node no longer is contained in - # the requested ROI (because larger ROIs than necessary have - # been requested upstream) - if not request[graph_key].roi.contains(node.location): - logger.debug("node outside of target, skipping") - graph.remove_node(node, retain_connectivity=True) - continue - - # restore original ROIs - graph.spec.roi = request[graph_key].roi - - def __get_common_voxel_size(self, request): - - voxel_size = None - prev = None - for array_key in request.array_specs.keys(): - if voxel_size is None: - voxel_size = self.spec[array_key].voxel_size[-self.spatial_dims:] - elif self.spec[array_key].voxel_size is not None: - assert voxel_size == self.spec[array_key].voxel_size[-self.spatial_dims:], \ - "ElasticAugment can only be used with arrays of same voxel sizes, " \ - "but %s has %s, and %s has %s."%( - array_key, self.spec[array_key].voxel_size, - prev, self.spec[prev].voxel_size) - prev = array_key - - if voxel_size is None: - raise RuntimeError("voxel size must not be None") - - return voxel_size - - def __create_transformation(self, target_shape): - - transformation = augment.create_identity_transformation( - target_shape, subsample=self.subsample - ) - if sum(self.jitter_sigma) > 0: - transformation += augment.create_elastic_transformation( - target_shape, - self.control_point_spacing, - self.jitter_sigma, - subsample=self.subsample, - ) - rotation = random.random() * self.rotation_max_amount + self.rotation_start - if rotation != 0: - transformation += augment.create_rotation_transformation( - target_shape, rotation, subsample=self.subsample - ) - - if self.subsample > 1: - transformation = augment.upscale_transformation( - transformation, target_shape - ) - - if self.prob_slip + self.prob_shift > 0: - self.__misalign(transformation) - - return transformation - - def __fast_point_projection( - self, transformation, nodes, source_roi, target_roi - ): - if len(nodes) < 1: - return [] - # rasterize the points into an array - ids, locs = zip( - *[ - ( - node.id, - (np.floor(node.location).astype(int) - source_roi.get_begin()) - // self.voxel_size, - ) - for node in nodes - if source_roi.contains(node.location) - ] - ) - ids, locs = np.array(ids), tuple(zip(*locs)) - points_array = np.zeros( - source_roi.get_shape() / self.voxel_size, dtype=np.int64 - ) - points_array[locs] = ids - - # reshape array data into (channels,) + spatial dims - shape = points_array.shape - data = points_array.reshape((-1,) + shape[-self.spatial_dims :]) - - # apply transformation on each channel - data = np.array( - [ - augment.apply_transformation( - data[c], transformation, interpolate="nearest" - ) - for c in range(data.shape[0]) - ] - ) - - missing_points = [] - projected_locs = ndimage.measurements.center_of_mass(data > 0, data, ids) - projected_locs = [ - np.array(loc[-self.spatial_dims :]) * self.voxel_size - + target_roi.get_begin() - for loc in projected_locs - ] - node_dict = {node.id:node for node in nodes} - for point_id, proj_loc in zip(ids, projected_locs): - point = node_dict.pop(point_id) - if not any([np.isnan(x) for x in proj_loc]): - assert ( - len(proj_loc) == self.spatial_dims - ), "projected location has wrong number of dimensions: {}, expected: {}".format( - len(proj_loc), self.spatial_dims - ) - point.location[-self.spatial_dims :] = proj_loc - else: - missing_points.append(point) - for node in node_dict.values(): - missing_points.append(point) - logger.debug( - "{} of {} points lost in fast points projection".format( - len(missing_points), len(ids) - ) - ) - - return missing_points - - def __project(self, transformation, location): - """Find the projection of location given by transformation. Returns None - if projection lies outside of transformation.""" - - dims = len(location) - - # subtract location from transformation - diff = transformation.copy() - for d in range(dims): - diff[d] -= location[d] - - # square - diff2 = diff * diff - - # sum - dist = diff2.sum(axis=0) - - # find grid point closes to location - center_grid = Coordinate(np.unravel_index(dist.argmin(), dist.shape)) - center_source = self.__source_at(transformation, center_grid) - - logger.debug("projecting %s onto grid", location) - logger.debug("grid shape: %s", transformation.shape[1:]) - logger.debug("grid projection: %s", center_grid) - logger.debug("dist shape: %s", dist.shape) - logger.debug("dist.argmin(): %s", dist.argmin()) - logger.debug("dist[argmin]: %s", dist[center_grid]) - logger.debug("transform[argmin]: %s", - transformation[(slice(None),) + center_grid]) - logger.debug("min dist: %s", dist.min()) - logger.debug("center source: %s", center_source) - - # inspect grid edges incident to center_grid - for d in range(dims): - - # nothing to do for dimensions without spatial extent - if transformation.shape[1 + d] == 1: - continue - - dim_vector = tuple(1 if dd == d else 0 for dd in range(dims)) - pos_grid = center_grid + dim_vector - neg_grid = center_grid - dim_vector - logger.debug("interpolating along %s", dim_vector) - - pos_u = -1 - neg_u = -1 - - if pos_grid[d] < transformation.shape[1 + d]: - pos_source = self.__source_at(transformation, pos_grid) - logger.debug("pos source: %s", pos_source) - pos_dist = pos_source[d] - center_source[d] - loc_dist = location[d] - center_source[d] - if pos_dist != 0: - pos_u = loc_dist / pos_dist - else: - pos_u = 0 - - if neg_grid[d] >= 0: - neg_source = self.__source_at(transformation, neg_grid) - logger.debug("neg source: %s", neg_source) - neg_dist = neg_source[d] - center_source[d] - loc_dist = location[d] - center_source[d] - if neg_dist != 0: - neg_u = loc_dist / neg_dist - else: - neg_u = 0 - - logger.debug("pos u/neg u: %s/%s", pos_u, neg_u) - - # if a point only falls behind edges, it lies outside of the grid - if pos_u < 0 and neg_u < 0: - return None - - return np.array(center_grid, dtype=np.float32) - - def __source_at(self, transformation, index): - """Read the source point of a transformation at index.""" - - slices = (slice(None),) + tuple(slice(i, i + 1) for i in index) - return transformation[slices].flatten() - - def __get_source_roi(self, transformation): - - dims = transformation.shape[0] - - # get bounding box of needed data for transformation - bb_min = Coordinate( - int(math.floor(transformation[d].min())) for d in range(dims) - ) - bb_max = Coordinate( - int(math.ceil(transformation[d].max())) + 1 for d in range(dims) - ) - - # create roi sufficiently large to feed transformation - source_roi = Roi(bb_min, bb_max - bb_min) - - return source_roi - - def __shift_transformation(self, shift, transformation): - - for d in range(transformation.shape[0]): - transformation[d] += shift[d] - - def __misalign(self, transformation): - - assert ( - transformation.shape[0] == 3 - ), "misalign can only be applied to 3D volumes" - - num_sections = transformation[0].shape[0] - - shifts = [Coordinate((0, 0, 0))] * num_sections - for z in range(num_sections): - - r = random.random() - - if r <= self.prob_slip: - - shifts[z] = self.__random_offset() - - elif r <= self.prob_slip + self.prob_shift: - - offset = self.__random_offset() - for zp in range(z, num_sections): - shifts[zp] += offset - - logger.debug("misaligning sections with " + str(shifts)) - - dims = 3 - bb_min = tuple(int(math.floor(transformation[d].min())) for d in range(dims)) - bb_max = tuple(int(math.ceil(transformation[d].max())) + 1 for d in range(dims)) - logger.debug("min/max of transformation: " + str(bb_min) + "/" + str(bb_max)) - - for z in range(num_sections): - transformation[1][z, :, :] += shifts[z][1] - transformation[2][z, :, :] += shifts[z][2] - - bb_min = tuple(int(math.floor(transformation[d].min())) for d in range(dims)) - bb_max = tuple(int(math.ceil(transformation[d].max())) + 1 for d in range(dims)) - logger.debug( - "min/max of transformation after misalignment: " - + str(bb_min) - + "/" - + str(bb_max) - ) - - def __random_offset(self): - - return Coordinate( - (0,) - + tuple( - self.max_misalign - random.randint(0, 2 * int(self.max_misalign)) - for d in range(2) - ) - )
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/exclude_labels.html b/docs/_modules/gunpowder/nodes/exclude_labels.html deleted file mode 100644 index 20c6614a..00000000 --- a/docs/_modules/gunpowder/nodes/exclude_labels.html +++ /dev/null @@ -1,461 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.exclude_labels — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.exclude_labels
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.exclude_labels

-import logging
-import numpy as np
-from scipy.ndimage.morphology import distance_transform_edt
-
-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-
-logger = logging.getLogger(__name__)
-
-
[docs]class ExcludeLabels(BatchFilter): - '''Excludes several labels from the ground-truth. - - The labels will be replaced by background_value. An optional ignore mask - will be created and set to 0 for the excluded locations that are further - than a threshold away from not excluded locations. - - Args: - - labels (:class:`ArrayKey`): - - The array containing the labels. - - exclude (``list`` of ``int``): - - The labels to exclude from ``labels``. - - ignore_mask (:class:`ArrayKey`, optional): - - The ignore mask to create. - - ignore_mask_erode (``float``, optional): - - By how much (in world units) to erode the ignore mask. - - background_value (``int``, optional): - - Value to replace excluded IDs, defaults to 0. - ''' - - def __init__( - self, - labels, - exclude, - ignore_mask=None, - ignore_mask_erode=0, - background_value=0): - - self.labels = labels - self.exclude = set(exclude) - self.ignore_mask = ignore_mask - self.ignore_mask_erode = ignore_mask_erode - self.background_value = background_value - - def setup(self): - - assert self.labels in self.spec, "ExcludeLabels can only be used if GT_LABELS is provided upstream." - if self.ignore_mask: - self.provides(self.ignore_mask, self.spec[self.labels]) - - def process(self, batch, request): - - gt = batch.arrays[self.labels] - - # 0 marks included regions (to be used directly with distance transform - # later) - include_mask = np.ones(gt.data.shape) - - gt_labels = np.unique(gt.data) - logger.debug("batch contains GT labels: " + str(gt_labels)) - for label in gt_labels: - if label in self.exclude: - logger.debug("excluding label " + str(label)) - gt.data[gt.data==label] = self.background_value - else: - include_mask[gt.data==label] = 0 - - # if no ignore mask is provided or requested, we are done - if not self.ignore_mask or not self.ignore_mask in request: - return - - voxel_size = self.spec[self.labels].voxel_size - distance_to_include = distance_transform_edt(include_mask, sampling=voxel_size) - logger.debug("max distance to foreground is " + str(distance_to_include.max())) - - # 1 marks included regions, plus a context area around them - include_mask = distance_to_include<self.ignore_mask_erode - - # include mask was computed on labels ROI, we need to copy it to - # the requested ignore_mask ROI - gt_ignore_roi = request[self.ignore_mask].roi - - intersection = gt.spec.roi.intersect(gt_ignore_roi) - intersection_in_gt = intersection - gt.spec.roi.get_offset() - intersection_in_gt_ignore = intersection - gt_ignore_roi.get_offset() - - # to voxel coordinates - intersection_in_gt //= voxel_size - intersection_in_gt_ignore //= voxel_size - - gt_ignore = np.zeros((gt_ignore_roi//voxel_size).get_shape(), dtype=np.uint8) - gt_ignore[intersection_in_gt_ignore.get_bounding_box()] = include_mask[intersection_in_gt.get_bounding_box()] - - spec = self.spec[self.labels].copy() - spec.roi = gt_ignore_roi - spec.dtype = np.uint8 - batch.arrays[self.ignore_mask] = Array(gt_ignore, spec)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/grow_boundary.html b/docs/_modules/gunpowder/nodes/grow_boundary.html deleted file mode 100644 index 97b825f4..00000000 --- a/docs/_modules/gunpowder/nodes/grow_boundary.html +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.grow_boundary — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.grow_boundary
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.grow_boundary

-import numpy as np
-from scipy import ndimage
-
-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-
-
[docs]class GrowBoundary(BatchFilter): - '''Grow a boundary between regions in a label array. Does not grow at the - border of the batch or an optionally provided mask. - - Args: - - labels (:class:`ArrayKey`): - - The array containing labels. - - mask (:class:`ArrayKey`, optional): - - A mask indicating unknown regions. This is to avoid boundaries to - grow between labelled and unknown regions. - - steps (``int``, optional): - - Number of voxels (not world units!) to grow. - - background (``int``, optional): - - The label to assign to the boundary voxels. - - only_xy (``bool``, optional): - - Do not grow a boundary in the z direction. - ''' - - def __init__(self, labels, mask=None, steps=1, background=0, only_xy=False): - self.labels = labels - self.mask = mask - self.steps = steps - self.background = background - self.only_xy = only_xy - - def process(self, batch, request): - - gt = batch.arrays[self.labels] - gt_mask = None if not self.mask else batch.arrays[self.mask] - - if gt_mask is not None: - - # grow only in area where mask and gt are defined - crop = gt_mask.spec.roi.intersect(gt.spec.roi) - - if crop is None: - raise RuntimeError("GT_LABELS %s and GT_MASK %s ROIs don't intersect."%(gt.spec.roi,gt_mask.spec.roi)) - voxel_size = self.spec[self.labels].voxel_size - crop_in_gt = (crop.shift(-gt.spec.roi.get_offset())/voxel_size).get_bounding_box() - crop_in_gt_mask = (crop.shift(-gt_mask.spec.roi.get_offset())/voxel_size).get_bounding_box() - - self.__grow(gt.data[crop_in_gt], gt_mask.data[crop_in_gt_mask], self.only_xy) - - else: - - self.__grow(gt.data, only_xy=self.only_xy) - - def __grow(self, gt, gt_mask=None, only_xy=False): - if gt_mask is not None: - assert gt.shape == gt_mask.shape, "GT_LABELS and GT_MASK do not have the same size." - - if only_xy: - assert len(gt.shape) == 3 - for z in range(gt.shape[0]): - self.__grow(gt[z], None if gt_mask is None else gt_mask[z]) - return - - # get all foreground voxels by erosion of each component - foreground = np.zeros(shape=gt.shape, dtype=np.bool) - masked = None - if gt_mask is not None: - masked = np.equal(gt_mask, 0) - for label in np.unique(gt): - if label == self.background: - continue - label_mask = gt==label - # Assume that masked out values are the same as the label we are - # eroding in this iteration. This ensures that at the boundary to - # a masked region the value blob is not shrinking. - if masked is not None: - label_mask = np.logical_or(label_mask, masked) - eroded_label_mask = ndimage.binary_erosion(label_mask, iterations=self.steps, border_value=1) - foreground = np.logical_or(eroded_label_mask, foreground) - - # label new background - background = np.logical_not(foreground) - gt[background] = self.background
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/hdf5_source.html b/docs/_modules/gunpowder/nodes/hdf5_source.html deleted file mode 100644 index 318df890..00000000 --- a/docs/_modules/gunpowder/nodes/hdf5_source.html +++ /dev/null @@ -1,394 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.hdf5_source — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.hdf5_source
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.hdf5_source

-from gunpowder.ext import h5py
-from .hdf5like_source_base import Hdf5LikeSource
-
-
[docs]class Hdf5Source(Hdf5LikeSource): - '''An HDF5 data source. - - Provides arrays from HDF5 datasets. If the attribute ``resolution`` is set - in a HDF5 dataset, it will be used as the array's ``voxel_size``. If the - attribute ``offset`` is set in a dataset, it will be used as the offset of - the :class:`Roi` for this array. It is assumed that the offset is given in - world units. - - Args: - - filename (``string``): - - The HDF5 file. - - datasets (``dict``, :class:`ArrayKey` -> ``string``): - - Dictionary of array keys to dataset names that this source offers. - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - An optional dictionary of array keys to array specs to overwrite - the array specs automatically determined from the data file. This - is useful to set a missing ``voxel_size``, for example. Only fields - that are not ``None`` in the given :class:`ArraySpec` will be used. - - channels_first (``bool``, optional): - - Specifies the ordering of the dimensions of the HDF5-like data source. - If channels_first is set (default), then the input shape is expected - to be (channels, spatial dimensions). This is recommended because of - better performance. If channels_first is set to false, then the input - data is read in channels_last manner and converted to channels_first. - ''' - def _open_file(self, filename): - return h5py.File(filename, 'r')
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/hdf5_write.html b/docs/_modules/gunpowder/nodes/hdf5_write.html deleted file mode 100644 index 40312741..00000000 --- a/docs/_modules/gunpowder/nodes/hdf5_write.html +++ /dev/null @@ -1,400 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.hdf5_write — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.hdf5_write
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.hdf5_write

-from .hdf5like_write_base import Hdf5LikeWrite
-from gunpowder.ext import h5py
-import os
-
-
[docs]class Hdf5Write(Hdf5LikeWrite): - '''Assemble arrays of passing batches in one HDF5 file. This is useful to - store chunks produced by :class:`Scan` on disk without keeping the larger - array in memory. The ROIs of the passing arrays will be used to determine - the position where to store the data in the dataset. - - Args: - - dataset_names (``dict``, :class:`ArrayKey` -> ``string``): - - A dictionary from array keys to names of the datasets to store them - in. - - output_dir (``string``): - - The directory to save the HDF5 file. Will be created, if it does - not exist. - - output_filename (``string``): - - The output filename of the container. Will be created, if it does - not exist, otherwise data is overwritten in the existing container. - - compression_type (``string`` or ``int``): - - Compression strategy. Legal values are ``gzip``, ``szip``, - ``lzf``. If an integer between 1 and 10, this indicates ``gzip`` - compression level. - - dataset_dtypes (``dict``, :class:`ArrayKey` -> data type): - - A dictionary from array keys to datatype (eg. ``np.int8``). If - given, arrays are stored using this type. The original arrays - within the pipeline remain unchanged. - ''' - - def _open_file(self, filename): - if os.path.exists(filename): - return h5py.File(filename, 'r+') - else: - return h5py.File(filename, 'w')
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/intensity_augment.html b/docs/_modules/gunpowder/nodes/intensity_augment.html deleted file mode 100644 index cd21e0ae..00000000 --- a/docs/_modules/gunpowder/nodes/intensity_augment.html +++ /dev/null @@ -1,442 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.intensity_augment — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.intensity_augment
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.intensity_augment

-import numpy as np
-
-from gunpowder.batch_request import BatchRequest
-
-from .batch_filter import BatchFilter
-
-
[docs]class IntensityAugment(BatchFilter): - '''Randomly scale and shift the values of an intensity array. - - Args: - - array (:class:`ArrayKey`): - - The intensity array to modify. - - scale_min (``float``): - scale_max (``float``): - shift_min (``float``): - shift_max (``float``): - - The min and max of the uniformly randomly drawn scaling and - shifting values for the intensity augmentation. Intensities are - changed as:: - - a = a.mean() + (a-a.mean())*scale + shift - - z_section_wise (``bool``): - - Perform the augmentation z-section wise. Requires 3D arrays and - assumes that z is the first dimension. - - clip (``bool``): - - Set to False if modified values should not be clipped to [0, 1] - Disables range check! - ''' - - def __init__(self, array, scale_min, scale_max, shift_min, shift_max, z_section_wise=False, clip=True): - self.array = array - self.scale_min = scale_min - self.scale_max = scale_max - self.shift_min = shift_min - self.shift_max = shift_max - self.z_section_wise = z_section_wise - self.clip = clip - - def setup(self): - self.enable_autoskip() - self.updates(self.array, self.spec[self.array]) - - def prepare(self, request): - # TODO: move all randomness into the prepare method - # TODO: write a test for this node - np.random.seed(request.random_seed) - deps = BatchRequest() - deps[self.array] = request[self.array].copy() - return deps - - def process(self, batch, request): - - raw = batch.arrays[self.array] - - assert not self.z_section_wise or raw.spec.roi.dims() == 3, "If you specify 'z_section_wise', I expect 3D data." - assert raw.data.dtype == np.float32 or raw.data.dtype == np.float64, "Intensity augmentation requires float types for the raw array (not " + str(raw.data.dtype) + "). Consider using Normalize before." - if self.clip: - assert raw.data.min() >= 0 and raw.data.max() <= 1, "Intensity augmentation expects raw values in [0,1]. Consider using Normalize before." - - if self.z_section_wise: - for z in range((raw.spec.roi/self.spec[self.array].voxel_size).get_shape()[0]): - raw.data[z] = self.__augment( - raw.data[z], - np.random.uniform(low=self.scale_min, high=self.scale_max), - np.random.uniform(low=self.shift_min, high=self.shift_max)) - else: - raw.data = self.__augment( - raw.data, - np.random.uniform(low=self.scale_min, high=self.scale_max), - np.random.uniform(low=self.shift_min, high=self.shift_max)) - - # clip values, we might have pushed them out of [0,1] - if self.clip: - raw.data[raw.data>1] = 1 - raw.data[raw.data<0] = 0 - - def __augment(self, a, scale, shift): - - return a.mean() + (a-a.mean())*scale + shift
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/intensity_scale_shift.html b/docs/_modules/gunpowder/nodes/intensity_scale_shift.html deleted file mode 100644 index 777cd2b6..00000000 --- a/docs/_modules/gunpowder/nodes/intensity_scale_shift.html +++ /dev/null @@ -1,384 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.intensity_scale_shift — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.intensity_scale_shift
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.intensity_scale_shift

-from .batch_filter import BatchFilter
-
-
[docs]class IntensityScaleShift(BatchFilter): - '''Scales the intensities of a batch by ``scale``, then adds ``shift``. - - Args: - - array (:class:`ArrayKey`): - - The key of the array to modify. - - scale (``float``): - shift (``float``): - - The shift and scale to apply to ``array``. - ''' - - def __init__(self, array, scale, shift): - self.array = array - self.scale = scale - self.shift = shift - - def process(self, batch, request): - - if self.array not in batch.arrays: - return - - raw = batch.arrays[self.array] - raw.data = raw.data*self.scale + self.shift
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/klb_source.html b/docs/_modules/gunpowder/nodes/klb_source.html deleted file mode 100644 index 6144c1a9..00000000 --- a/docs/_modules/gunpowder/nodes/klb_source.html +++ /dev/null @@ -1,576 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.klb_source — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.klb_source
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.klb_source

-import copy
-import logging
-import numpy as np
-import glob
-
-from gunpowder.batch import Batch
-from gunpowder.coordinate import Coordinate
-from gunpowder.ext import pyklb
-from gunpowder.profiling import Timing
-from gunpowder.roi import Roi
-from gunpowder.array import Array
-from gunpowder.array_spec import ArraySpec
-from .batch_provider import BatchProvider
-
-logger = logging.getLogger(__name__)
-
-
[docs]class KlbSource(BatchProvider): - '''A `KLB <https://bitbucket.org/fernandoamat/keller-lab-block-filetype>`_ - data source. - - Provides a single array from the given KLB dataset. - - Args: - - filename (``string``): - - The name of the KLB file. This string can be a glob expression - (e.g., ``frame_*.klb``), in which case all files that match are - sorted and stacked together to form an additional dimension (like - time). The additional dimension will start at 0 and have a default - voxel size of 1 (which can be overwritten using the ``array_spec`` - argument). - - array (:class:`ArrayKey`): - - ArrayKey that this source offers. - - array_spec (:class:`ArraySpec`, optional): - - An optional :class:`ArraySpec` to overwrite the array specs - automatically determined from the KLB file. This is useful to set - ``voxel_size``, for example. Only fields that are not ``None`` in - the given :class:`ArraySpec` will be used. - - num_threads (``int``): - - An optional integer to pass to pyklb reader indicating the number - of threads to use when reading klb files. Entering None causes - uses the pyklb default, which now is based on the number of cores - in the machine. This pyklb default is bad for jobs on the cluster that - are limited to the number of cores requested, and 1 is recommended. - - ''' - - def __init__( - self, - filename, - array, - array_spec=None, - num_threads=1): - - self.filename = filename - self.array = array - self.array_spec = array_spec - self.num_threads = num_threads - - self.files = None - self.ndims = None - - def setup(self): - - self.files = glob.glob(self.filename) - self.files.sort() - - logger.info("Reading KLB headers of %d files...", len(self.files)) - headers = [ pyklb.readheader(f) for f in self.files ] - spec = self.__read_spec(headers) - - self.provides(self.array, spec) - - def provide(self, request): - - timing = Timing(self) - timing.start() - - batch = Batch() - - request_spec = request[self.array] - - logger.debug("Reading %s in %s...", self.array, request_spec.roi) - - voxel_size = self.spec[self.array].voxel_size - - # scale request roi to voxel units - dataset_roi = request_spec.roi/voxel_size - - # shift request roi into dataset - dataset_roi = dataset_roi - self.spec[self.array].roi.get_offset()/voxel_size - - # create array spec - array_spec = self.spec[self.array].copy() - array_spec.roi = request_spec.roi - - # add array to batch - batch.arrays[self.array] = Array( - self.__read(dataset_roi), - array_spec) - - logger.debug("done") - - timing.stop() - batch.profiling_stats.add(timing) - - return batch - - def __read_spec(self, headers): - - num_files = len(headers) - assert num_files > 0 - common_header = headers[0] - for header in headers: - for attr in ['imagesize_tczyx', 'pixelspacing_tczyx']: - assert (common_header[attr] == header[attr]).all(), ( - "Headers of provided KLB files differ in attribute %s"%attr) - assert common_header['datatype'] == header['datatype'], ( - "Headers of provided KLB files differ in attribute datatype") - - size = Coordinate(common_header['imagesize_tczyx']) - voxel_size = Coordinate(common_header['pixelspacing_tczyx']) - dtype = common_header['datatype'] - - # strip leading 1 dimensions - while size[0] == 1 and len(size) > 1: - size = size[1:] - voxel_size = voxel_size[1:] - - # append num_files dimension - if num_files > 1: - size = (num_files,) + size - voxel_size = (1,) + voxel_size - - dims = Coordinate(size) - self.ndims = len(dims) - - if self.array_spec is not None: - spec = self.array_spec - else: - spec = ArraySpec() - - if spec.voxel_size is None: - spec.voxel_size = Coordinate(voxel_size) - - if spec.roi is None: - offset = Coordinate((0,)*self.ndims) - spec.roi = Roi(offset, dims*spec.voxel_size) - - if spec.dtype is not None: - assert spec.dtype == dtype, ( - "dtype %s provided in array_specs for %s, but differs from " - "dataset dtype %s"%( - self.array_specs[self.array].dtype, self.array, - dataset.dtype)) - else: - spec.dtype = dtype - - if spec.interpolatable is None: - - spec.interpolatable = spec.dtype in [ - np.float, - np.float32, - np.float64, - np.float128, - np.uint8 # assuming this is not used for labels - ] - logger.warning("WARNING: You didn't set 'interpolatable' for %s. " - "Based on the dtype %s, it has been set to %s. " - "This might not be what you want.", - self.array, spec.dtype, spec.interpolatable) - - return spec - - def __read(self, roi): - - if len(self.files) == 1: - - return self.__read_file(self.files[0], roi) - - else: - - file_indices = range( - roi.get_begin()[0], - roi.get_end()[0]) - - file_roi = Roi( - roi.get_begin()[1:], - roi.get_shape()[1:]) - - return np.array([ - self.__read_file(self.files[i], file_roi) - for i in file_indices - ]) - - def __read_file(self, filename, roi): - - # pyklb reads max-inclusive, gunpowder rois are max exclusive -> - # subtract (1, 1, ...) from max coordinate - if self.num_threads: - return pyklb.readroi( - filename, - roi.get_begin(), - roi.get_end() - (1,)*roi.dims(), - numthreads=self.num_threads) - else: - return pyklb.readroi( - filename, - roi.get_begin(), - roi.get_end() - (1,)*roi.dims()) - - def __repr__(self): - - return self.filename
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/merge_provider.html b/docs/_modules/gunpowder/nodes/merge_provider.html deleted file mode 100644 index c786de91..00000000 --- a/docs/_modules/gunpowder/nodes/merge_provider.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.merge_provider — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.merge_provider
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.merge_provider

-from gunpowder.provider_spec import ProviderSpec
-from gunpowder.batch import Batch
-from gunpowder.batch_request import BatchRequest
-
-from .batch_provider import BatchProvider
-
-import random
-
-
-
[docs]class MergeProvider(BatchProvider): - '''Merges different providers:: - - (a + b + c) + MergeProvider() - - will create a provider that combines the arrays and points offered by - ``a``, ``b``, and ``c``. Array and point keys of ``a``, ``b``, and ``c`` should be - the disjoint. - ''' - def __init__(self): - self.key_to_provider = {} - - def setup(self): - self.enable_placeholders() - assert len(self.get_upstream_providers()) > 0, "at least one batch provider needs to be added to the MergeProvider" - # Only allow merging if no two upstream_providers have the same - # array/points keys - error_message = "Key {} provided by more than one upstream provider. Node MergeProvider only allows to merge " \ - "providers with different keys." - for provider in self.get_upstream_providers(): - for key, spec in provider.spec.items(): - assert self.spec is None or key not in self.spec, error_message.format(key) - self.provides(key, spec) - self.key_to_provider[key] = provider - - def provide(self, request): - - # create upstream requests - upstream_requests = {} - for key, spec in request.items(): - - provider = self.key_to_provider[key] - if provider not in upstream_requests: - # use new random seeds per upstream request. - # seeds picked by random should be deterministic since - # the provided request already has a random seed. - seed = random.randint(0, 2**32) - upstream_requests[provider] = BatchRequest(random_seed=seed) - - upstream_requests[provider][key] = spec - - # execute requests, merge batches - merged_batch = Batch() - for provider, upstream_request in upstream_requests.items(): - - batch = provider.request_batch(upstream_request) - for key, array in batch.arrays.items(): - merged_batch.arrays[key] = array - for key, graph in batch.graphs.items(): - merged_batch.graphs[key] = graph - merged_batch.profiling_stats.merge_with(batch.profiling_stats) - - return merged_batch
- - -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/n5_source.html b/docs/_modules/gunpowder/nodes/n5_source.html deleted file mode 100644 index 2abbbeef..00000000 --- a/docs/_modules/gunpowder/nodes/n5_source.html +++ /dev/null @@ -1,385 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.n5_source — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.n5_source
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.n5_source

-import logging
-
-from gunpowder.coordinate import Coordinate
-from gunpowder.ext import z5py
-from .hdf5like_source_base import Hdf5LikeSource
-
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class N5Source(Hdf5LikeSource): - '''An `N5 <https://github.com/saalfeldlab/n5>`_ data source. - - Provides arrays from N5 datasets. If the attribute ``resolution`` is set - in a N5 dataset, it will be used as the array's ``voxel_size``. If the - attribute ``offset`` is set in a dataset, it will be used as the offset of - the :class:`Roi` for this array. It is assumed that the offset is given in - world units. - - Args: - - filename (``string``): - - The N5 directory. - - datasets (``dict``, :class:`ArrayKey` -> ``string``): - - Dictionary of array keys to dataset names that this source offers. - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - An optional dictionary of array keys to array specs to overwrite - the array specs automatically determined from the data file. This - is useful to set a missing ``voxel_size``, for example. Only fields - that are not ``None`` in the given :class:`ArraySpec` will be used. - - channels_first (``bool``, optional): - - Specifies the ordering of the dimensions of the HDF5-like data source. - If channels_first is set (default), then the input shape is expected - to be (channels, spatial dimensions). This is recommended because of - better performance. If channels_first is set to false, then the input - data is read in channels_last manner and converted to channels_first. - ''' - def _get_voxel_size(self, dataset): - try: - logger.debug('Voxel size being reversed to account for N5 using column-major ordering') - return Coordinate(dataset.attrs['resolution'][::-1]) - except Exception: # todo: make specific when z5py supports it - return None - - def _get_offset(self, dataset): - try: - logger.debug('Offset being reversed to account for N5 using column-major ordering') - return Coordinate(dataset.attrs['offset'][::-1]) - except Exception: # todo: make specific when z5py supports it - return None - - def _open_file(self, filename): - return z5py.File(filename, use_zarr_format=False)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/noise_augment.html b/docs/_modules/gunpowder/nodes/noise_augment.html deleted file mode 100644 index f61924ab..00000000 --- a/docs/_modules/gunpowder/nodes/noise_augment.html +++ /dev/null @@ -1,414 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.noise_augment — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.noise_augment
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.noise_augment

-import numpy as np
-import skimage
-
-from gunpowder.batch_request import BatchRequest
-
-from .batch_filter import BatchFilter
-
-
[docs]class NoiseAugment(BatchFilter): - '''Add random noise to an array. Uses the scikit-image function skimage.util.random_noise. - See scikit-image documentation for more information on arguments and additional kwargs. - - Args: - - array (:class:`ArrayKey`): - - The intensity array to modify. Should be of type float and within range [-1, 1] or [0, 1]. - - mode (``string``): - - Type of noise to add, see scikit-image documentation. - - seed (``int``): - - Optionally set a random seed, see scikit-image documentation. - - clip (``bool``): - - Whether to preserve the image range (either [-1, 1] or [0, 1]) by clipping values in the end, see - scikit-image documentation - ''' - - def __init__(self, array, mode='gaussian', seed=None, clip=True, **kwargs): - self.array = array - self.mode = mode - self.seed = seed - self.clip = clip - self.kwargs = kwargs - - def setup(self): - self.enable_autoskip() - self.updates(self.array, self.spec[self.array]) - - def prepare(self, request): - deps = BatchRequest() - deps[self.array] = request[self.array].copy() - return deps - - def process(self, batch, request): - - raw = batch.arrays[self.array] - - assert raw.data.dtype == np.float32 or raw.data.dtype == np.float64, "Noise augmentation requires float types for the raw array (not " + str(raw.data.dtype) + "). Consider using Normalize before." - assert raw.data.min() >= -1 and raw.data.max() <= 1, "Noise augmentation expects raw values in [-1,1] or [0,1]. Consider using Normalize before." - raw.data = skimage.util.random_noise( - raw.data, - mode=self.mode, - seed=self.seed, - clip=self.clip, - **self.kwargs).astype(raw.data.dtype)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/normalize.html b/docs/_modules/gunpowder/nodes/normalize.html deleted file mode 100644 index 9f1db473..00000000 --- a/docs/_modules/gunpowder/nodes/normalize.html +++ /dev/null @@ -1,434 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.normalize — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.normalize
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.normalize

-import logging
-import copy
-import numpy as np
-
-from gunpowder.batch_request import BatchRequest
-
-from .batch_filter import BatchFilter
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Normalize(BatchFilter): - '''Normalize the values of an array to be floats between 0 and 1, based on - the type of the array. - - Args: - - array (:class:`ArrayKey`): - - The key of the array to modify. - - factor (scalar, optional): - - The factor to use. If not given, a factor is chosen based on the - ``dtype`` of the array (e.g., ``np.uint8`` would result in a factor - of ``1.0/255``). - - dtype (data-type, optional): - - The datatype of the normalized array. Defaults to ``np.float32``. - ''' - - def __init__(self, array, factor=None, dtype=np.float32): - - self.array = array - self.factor = factor - self.dtype = dtype - - def setup(self): - self.enable_autoskip() - array_spec = copy.deepcopy(self.spec[self.array]) - array_spec.dtype = self.dtype - self.updates(self.array, array_spec) - - def prepare(self, request): - deps = BatchRequest() - deps[self.array] = request[self.array] - deps[self.array].dtype = None - return deps - - def process(self, batch, request): - - if self.array not in batch.arrays: - return - - factor = self.factor - array = batch.arrays[self.array] - array.spec.dtype = self.dtype - - if factor is None: - - logger.debug("automatically normalizing %s with dtype=%s", - self.array, array.data.dtype) - - if array.data.dtype == np.uint8: - factor = 1.0/255 - elif array.data.dtype == np.uint16: - factor = 1.0/(256*256-1) - elif array.data.dtype == np.float32: - assert array.data.min() >= 0 and array.data.max() <= 1, ( - "Values are float but not in [0,1], I don't know how " - "to normalize. Please provide a factor.") - factor = 1.0 - else: - raise RuntimeError("Automatic normalization for " + - str(array.data.dtype) + " not implemented, please " - "provide a factor.") - - logger.debug("scaling %s with %f", self.array, factor) - array.data = array.data.astype(self.dtype)*factor
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/pad.html b/docs/_modules/gunpowder/nodes/pad.html deleted file mode 100644 index a6e7127e..00000000 --- a/docs/_modules/gunpowder/nodes/pad.html +++ /dev/null @@ -1,493 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.pad — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.nodes.pad

-import copy
-import logging
-import numpy as np
-
-from .batch_filter import BatchFilter
-from gunpowder.array import ArrayKey
-from gunpowder.coordinate import Coordinate
-from gunpowder.points import PointsKey
-from gunpowder.roi import Roi
-from gunpowder.batch_request import BatchRequest
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Pad(BatchFilter): - '''Add a constant intensity padding around arrays of another batch - provider. This is useful if your requested batches can be larger than what - your source provides. - - Args: - - key (:class:`ArrayKey` or :class:`GraphKey`): - - The array or points set to pad. - - size (:class:`Coordinate` or ``None``): - - The padding to be added. If None, an infinite padding is added. If - a coordinate, this amount will be added to the ROI in the positive - and negative direction. - - value (scalar or ``None``): - - The value to report inside the padding. If not given, 0 is used. - Only used for :class:`Array<Arrays>`. - ''' - - def __init__(self, key, size, value=None): - - self.key = key - self.size = size - self.value = value - - def setup(self): - self.enable_autoskip() - - assert self.key in self.spec, ( - "Asked to pad %s, but is not provided upstream."%self.key) - assert self.spec[self.key].roi is not None, ( - "Asked to pad %s, but upstream provider doesn't have a ROI for " - "it."%self.key) - - spec = self.spec[self.key].copy() - if self.size is not None: - spec.roi = spec.roi.grow(self.size, self.size) - else: - spec.roi.set_shape(None) - self.updates(self.key, spec) - - def prepare(self, request): - - upstream_spec = self.get_upstream_provider().spec - - logger.debug("request: %s"%request) - logger.debug("upstream spec: %s"%upstream_spec) - - # TODO: remove this? - if self.key not in request: - return - - roi = request[self.key].roi.copy() - - # change request to fit into upstream spec - request[self.key].roi = roi.intersect(upstream_spec[self.key].roi) - - if request[self.key].roi.empty(): - - logger.warning( - "Requested %s ROI %s lies entirely outside of upstream " - "ROI %s.", self.key, roi, upstream_spec[self.key].roi) - - # ensure a valid request by asking for empty ROI - request[self.key].roi = Roi( - upstream_spec[self.key].roi.get_offset(), - (0,)*upstream_spec[self.key].roi.dims() - ) - - logger.debug("new request: %s"%request) - - deps = BatchRequest() - deps[self.key] = request[self.key] - return deps - - def process(self, batch, request): - - if self.key not in request: - return - - # restore requested batch size and ROI - if isinstance(self.key, ArrayKey): - - array = batch.arrays[self.key] - array.data = self.__expand( - array.data, - array.spec.roi/array.spec.voxel_size, - request[self.key].roi/array.spec.voxel_size, - self.value if self.value else 0 - ) - array.spec.roi = request[self.key].roi - - else: - - points = batch.graphs[self.key] - points.spec.roi = request[self.key].roi - - def __expand(self, a, from_roi, to_roi, value): - '''from_roi and to_roi should be in voxels.''' - - logger.debug( - "expanding array of shape %s from %s to %s", - str(a.shape), from_roi, to_roi) - - num_channels = len(a.shape) - from_roi.dims() - channel_shapes = a.shape[:num_channels] - - b = np.zeros(channel_shapes + to_roi.get_shape(), dtype=a.dtype) - if value != 0: - b[:] = value - - shift = tuple(-x for x in to_roi.get_offset()) - logger.debug("shifting 'from' by " + str(shift)) - a_in_b = from_roi.shift(shift).to_slices() - - logger.debug("target shape is " + str(b.shape)) - logger.debug("target slice is " + str(a_in_b)) - - b[(slice(None),)*num_channels + a_in_b] = a - - return b
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/precache.html b/docs/_modules/gunpowder/nodes/precache.html deleted file mode 100644 index dec1ef8d..00000000 --- a/docs/_modules/gunpowder/nodes/precache.html +++ /dev/null @@ -1,485 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.precache — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.precache
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.precache

-import copy
-import logging
-import multiprocessing
-import time
-import random
-
-from .batch_filter import BatchFilter
-from gunpowder.profiling import Timing
-from gunpowder.producer_pool import ProducerPool
-
-from collections import deque
-
-logger = logging.getLogger(__name__)
-
-
-class WorkersDiedException(Exception):
-    pass
-
-
[docs]class PreCache(BatchFilter): - '''Pre-cache repeated equal batch requests. For the first of a series of - equal batch request, a set of workers is spawned to pre-cache the batches - in parallel processes. This way, subsequent requests can be served quickly. - - A note on changing the requests sent to `PreCache`. - Given requests A and B, if requests are sent in the sequence: - A, ..., A, B, A, ..., A, B, A, ... - Precache will build a Queue of batches that satisfy A, and handle requests - B on demand. This prevents `PreCache` from discarding the queue on every - SnapshotRequest. - However if B request replace A as the most common request, i.e.: - A, A, A, ..., A, B, B, B, ..., - `PreCache` will discard the A queue and build a B queue after it has seen - more B requests than A requests out of the last 5 requests. - - This node only makes sense if: - - 1. Incoming batch requests are repeatedly the same. - 2. There is a source of randomness in upstream nodes. - - Args: - - cache_size (``int``): - - How many batches to hold at most in the cache. - - num_workers (``int``): - - How many processes to spawn to fill the cache. - ''' - - def __init__(self, cache_size=50, num_workers=20): - - self.current_request = None - self.workers = None - self.cache_size = cache_size - self.num_workers = num_workers - - # keep track of recent requests - self.last_5 = deque([None,] * 5, maxlen=5) - - def teardown(self): - - if self.workers is not None: - self.workers.stop() - - def provide(self, request): - - timing = Timing(self) - timing.start() - - # update recent requests - self.last_5.popleft() - self.last_5.append(request) - - if request != self.current_request: - - current_count = sum( - [ - recent_request == self.current_request - for recent_request in self.last_5 - ] - ) - new_count = sum( - [recent_request == request for recent_request in self.last_5] - ) - if new_count > current_count or self.current_request is None: - - if self.workers is not None: - logger.info("new request received, stopping current workers...") - self.workers.stop() - - self.current_request = copy.deepcopy(request) - - logger.info("starting new set of workers (%s, cache size %s)...", - self.num_workers, self.cache_size) - self.workers = ProducerPool( - [lambda i=i: self.__run_worker(i) for i in range(self.num_workers)], - queue_size=self.cache_size, - ) - self.workers.start() - - logger.debug("getting batch from queue...") - batch = self.workers.get() - - timing.stop() - batch.profiling_stats.add(timing) - - else: - logger.debug("Resolving new request sequentially") - batch = self.get_upstream_provider().request_batch(request) - - timing.stop() - batch.profiling_stats.add(timing) - - else: - logger.debug("getting batch from queue...") - batch = self.workers.get() - - timing.stop() - batch.profiling_stats.add(timing) - - return batch - - def __run_worker(self, i): - request = copy.deepcopy(self.current_request) - # Note that using a precache node breaks determinism in batches recieved since we do not - # keep a mapping of the order in which random seeds were used, and the order in which - # the corresponding batch gets returned. - request._random_seed = random.randint(0, 2**32) - return self.get_upstream_provider().request_batch(request)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/print_profiling_stats.html b/docs/_modules/gunpowder/nodes/print_profiling_stats.html deleted file mode 100644 index 21298052..00000000 --- a/docs/_modules/gunpowder/nodes/print_profiling_stats.html +++ /dev/null @@ -1,469 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.print_profiling_stats — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.print_profiling_stats
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.print_profiling_stats

-import logging
-
-from .batch_filter import BatchFilter
-from gunpowder.profiling import Timing, TimingSummary, ProfilingStats
-
-logger = logging.getLogger(__name__)
-
-
[docs]class PrintProfilingStats(BatchFilter): - '''Print profiling information about nodes upstream of this node in the DAG. - - The output also includes a ``TOTAL`` section, which shows the wall-time - spent in the upstream and downstream passes. For the downstream pass, this - information is not available in the first iteration, since the request-batch - cycle is not completed, yet. - - Args: - - every (``int``): - - Collect statistics about that many batch requests and show min, - max, mean, and median runtimes. - ''' - - def __init__(self, every=1): - - self.every = every - self.n = 0 - self.accumulated_stats = ProfilingStats() - self.__upstream_timing = Timing(self) - self.__upstream_timing_summary = TimingSummary() - self.__downstream_timing = Timing(self) - self.__downstream_timing_summary = TimingSummary() - - def prepare(self, request): - - self.__downstream_timing.stop() - # skip the first one, where we don't know how much time we spent - # downstream - if self.__downstream_timing.elapsed() > 0: - self.__downstream_timing_summary.add(self.__downstream_timing) - self.__downstream_timing = Timing(self) - - self.__upstream_timing.start() - - deps = request - return deps - - def process(self, batch, request): - - self.__upstream_timing.stop() - self.__upstream_timing_summary.add(self.__upstream_timing) - self.__upstream_timing = Timing(self) - - self.__downstream_timing.start() - - self.n += 1 - print_stats = self.n%self.every == 0 - - self.accumulated_stats.merge_with(batch.profiling_stats) - - if not print_stats: - return - - stats = "\n" - stats += "Profiling Stats\n" - stats += "===============\n" - stats += "\n" - stats += "NODE".ljust(20) - stats += "METHOD".ljust(10) - stats += "COUNTS".ljust(10) - stats += "MIN".ljust(10) - stats += "MAX".ljust(10) - stats += "MEAN".ljust(10) - stats += "MEDIAN".ljust(10) - stats += "\n" - - summaries = list(self.accumulated_stats.get_timing_summaries().items()) - summaries.sort() - - for (node_name, method_name), summary in summaries: - - if summary.counts() > 0: - stats += node_name[:19].ljust(20) - stats += method_name[:19].ljust(10) if method_name is not None else ' '*10 - stats += ("%d"%summary.counts())[:9].ljust(10) - stats += ("%.2f"%summary.min())[:9].ljust(10) - stats += ("%.2f"%summary.max())[:9].ljust(10) - stats += ("%.2f"%summary.mean())[:9].ljust(10) - stats += ("%.2f"%summary.median())[:9].ljust(10) - stats += "\n" - - stats += "\n" - stats += "TOTAL" - stats += "\n" - - for phase, summary in zip(['upstream', 'downstream'], [self.__upstream_timing_summary, self.__downstream_timing_summary]): - - if summary.counts() > 0: - stats += phase[:19].ljust(30) - stats += ("%d"%summary.counts())[:9].ljust(10) - stats += ("%.2f"%summary.min())[:9].ljust(10) - stats += ("%.2f"%summary.max())[:9].ljust(10) - stats += ("%.2f"%summary.mean())[:9].ljust(10) - stats += ("%.2f"%summary.median())[:9].ljust(10) - stats += "\n" - - stats += "\n" - - logger.info(stats) - - # reset summaries - self.accumulated_stats = ProfilingStats() - self.__upstream_timing_summary = TimingSummary() - self.__downstream_timing_summary = TimingSummary()
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/random_location.html b/docs/_modules/gunpowder/nodes/random_location.html deleted file mode 100644 index 0c8847ec..00000000 --- a/docs/_modules/gunpowder/nodes/random_location.html +++ /dev/null @@ -1,818 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.random_location — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.random_location
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.random_location

-import math
-import logging
-from random import random, randint, choices, seed
-import itertools
-
-import numpy as np
-from scipy.spatial import cKDTree
-from skimage.transform import integral_image, integrate
-from gunpowder.batch_request import BatchRequest
-from gunpowder.coordinate import Coordinate
-from gunpowder.roi import Roi
-from .batch_filter import BatchFilter
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class RandomLocation(BatchFilter): - """Choses a batch at a random location in the bounding box of the upstream - provider. - - The random location is chosen such that the batch request ROI lies entirely - inside the provider's ROI. - - If ``min_masked`` and ``mask`` are set, only batches are returned that have - at least the given ratio of masked-in voxels. This is in general faster - than using the :class:`Reject` node, at the expense of storing an integral - array of the complete mask. - - If ``ensure_nonempty`` is set to a :class:`GraphKey`, only batches are - returned that have at least one point of this point collection within the - requested ROI. - - Additional tests for randomly picked locations can be implemented by - subclassing and overwriting of :func:`accepts`. This method takes the - randomly shifted request that meets all previous criteria (like - ``min_masked`` and ``ensure_nonempty``) and should return ``True`` if the - request is acceptable. - - Args: - - min_masked (``float``, optional): - - If non-zero, require that the random sample contains at least that - ratio of masked-in voxels. - - mask (:class:`ArrayKey`, optional): - - The array to use for mask checks. - - ensure_nonempty (:class:`GraphKey`, optional): - - Ensures that when finding a random location, a request for - ``ensure_nonempty`` will contain at least one point. - - p_nonempty (``float``, optional): - - If ``ensure_nonempty`` is set, it defines the probability that a - request for ``ensure_nonempty`` will contain at least one point. - Default value is 1.0. - - ensure_centered (``bool``, optional): - - if ``ensure_nonempty`` is set, ``ensure_centered`` guarantees - that the center voxel of the roi contains a point. - - point_balance_radius (``int``): - - if ``ensure_nonempty`` is set, ``point_balance_radius`` defines - a radius s.t. for every point `p` in ``ensure_nonempty``, the - probability of picking p is inversely related to the number of - other points within a distance of ``point_balance_radius`` to p. - This helps avoid oversampling of dense regions of the graph, and - undersampling of sparse regions. - """ - - def __init__( - self, - min_masked=0, - mask=None, - ensure_nonempty=None, - p_nonempty=1.0, - ensure_centered=None, - point_balance_radius=1, - ): - - self.min_masked = min_masked - self.mask = mask - self.mask_spec = None - self.mask_integral = None - self.ensure_nonempty = ensure_nonempty - self.points = None - self.p_nonempty = p_nonempty - self.upstream_spec = None - self.random_shift = None - self.ensure_centered = ensure_centered - self.point_balance_radius = point_balance_radius - - def setup(self): - - upstream = self.get_upstream_provider() - self.upstream_spec = upstream.spec - - if self.mask and self.min_masked > 0: - - assert self.mask in self.upstream_spec, ( - "Upstream provider does not have %s"%self.mask) - self.mask_spec = self.upstream_spec.array_specs[self.mask] - - logger.info("requesting complete mask...") - - mask_request = BatchRequest({self.mask: self.mask_spec}) - mask_batch = upstream.request_batch(mask_request) - - logger.info("allocating mask integral array...") - - mask_data = mask_batch.arrays[self.mask].data - mask_integral_dtype = np.uint64 - logger.debug("mask size is %s", mask_data.size) - if mask_data.size < 2**32: - mask_integral_dtype = np.uint32 - if mask_data.size < 2**16: - mask_integral_dtype = np.uint16 - logger.debug("chose %s as integral array dtype", mask_integral_dtype) - - self.mask_integral = np.array(mask_data > 0, dtype=mask_integral_dtype) - self.mask_integral = integral_image(self.mask_integral, - dtype=mask_integral_dtype) - - if self.ensure_nonempty: - - assert self.ensure_nonempty in self.upstream_spec, ( - "Upstream provider does not have %s"%self.ensure_nonempty) - graph_spec = self.upstream_spec.graph_specs[self.ensure_nonempty] - - - logger.info("requesting all %s points...", self.ensure_nonempty) - - nonempty_request = BatchRequest({self.ensure_nonempty: graph_spec}) - nonempty_batch = upstream.request_batch(nonempty_request) - - self.points = cKDTree( - [p.location for p in nonempty_batch[self.ensure_nonempty].nodes] - ) - - point_counts = self.points.query_ball_point( - [p.location for p in nonempty_batch[self.ensure_nonempty].nodes], - r=self.point_balance_radius, - ) - weights = [1 / len(point_count) for point_count in point_counts] - self.cumulative_weights = list(itertools.accumulate(weights)) - - logger.debug("retrieved %d points", len(self.points.data)) - - # clear bounding boxes of all provided arrays and points -- - # RandomLocation does not have limits (offsets are ignored) - for key, spec in self.spec.items(): - if spec.roi is not None: - spec.roi.set_shape(None) - self.updates(key, spec) - - def prepare(self, request): - seed(request.random_seed) - - logger.debug("request: %s", request.array_specs) - logger.debug("my spec: %s", self.spec) - - if request.array_specs.keys(): - lcm_voxel_size = self.spec.get_lcm_voxel_size( - request.array_specs.keys()) - else: - lcm_voxel_size = Coordinate((1,)*request.get_total_roi().dims()) - - shift_roi = self.__get_possible_shifts(request, lcm_voxel_size) - - if request.array_specs.keys(): - - shift_roi = shift_roi.snap_to_grid(lcm_voxel_size, mode='shrink') - lcm_shift_roi = shift_roi/lcm_voxel_size - logger.debug( - "restricting random locations to multiples of voxel size %s", - lcm_voxel_size) - - else: - - lcm_shift_roi = shift_roi - - assert not lcm_shift_roi.unbounded(), ( - "Can not pick a random location, intersection of upstream ROIs is " - "unbounded.") - assert not lcm_shift_roi.empty(), ( - "Can not satisfy batch request, no location covers all requested " - "ROIs.") - - random_shift = self.__select_random_shift( - request, - lcm_shift_roi, - lcm_voxel_size) - - self.random_shift = random_shift - self.__shift_request(request, random_shift) - - return request - - def process(self, batch, request): - - # reset ROIs to request - for (array_key, spec) in request.array_specs.items(): - batch.arrays[array_key].spec.roi = spec.roi - for (graph_key, spec) in request.graph_specs.items(): - batch.graphs[graph_key].spec.roi = spec.roi - - # change shift point locations to lie within roi - for graph_key in request.graph_specs.keys(): - batch.graphs[graph_key].shift(-self.random_shift) - - def accepts(self, request): - '''Should return True if the randomly chosen location is acceptable - (besided meeting other criteria like ``min_masked`` and/or - ``ensure_nonempty``). Subclasses can overwrite this method to implement - additional tests for acceptable locations.''' - - return True - - def __get_possible_shifts(self, request, voxel_size): - - total_shift_roi = None - - for key, spec in request.items(): - - if spec.roi is None: - continue - - request_roi = spec.roi - provided_roi = self.upstream_spec[key].roi - - shift_roi = provided_roi.shift( - -request_roi.get_begin() - ).grow( - (0,)*request_roi.dims(), - -(request_roi.get_shape() - voxel_size) - ) - - if total_shift_roi is None: - total_shift_roi = shift_roi - else: - if shift_roi != total_shift_roi: - total_shift_roi = total_shift_roi.intersect(shift_roi) - - logger.debug("valid shifts for request in " + str(total_shift_roi)) - - return total_shift_roi - - def __select_random_shift(self, request, lcm_shift_roi, lcm_voxel_size): - - ensure_points = ( - self.ensure_nonempty is not None - and - random() <= self.p_nonempty) - - while True: - - if ensure_points: - random_shift = self.__select_random_location_with_points( - request, - lcm_shift_roi, - lcm_voxel_size) - else: - random_shift = self.__select_random_location( - lcm_shift_roi, - lcm_voxel_size) - - logger.debug("random shift: " + str(random_shift)) - - if not self.__is_min_masked(random_shift, request): - logger.debug( - "random location does not meet 'min_masked' criterium") - continue - - if not self.__accepts(random_shift, request): - logger.debug( - "random location does not meet user-provided criterium") - continue - - return random_shift - - def __is_min_masked(self, random_shift, request): - - if not self.mask or self.min_masked == 0: - return True - - # get randomly chosen mask ROI - request_mask_roi = request.array_specs[self.mask].roi - request_mask_roi = request_mask_roi.shift(random_shift) - - # get coordinates inside mask array - mask_voxel_size = self.spec[self.mask].voxel_size - request_mask_roi_in_array = request_mask_roi/mask_voxel_size - request_mask_roi_in_array -= self.mask_spec.roi.get_offset()/mask_voxel_size - - # get number of masked-in voxels - num_masked_in = integrate( - self.mask_integral, - [request_mask_roi_in_array.get_begin()], - [request_mask_roi_in_array.get_end()-(1,)*self.mask_integral.ndim] - )[0] - - mask_ratio = float(num_masked_in)/request_mask_roi_in_array.size() - logger.debug("mask ratio is %f", mask_ratio) - - return mask_ratio >= self.min_masked - - def __accepts(self, random_shift, request): - - # create a shifted copy of the request - shifted_request = request.copy() - self.__shift_request(shifted_request, random_shift) - - return self.accepts(shifted_request) - - def __shift_request(self, request, shift): - - # shift request ROIs - for specs_type in [request.array_specs, request.graph_specs]: - for (key, spec) in specs_type.items(): - if spec.roi is None: - continue - roi = spec.roi.shift(shift) - specs_type[key].roi = roi - - def __select_random_location_with_points( - self, - request, - lcm_shift_roi, - lcm_voxel_size): - - request_points = request.graph_specs.get(self.ensure_nonempty) - if request_points is None: - total_roi = request.get_total_roi() - logger.warning( - f"Requesting non empty {self.ensure_nonempty}, however {self.ensure_nonempty} " - f"has not been requested. Falling back on using the total roi of the " - f"request {total_roi} for {self.ensure_nonempty}." - ) - request_points_roi = total_roi - else: - request_points_roi = request_points.roi - - while True: - - # How to pick shifts that ensure that a randomly chosen point is - # contained in the request ROI: - # - # - # request point - # [---------) . - # 0 +10 17 - # - # least shifted to contain point - # [---------) - # 8 +10 - # == - # point-request.begin-request.shape+1 - # - # most shifted to contain point: - # [---------) - # 17 +10 - # == - # point-request.begin - # - # all possible shifts - # [---------) - # 8 +10 - # == - # point-request.begin-request.shape+1 - # == - # request.shape - - # pick a random point - point = choices(self.points.data, cum_weights=self.cumulative_weights)[0] - - logger.debug("select random point at %s", point) - - # get the lcm voxel that contains this point - lcm_location = Coordinate(point/lcm_voxel_size) - logger.debug( - "belongs to lcm voxel %s", - lcm_location) - - # get the request ROI's shape in lcm - lcm_roi_begin = request_points_roi.get_begin()/lcm_voxel_size - lcm_roi_shape = request_points_roi.get_shape()/lcm_voxel_size - logger.debug("Point request ROI: %s", request_points_roi) - logger.debug("Point request lcm ROI shape: %s", lcm_roi_shape) - - # get all possible starting points of lcm_roi_shape that contain - # lcm_location - if self.ensure_centered: - lcm_shift_roi_begin = ( - lcm_location - - lcm_roi_begin - - lcm_roi_shape / 2 - + Coordinate((1,) * len(lcm_location)) - ) - lcm_shift_roi_shape = Coordinate((1,) * len(lcm_location)) - else: - lcm_shift_roi_begin = ( - lcm_location - lcm_roi_begin - lcm_roi_shape + - Coordinate((1,)*len(lcm_location)) - ) - lcm_shift_roi_shape = lcm_roi_shape - lcm_point_shift_roi = Roi(lcm_shift_roi_begin, lcm_shift_roi_shape) - - logger.debug("lcm point shift roi: %s", lcm_point_shift_roi) - - # intersect with total shift ROI - if not lcm_point_shift_roi.intersects(lcm_shift_roi): - logger.debug( - "reject random shift, random point %s shift ROI %s does " - "not intersect total shift ROI %s", point, - lcm_point_shift_roi, lcm_shift_roi) - continue - lcm_point_shift_roi = lcm_point_shift_roi.intersect(lcm_shift_roi) - - # select a random shift from all possible shifts - random_shift = self.__select_random_location( - lcm_point_shift_roi, - lcm_voxel_size) - logger.debug("random shift: %s", random_shift) - - # count all points inside the shifted ROI - points = self.__get_points_in_roi( - request_points_roi.shift(random_shift)) - assert point in points, ( - "Requested batch to contain point %s, but got points " - "%s"%(point, points)) - num_points = len(points) - - return random_shift - - def __select_random_location(self, lcm_shift_roi, lcm_voxel_size): - - # select a random point inside ROI - random_shift = Coordinate( - randint(begin, end - 1) - for begin, end in zip(lcm_shift_roi.get_begin(), lcm_shift_roi.get_end())) - - random_shift *= lcm_voxel_size - - return random_shift - - def __get_points_in_roi(self, roi): - - points = [] - - center = roi.get_center() - radius = math.ceil(float(max(roi.get_shape()))/2) - candidates = self.points.query_ball_point(center, radius, p=np.inf) - - for i in candidates: - if roi.contains(self.points.data[i]): - points.append(self.points.data[i]) - - return np.array(points)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/random_provider.html b/docs/_modules/gunpowder/nodes/random_provider.html deleted file mode 100644 index 02657fbc..00000000 --- a/docs/_modules/gunpowder/nodes/random_provider.html +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.random_provider — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.random_provider
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.random_provider

-import copy
-import numpy as np
-
-from .batch_provider import BatchProvider
-
-
-
[docs]class RandomProvider(BatchProvider): - '''Randomly selects one of the upstream providers:: - - (a + b + c) + RandomProvider() - - will create a provider that randomly relays requests to providers ``a``, - ``b``, or ``c``. Array and point keys of ``a``, ``b``, and ``c`` should be - the same. - - Args: - probabilities (1-D array-like, optional): An optional list of - probabilities for choosing upstream providers, given in the - same order. Probabilities do not need to be normalized. Default - is ``None``, corresponding to equal probabilities. - ''' - - def __init__(self, probabilities=None): - self.probabilities = probabilities - - # automatically normalize probabilities to sum to 1 - if self.probabilities is not None: - self.probabilities = [float(x)/np.sum(probabilities) for x in - self.probabilities] - - def setup(self): - self.enable_placeholders() - assert len(self.get_upstream_providers()) > 0,\ - "at least one batch provider must be added to the RandomProvider" - if self.probabilities is not None: - assert len(self.get_upstream_providers()) == len( - self.probabilities), "if probabilities are specified, they " \ - "need to be given for each batch " \ - "provider added to the RandomProvider" - - common_spec = None - - # advertise outputs only if all upstream providers have them - for provider in self.get_upstream_providers(): - - if common_spec is None: - common_spec = copy.deepcopy(provider.spec) - else: - for key, spec in list(common_spec.items()): - if key not in provider.spec: - del common_spec[key] - - for key, spec in common_spec.items(): - self.provides(key, spec) - - - def provide(self, request): - # Random seed is set in provide rather than prepare since this node - # is not a batch filter - np.random.seed(request.random_seed) - return np.random.choice(self.get_upstream_providers(), - p=self.probabilities).request_batch(request)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/rasterize_graph.html b/docs/_modules/gunpowder/nodes/rasterize_graph.html deleted file mode 100644 index 0cd889ea..00000000 --- a/docs/_modules/gunpowder/nodes/rasterize_graph.html +++ /dev/null @@ -1,778 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.rasterize_graph — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.rasterize_graph
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.rasterize_graph

-import copy
-import logging
-import numpy as np
-from scipy.ndimage.filters import gaussian_filter
-from skimage import draw
-
-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-from gunpowder.array_spec import ArraySpec
-from gunpowder.batch_request import BatchRequest
-from gunpowder.coordinate import Coordinate
-from gunpowder.freezable import Freezable
-from gunpowder.morphology import enlarge_binary_map, create_ball_kernel
-from gunpowder.ndarray import replace
-from gunpowder.graph import GraphKey
-from gunpowder.graph_spec import GraphSpec
-from gunpowder.roi import Roi
-
-logger = logging.getLogger(__name__)
-
-
[docs]class RasterizationSettings(Freezable): - '''Data structure to store parameters for rasterization of graph. - - Args: - - radius (``float`` or ``tuple`` of ``float``): - - The radius (for balls or tubes) or sigma (for peaks) in world units. - - mode (``string``): - - One of ``ball`` or ``peak``. If ``ball`` (the default), a ball with the - given ``radius`` will be drawn. If ``peak``, the point will be - rasterized as a peak with values :math:`\exp(-|x-p|^2/\sigma)` with - sigma set by ``radius``. - - mask (:class:`ArrayKey`, optional): - - Used to mask the rasterization of points. The array is assumed to - contain discrete labels. The object id at the specific point being - rasterized is used to intersect the rasterization to keep it inside - the specific object. - - inner_radius_fraction (``float``, optional): - - Only for mode ``ball``. - - If set, instead of a ball, a hollow sphere is rastered. The radius - of the whole sphere corresponds to the radius specified with - ``radius``. This parameter sets the radius of the hollow area, as a - fraction of ``radius``. - - fg_value (``int``, optional): - - Only for mode ``ball``. - - The value to use to rasterize points, defaults to 1. - - bg_value (``int``, optional): - - Only for mode ``ball``. - - The value to use to for the background in the output array, - defaults to 0. - - edges (``bool``, optional): - - Whether to rasterize edges by linearly interpolating between Nodes. - Default is True. - - color_attr (``str``, optional) - - Which graph attribute to use for coloring nodes and edges. One - useful example might be `component` which would color your graph - based on the component labels. - Notes: - - Only available in "ball" mode - - Nodes and Edges missing the attribute will be skipped. - - color_attr must be populated for nodes and edges upstream of this node - ''' - def __init__( - self, - radius, - mode='ball', - mask=None, - inner_radius_fraction=None, - fg_value=1, - bg_value=0, - edges=True, - color_attr=None, - ): - - radius = np.array([radius]).flatten().astype(np.float64) - - if inner_radius_fraction is not None: - assert ( - inner_radius_fraction > 0.0 and - inner_radius_fraction < 1.0), ( - "Inner radius fraction has to be between (excluding) 0 and 1") - inner_radius_fraction = 1.0 - inner_radius_fraction - - self.radius = radius - self.mode = mode - self.mask = mask - self.inner_radius_fraction = inner_radius_fraction - self.fg_value = fg_value - self.bg_value = bg_value - self.edges = edges - self.color_attr = color_attr - self.freeze()
- - -
[docs]class RasterizeGraph(BatchFilter): - """Draw graphs into a binary array as balls/tubes of a given radius. - - Args: - - graph (:class:`GraphKey`): - The key of the graph to rasterize. - - array (:class:`ArrayKey`): - The key of the binary array to create. - - array_spec (:class:`ArraySpec`, optional): - - The spec of the array to create. Use this to set the datatype and - voxel size. - - settings (:class:`RasterizationSettings`, optional): - Which settings to use to rasterize the graph. - """ - - def __init__(self, graph, array, array_spec=None, settings=None): - - self.graph = graph - self.array = array - if array_spec is None: - self.array_spec = ArraySpec() - else: - self.array_spec = array_spec - if settings is None: - self.settings = RasterizationSettings(1) - else: - self.settings = settings - - def setup(self): - - graph_roi = self.spec[self.graph].roi - - if self.array_spec.voxel_size is None: - self.array_spec.voxel_size = Coordinate((1,)*graph_roi.dims()) - - if self.array_spec.dtype is None: - if self.settings.mode == 'ball': - self.array_spec.dtype = np.uint8 - else: - self.array_spec.dtype = np.float32 - - self.array_spec.roi = graph_roi.copy() - self.provides( - self.array, - self.array_spec) - - self.enable_autoskip() - - def prepare(self, request): - - if self.settings.mode == 'ball': - context = np.ceil(self.settings.radius).astype(np.int) - elif self.settings.mode == 'peak': - context = np.ceil(2*self.settings.radius).astype(np.int) - else: - raise RuntimeError('unknown raster mode %s'%self.settings.mode) - - dims = self.array_spec.roi.dims() - if len(context) == 1: - context = context.repeat(dims) - - # request graph in a larger area to get rasterization from outside - # graph - graph_roi = request[self.array].roi.grow( - Coordinate(context), - Coordinate(context)) - - # however, restrict the request to the graph actually provided - graph_roi = graph_roi.intersect(self.spec[self.graph].roi) - - deps = BatchRequest() - deps[self.graph] = GraphSpec(roi=graph_roi) - - if self.settings.mask is not None: - - mask_voxel_size = self.spec[self.settings.mask].voxel_size - assert self.spec[self.array].voxel_size == mask_voxel_size, ( - "Voxel size of mask and rasterized volume need to be equal") - - new_mask_roi = graph_roi.snap_to_grid(mask_voxel_size) - deps[self.settings.mask] = ArraySpec(roi=new_mask_roi) - - return deps - - def process(self, batch, request): - - graph = batch.graphs[self.graph] - mask = self.settings.mask - voxel_size = self.spec[self.array].voxel_size - - # get roi used for creating the new array (graph_roi does not - # necessarily align with voxel size) - enlarged_vol_roi = graph.spec.roi.snap_to_grid(voxel_size) - offset = enlarged_vol_roi.get_begin() / voxel_size - shape = enlarged_vol_roi.get_shape() / voxel_size - data_roi = Roi(offset, shape) - - logger.debug("Graph in %s", graph.spec.roi) - for node in graph.nodes: - logger.debug("%d, %s", node.id, node.location) - logger.debug("Data roi in voxels: %s", data_roi) - logger.debug("Data roi in world units: %s", data_roi*voxel_size) - - if graph.num_vertices == 0: - # If there are no nodes at all, just create an empty matrix. - rasterized_graph_data = np.zeros( - data_roi.get_shape(), dtype=self.spec[self.array].dtype - ) - elif mask is not None: - - mask_array = batch.arrays[mask].crop(enlarged_vol_roi) - # get those component labels in the mask, that contain graph - labels = [] - for i, point in graph.data.items(): - v = Coordinate(point.location / voxel_size) - v -= data_roi.get_begin() - labels.append(mask_array.data[v]) - # Make list unique - labels = list(set(labels)) - - # zero label should be ignored - if 0 in labels: - labels.remove(0) - - if len(labels) == 0: - logger.debug("Graph and provided object mask do not overlap. No graph to rasterize.") - rasterized_graph_data = np.zeros(data_roi.get_shape(), - dtype=self.spec[self.array].dtype) - else: - # create data for the whole graph ROI, "or"ed together over - # individual object masks - rasterized_graph_data = np.sum( - [ - self.__rasterize( - graph, - data_roi, - voxel_size, - self.spec[self.array].dtype, - self.settings, - Array(data=mask_array.data==label, spec=mask_array.spec)) - - for label in labels - ], - axis=0) - - else: - - # create data for the whole graph ROI without mask - rasterized_graph_data = self.__rasterize( - graph, - data_roi, - voxel_size, - self.spec[self.array].dtype, - self.settings) - - # fix bg/fg labelling if requested - if (self.settings.bg_value != 0 or - self.settings.fg_value != 1): - - replaced = replace( - rasterized_graph_data, - [0, 1], - [self.settings.bg_value, self.settings.fg_value]) - rasterized_graph_data = replaced.astype(self.spec[self.array].dtype) - - # create array and crop it to requested roi - spec = self.spec[self.array].copy() - spec.roi = data_roi*voxel_size - rasterized_points = Array( - data=rasterized_graph_data, - spec=spec) - batch[self.array] = rasterized_points.crop(request[self.array].roi) - - def __rasterize(self, graph, data_roi, voxel_size, dtype, settings, mask_array=None): - '''Rasterize 'graph' into an array with the given 'voxel_size''' - - mask = mask_array.data if mask_array is not None else None - - logger.debug("Rasterizing graph in %s", graph.spec.roi) - - # prepare output array - rasterized_graph = np.zeros(data_roi.get_shape(), dtype=dtype) - - # Fast rasterization currently only implemented for mode ball without - # inner radius set - use_fast_rasterization = ( - settings.mode == "ball" - and settings.inner_radius_fraction is None - and len(list(graph.edges)) == 0 - ) - - if use_fast_rasterization: - - dims = len(rasterized_graph.shape) - - # get structuring element for mode ball - ball_kernel = create_ball_kernel(settings.radius, voxel_size) - radius_voxel = Coordinate(np.array(ball_kernel.shape)/2) - data_roi_base = Roi( - offset=Coordinate((0,)*dims), - shape=Coordinate(rasterized_graph.shape)) - kernel_roi_base = Roi( - offset=Coordinate((0,)*dims), - shape=Coordinate(ball_kernel.shape)) - - # Rasterize volume either with single voxel or with defined struct elememt - for node in graph.nodes: - - # get the voxel coordinate, 'Coordinate' ensures integer - v = Coordinate(node.location/voxel_size) - - # get the voxel coordinate relative to output array start - v -= data_roi.get_begin() - - # skip graph outside of mask - if mask is not None and not mask[v]: - continue - - logger.debug( - "Rasterizing node %s at %s", - node.location, - node.location/voxel_size - data_roi.get_begin()) - - if use_fast_rasterization: - - # Calculate where to crop the kernel mask and the rasterized array - shifted_kernel = kernel_roi_base.shift(v - radius_voxel) - shifted_data = data_roi_base.shift(-(v - radius_voxel)) - arr_crop = data_roi_base.intersect(shifted_kernel) - kernel_crop = kernel_roi_base.intersect(shifted_data) - arr_crop_ind = arr_crop.get_bounding_box() - kernel_crop_ind = kernel_crop.get_bounding_box() - - rasterized_graph[arr_crop_ind] = np.logical_or( - ball_kernel[kernel_crop_ind], rasterized_graph[arr_crop_ind] - ) - - else: - - if settings.color_attr is not None: - c = graph.nodes[node].get(settings.color_attr) - if c is None: - logger.debug(f"Skipping node: {node}") - continue - elif np.isclose(c, 1) and not np.isclose(settings.fg_value, 1): - logger.warning( - f"Node {node} is being colored with color {c} according to " - f"attribute {settings.color_attr} " - f"but color 1 will be replaced with fg_value: {settings.fg_value}" - ) - else: - c = 1 - rasterized_graph[v] = c - if settings.edges: - for e in graph.edges: - if settings.color_attr is not None: - c = graph.edges[e].get(settings.color_attr) - if c is None: - continue - elif np.isclose(c, 1) and not np.isclose(settings.fg_value, 1): - logger.warning( - f"Edge {e} is being colored with color {c} according to " - f"attribute {settings.color_attr} " - f"but color 1 will be replaced with fg_value: {settings.fg_value}" - ) - - u = graph.node(e.u) - v = graph.node(e.v) - u_coord = Coordinate(u.location / voxel_size) - v_coord = Coordinate(v.location / voxel_size) - line = draw.line_nd(u_coord, v_coord, endpoint=True) - rasterized_graph[line] = 1 - - # grow graph - if not use_fast_rasterization: - - if settings.mode == "ball": - - enlarge_binary_map( - rasterized_graph, - settings.radius, - voxel_size, - settings.inner_radius_fraction, - in_place=True) - - else: - - sigmas = settings.radius/voxel_size - - gaussian_filter( - rasterized_graph, sigmas, output=rasterized_graph, mode="constant" - ) - - # renormalize to have 1 be the highest value - max_value = np.max(rasterized_graph) - if max_value > 0: - rasterized_graph /= max_value - - if mask_array is not None: - # use more efficient bitwise operation when possible - if settings.mode == "ball": - rasterized_graph &= mask - else: - rasterized_graph *= mask - - return rasterized_graph
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/rasterize_points.html b/docs/_modules/gunpowder/nodes/rasterize_points.html deleted file mode 100644 index 13ab0e94..00000000 --- a/docs/_modules/gunpowder/nodes/rasterize_points.html +++ /dev/null @@ -1,703 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.rasterize_points — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.rasterize_points
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.rasterize_points

-import copy
-import logging
-import numpy as np
-from scipy.ndimage.filters import gaussian_filter
-
-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-from gunpowder.array_spec import ArraySpec
-from gunpowder.coordinate import Coordinate
-from gunpowder.freezable import Freezable
-from gunpowder.morphology import enlarge_binary_map, create_ball_kernel
-from gunpowder.ndarray import replace
-from gunpowder.points import PointsKeys
-from gunpowder.points_spec import PointsSpec
-from gunpowder.roi import Roi
-
-logger = logging.getLogger(__name__)
-
-
[docs]class RasterizationSettings(Freezable): - '''Data structure to store parameters for rasterization of points. - - Args: - - radius (``float`` or ``tuple`` of ``float``): - - The radius (for balls) or sigma (for peaks) in world units. - - mode (``string``): - - One of ``ball`` or ``peak``. If ``ball`` (the default), a ball with the - given ``radius`` will be drawn. If ``peak``, the point will be - rasterized as a peak with values :math:`\exp(-|x-p|^2/\sigma)` with - sigma set by ``radius``. - - mask (:class:`ArrayKey`, optional): - - Used to mask the rasterization of points. The array is assumed to - contain discrete labels. The object id at the specific point being - rasterized is used to intersect the rasterization to keep it inside - the specific object. - - inner_radius_fraction (``float``, optional): - - Only for mode ``ball``. - - If set, instead of a ball, a hollow sphere is rastered. The radius - of the whole sphere corresponds to the radius specified with - ``radius``. This parameter sets the radius of the hollow area, as a - fraction of ``radius``. - - fg_value (``int``, optional): - - Only for mode ``ball``. - - The value to use to rasterize points, defaults to 1. - - bg_value (``int``, optional): - - Only for mode ``ball``. - - The value to use to for the background in the output array, - defaults to 0. - ''' - def __init__( - self, - radius, - mode='ball', - mask=None, - inner_radius_fraction=None, - fg_value=1, - bg_value=0): - - radius = np.array([radius]).flatten().astype(np.float64) - - if inner_radius_fraction is not None: - assert ( - inner_radius_fraction > 0.0 and - inner_radius_fraction < 1.0), ( - "Inner radius fraction has to be between (excluding) 0 and 1") - - self.radius = radius - self.mode = mode - self.mask = mask - self.inner_radius_fraction = inner_radius_fraction - self.fg_value = fg_value - self.bg_value = bg_value - self.freeze()
- -
[docs]class RasterizePoints(BatchFilter): - '''Draw points into a binary array as balls of a given radius. - - Args: - - points (:class:`PointsKeys`): - The key of the points to rasterize. - - array (:class:`ArrayKey`): - The key of the binary array to create. - - array_spec (:class:`ArraySpec`, optional): - - The spec of the array to create. Use this to set the datatype and - voxel size. - - settings (:class:`RasterizationSettings`, optional): - Which settings to use to rasterize the points. - ''' - - def __init__(self, points, array, array_spec=None, settings=None): - - self.points = points - self.array = array - if array_spec is None: - self.array_spec = ArraySpec() - else: - self.array_spec = array_spec - if settings is None: - self.settings = RasterizationSettings(1) - else: - self.settings = settings - - def setup(self): - - points_roi = self.spec[self.points].roi - - if self.array_spec.voxel_size is None: - self.array_spec.voxel_size = Coordinate((1,)*points_roi.dims()) - - if self.array_spec.dtype is None: - if self.settings.mode == 'ball': - self.array_spec.dtype = np.uint8 - else: - self.array_spec.dtype = np.float32 - - self.array_spec.roi = points_roi.copy() - self.provides( - self.array, - self.array_spec) - - self.enable_autoskip() - - def prepare(self, request): - - if self.settings.mode == 'ball': - context = np.ceil(self.settings.radius).astype(np.int) - elif self.settings.mode == 'peak': - context = np.ceil(2*self.settings.radius).astype(np.int) - else: - raise RuntimeError('unknown raster mode %s'%self.settings.mode) - - dims = self.array_spec.roi.dims() - if len(context) == 1: - context = context.repeat(dims) - - # request points in a larger area to get rasterization from outside - # points - points_roi = request[self.array].roi.grow( - Coordinate(context), - Coordinate(context)) - - # however, restrict the request to the points actually provided - points_roi = points_roi.intersect(self.spec[self.points].roi) - request[self.points] = PointsSpec(roi=points_roi) - - if self.settings.mask is not None: - - mask_voxel_size = self.spec[self.settings.mask].voxel_size - assert self.spec[self.array].voxel_size == mask_voxel_size, ( - "Voxel size of mask and rasterized volume need to be equal") - - new_mask_roi = points_roi.snap_to_grid(mask_voxel_size) - if self.settings.mask in request: - request[self.settings.mask].roi = \ - request[self.settings.mask].roi.union(new_mask_roi) - else: - request[self.settings.mask] = \ - ArraySpec(roi=new_mask_roi) - - def process(self, batch, request): - - points = batch.points[self.points] - mask = self.settings.mask - voxel_size = self.spec[self.array].voxel_size - - # get roi used for creating the new array (points_roi does no - # necessarily align with voxel size) - enlarged_vol_roi = points.spec.roi.snap_to_grid(voxel_size) - offset = enlarged_vol_roi.get_begin() / voxel_size - shape = enlarged_vol_roi.get_shape() / voxel_size - data_roi = Roi(offset, shape) - - logger.debug("Points in %s", points.spec.roi) - for i, point in points.data.items(): - logger.debug("%d, %s", i, point.location) - logger.debug("Data roi in voxels: %s", data_roi) - logger.debug("Data roi in world units: %s", data_roi*voxel_size) - - if len(points.data.items()) == 0: - # If there are no points at all, just create an empty matrix. - rasterized_points_data = np.zeros(data_roi.get_shape(), - dtype=self.spec[self.array].dtype) - elif mask is not None: - - mask_array = batch.arrays[mask].crop(enlarged_vol_roi) - # get those component labels in the mask, that contain points - labels = [] - for i, point in points.data.items(): - v = Coordinate(point.location / voxel_size) - v -= data_roi.get_begin() - labels.append(mask_array.data[v]) - # Make list unique - labels = list(set(labels)) - - # zero label should be ignored - if 0 in labels: - labels.remove(0) - - if len(labels) == 0: - logger.debug("Points and provided object mask do not overlap. No points to rasterize.") - rasterized_points_data = np.zeros(data_roi.get_shape(), - dtype=self.spec[self.array].dtype) - else: - # create data for the whole points ROI, "or"ed together over - # individual object masks - rasterized_points_data = np.sum( - [ - self.__rasterize( - points, - data_roi, - voxel_size, - self.spec[self.array].dtype, - self.settings, - Array(data=mask_array.data==label, spec=mask_array.spec)) - - for label in labels - ], - axis=0) - - else: - - # create data for the whole points ROI without mask - rasterized_points_data = self.__rasterize( - points, - data_roi, - voxel_size, - self.spec[self.array].dtype, - self.settings) - - # fix bg/fg labelling if requested - if (self.settings.bg_value != 0 or - self.settings.fg_value != 1): - - replaced = replace( - rasterized_points_data, - [0, 1], - [self.settings.bg_value, self.settings.fg_value]) - rasterized_points_data = replaced.astype(self.spec[self.array].dtype) - - # create array and crop it to requested roi - spec = self.spec[self.array].copy() - spec.roi = data_roi*voxel_size - rasterized_points = Array( - data=rasterized_points_data, - spec=spec) - batch.arrays[self.array] = rasterized_points.crop(request[self.array].roi) - - # restore requested ROI of points - if self.points in request: - request_roi = request[self.points].roi - points.spec.roi = request_roi - points.data = {i: p for i, p in points.data.items() if request_roi.contains(p.location)} - - # restore requested mask - if mask is not None: - batch.arrays[mask] = batch.arrays[mask].crop(request[mask].roi) - - def __rasterize(self, points, data_roi, voxel_size, dtype, settings, mask_array=None): - '''Rasterize 'points' into an array with the given 'voxel_size''' - - mask = mask_array.data if mask_array is not None else None - - logger.debug("Rasterizing points in %s", points.spec.roi) - - # prepare output array - rasterized_points = np.zeros(data_roi.get_shape(), dtype=dtype) - - # Fast rasterization currently only implemented for mode ball without - # inner radius set - use_fast_rasterization = ( - settings.mode == 'ball' and - settings.inner_radius_fraction is None - ) - - if use_fast_rasterization: - - dims = len(rasterized_points.shape) - - # get structuring element for mode ball - ball_kernel = create_ball_kernel(settings.radius, voxel_size) - radius_voxel = Coordinate(np.array(ball_kernel.shape)/2) - data_roi_base = Roi( - offset=Coordinate((0,)*dims), - shape=Coordinate(rasterized_points.shape)) - kernel_roi_base = Roi( - offset=Coordinate((0,)*dims), - shape=Coordinate(ball_kernel.shape)) - - # Rasterize volume either with single voxel or with defined struct elememt - for point in points.data.values(): - - # get the voxel coordinate, 'Coordinate' ensures integer - v = Coordinate(point.location/voxel_size) - - # get the voxel coordinate relative to output array start - v -= data_roi.get_begin() - - # skip points outside of mask - if mask is not None and not mask[v]: - continue - - logger.debug( - "Rasterizing point %s at %s", - point.location, - point.location/voxel_size - data_roi.get_begin()) - - if use_fast_rasterization: - - # Calculate where to crop the kernel mask and the rasterized array - shifted_kernel = kernel_roi_base.shift(v - radius_voxel) - shifted_data = data_roi_base.shift(-(v - radius_voxel)) - arr_crop = data_roi_base.intersect(shifted_kernel) - kernel_crop = kernel_roi_base.intersect(shifted_data) - arr_crop_ind = arr_crop.get_bounding_box() - kernel_crop_ind = kernel_crop.get_bounding_box() - - rasterized_points[arr_crop_ind] = np.logical_or( - ball_kernel[kernel_crop_ind], - rasterized_points[arr_crop_ind]) - - else: - - rasterized_points[v] = 1 - - # grow points - if not use_fast_rasterization: - - if settings.mode == 'ball': - - enlarge_binary_map( - rasterized_points, - settings.radius, - voxel_size, - 1.0 - settings.inner_radius_fraction, - in_place=True) - - else: - - sigmas = settings.radius/voxel_size - - gaussian_filter( - rasterized_points, - sigmas, - output=rasterized_points, - mode='constant') - - # renormalize to have 1 be the highest value - max_value = np.max(rasterized_points) - if max_value > 0: - rasterized_points /= max_value - - if mask_array is not None: - # use more efficient bitwise operation when possible - if settings.mode == 'ball': - rasterized_points &= mask - else: - rasterized_points *= mask - - return rasterized_points
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/reject.html b/docs/_modules/gunpowder/nodes/reject.html deleted file mode 100644 index 550b7918..00000000 --- a/docs/_modules/gunpowder/nodes/reject.html +++ /dev/null @@ -1,483 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.reject — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.nodes.reject

-import logging
-import random
-
-from .batch_filter import BatchFilter
-from gunpowder.profiling import Timing
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Reject(BatchFilter): - '''Reject batches based on the masked-in vs. masked-out ratio. - - Args: - - mask (:class:`ArrayKey`, optional): - - The mask to use, if any. - - min_masked (``float``, optional): - - The minimal required ratio of masked-in vs. masked-out voxels. - Defaults to 0.5. - - ensure_nonempty (:class:`GraphKey`, optional) - - Ensures there is at least one point in the batch. - - reject_probability (``float``, optional): - - The probability by which a batch that is not valid (less than - min_masked) is actually rejected. Defaults to 1., i.e. strict - rejection. - ''' - - def __init__( - self, - mask=None, - min_masked=0.5, - ensure_nonempty=None, - reject_probability=1.): - - self.mask = mask - self.min_masked = min_masked - self.ensure_nonempty = ensure_nonempty - self.reject_probability = reject_probability - - def setup(self): - if self.mask: - assert self.mask in self.spec, ( - "Reject can only be used if %s is provided" % self.mask) - if self.ensure_nonempty: - assert self.ensure_nonempty in self.spec, ( - "Reject can only be used if %s is provided" % - self.ensure_nonempty) - self.upstream_provider = self.get_upstream_provider() - - def provide(self, request): - random.seed(request.random_seed) - - report_next_timeout = 10 - num_rejected = 0 - - timing = Timing(self) - timing.start() - if self.mask: - assert self.mask in request, ( - "Reject can only be used if %s is provided" % self.mask) - if self.ensure_nonempty: - assert self.ensure_nonempty in request, ( - "Reject can only be used if %s is provided" % - self.ensure_nonempty) - - have_good_batch = False - while not have_good_batch: - - batch = self.upstream_provider.request_batch(request) - - if self.mask: - mask_ratio = batch.arrays[self.mask].data.mean() - else: - mask_ratio = None - - if self.ensure_nonempty: - num_points = len( - list(batch.points[self.ensure_nonempty].nodes)) - else: - num_points = None - - have_min_mask = mask_ratio is None or mask_ratio > self.min_masked - have_points = num_points is None or num_points > 0 - - have_good_batch = have_min_mask and have_points - - if not have_good_batch and self.reject_probability < 1.: - have_good_batch = random.random() > self.reject_probability - - if not have_good_batch: - if self.mask: - logger.debug( - "reject batch with mask ratio %f at %s", - mask_ratio, batch.arrays[self.mask].spec.roi) - if self.ensure_nonempty: - logger.debug( - "reject batch with empty points in %s", - batch.points[self.ensure_nonempty].spec.roi) - num_rejected += 1 - - if timing.elapsed() > report_next_timeout: - - logger.warning( - "rejected %d batches, been waiting for a good one " - "since %ds", num_rejected, report_next_timeout) - report_next_timeout *= 2 - - else: - if self.mask: - logger.debug( - "accepted batch with mask ratio %f at %s", - mask_ratio, batch.arrays[self.mask].spec.roi) - if self.ensure_nonempty: - logger.debug( - "accepted batch with nonempty points in %s", - self.ensure_nonempty) - - timing.stop() - batch.profiling_stats.add(timing) - - return batch
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/renumber_connected_components.html b/docs/_modules/gunpowder/nodes/renumber_connected_components.html deleted file mode 100644 index 715776e8..00000000 --- a/docs/_modules/gunpowder/nodes/renumber_connected_components.html +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.renumber_connected_components — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.renumber_connected_components
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.renumber_connected_components

-from .batch_filter import BatchFilter
-from gunpowder.ext import malis
-
-
[docs]class RenumberConnectedComponents(BatchFilter): - '''Find connected components of the same value, and replace each component - with a new label. - - Args: - - labels (:class:`ArrayKey`): - - The label array to modify. - ''' - - def __init__(self, labels): - self.labels = labels - - def process(self, batch, request): - components = batch.arrays[self.labels].data - dtype = components.dtype - simple_neighborhood = malis.mknhood3d() - affinities_from_components = malis.seg_to_affgraph( - components, - simple_neighborhood) - components, _ = malis.connected_components_affgraph( - affinities_from_components, - simple_neighborhood) - batch.arrays[self.labels].data = components.astype(dtype)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/scan.html b/docs/_modules/gunpowder/nodes/scan.html deleted file mode 100644 index 2ea25536..00000000 --- a/docs/_modules/gunpowder/nodes/scan.html +++ /dev/null @@ -1,764 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.scan — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.nodes.scan

-import logging
-import multiprocessing
-import numpy as np
-import tqdm
-from gunpowder.array import Array
-from gunpowder.batch import Batch
-from gunpowder.coordinate import Coordinate
-from gunpowder.graph import Graph
-from gunpowder.producer_pool import ProducerPool
-from gunpowder.roi import Roi
-from .batch_filter import BatchFilter
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Scan(BatchFilter): - '''Iteratively requests batches of size ``reference`` from upstream - providers in a scanning fashion, until all requested ROIs are covered. If - the batch request to this node is empty, it will scan the complete upstream - ROIs (and return nothing). Otherwise, it scans only the requested ROIs and - returns a batch assembled of the smaller requests. In either case, the - upstream requests will be contained in the downstream requested ROI or - upstream ROIs. - - See also :class:`Hdf5Write`. - - Args: - - reference (:class:`BatchRequest`): - - A reference :class:`BatchRequest`. This request will be shifted in - a scanning fashion over the upstream ROIs of the requested arrays - or points. - - num_workers (``int``, optional): - - If set to >1, upstream requests are made in parallel with that - number of workers. - - cache_size (``int``, optional): - - If multiple workers are used, how many batches to hold at most. - ''' - - def __init__(self, reference, num_workers=1, cache_size=50): - - self.reference = reference.copy() - self.num_workers = num_workers - self.cache_size = cache_size - self.workers = None - self.batch = None - - def setup(self): - - if self.num_workers > 1: - self.request_queue = multiprocessing.Queue(maxsize=0) - self.workers = ProducerPool( - [self.__worker_get_chunk for _ in range(self.num_workers)], - queue_size=self.cache_size) - self.workers.start() - - def teardown(self): - - if self.num_workers > 1: - self.workers.stop() - - def provide(self, request): - - empty_request = (len(request) == 0) - if empty_request: - scan_spec = self.spec - else: - scan_spec = request - - stride = self.__get_stride() - shift_roi = self.__get_shift_roi(scan_spec) - - shifts = self.__enumerate_shifts(shift_roi, stride) - num_chunks = len(shifts) - - logger.info("scanning over %d chunks", num_chunks) - - # the batch to return - self.batch = Batch() - - if self.num_workers > 1: - - for shift in shifts: - shifted_reference = self.__shift_request(self.reference, shift) - self.request_queue.put(shifted_reference) - - for i in tqdm.tqdm(range(num_chunks)): - - chunk = self.workers.get() - - if not empty_request: - self.__add_to_batch(request, chunk) - - logger.debug("processed chunk %d/%d", i + 1, num_chunks) - - else: - - for i, shift in tqdm.tqdm(enumerate(shifts)): - - shifted_reference = self.__shift_request(self.reference, shift) - chunk = self.__get_chunk(shifted_reference) - - if not empty_request: - self.__add_to_batch(request, chunk) - - logger.debug("processed chunk %d/%d", i + 1, num_chunks) - - batch = self.batch - self.batch = None - - logger.debug("returning batch %s", batch) - - return batch - - def __get_stride(self): - '''Get the maximal amount by which ``reference`` can be moved, such - that it tiles the space.''' - - stride = None - - # get the least common multiple of all voxel sizes, we have to stride - # at least that far - lcm_voxel_size = self.spec.get_lcm_voxel_size( - self.reference.array_specs.keys()) - - # that's just the minimal size in each dimension - for key, reference_spec in self.reference.items(): - - shape = reference_spec.roi.get_shape() - - for d in range(len(lcm_voxel_size)): - assert shape[d] >= lcm_voxel_size[d], ("Shape of reference " - "ROI %s for %s is " - "smaller than least " - "common multiple of " - "voxel size " - "%s"%(reference_spec.roi, - key, - lcm_voxel_size)) - - if stride is None: - stride = shape - else: - stride = Coordinate(( - min(a, b) - for a, b in zip(stride, shape))) - - return stride - - def __get_shift_roi(self, spec): - '''Get the minimal and maximal shift (as a ROI) to apply to - ``self.reference``, such that it is still fully contained in ``spec``. - ''' - - total_shift_roi = None - - # get individual shift ROIs and intersect them - for key, reference_spec in self.reference.items(): - - logger.debug( - "getting shift roi for %s with spec %s", - key, - reference_spec) - - if key not in spec: - logger.debug("skipping, %s not in upstream spec", key) - continue - if spec[key].roi is None: - logger.debug("skipping, %s has not ROI", key) - continue - - logger.debug("upstream ROI is %s", spec[key].roi) - - for r, s in zip(reference_spec.roi.get_shape(), spec[key].roi.get_shape()): - assert s is None or r <= s, ( - "reference %s with ROI %s does not fit into provided " - "upstream %s" % (key, reference_spec.roi, spec[key].roi) - ) - - # we have a reference ROI - # - # [--------) [9] - # 3 12 - # - # and a spec ROI - # - # [---------------) [16] - # 16 32 - # - # min and max shifts of reference are - # - # [--------) [9] - # 16 25 - # [--------) [9] - # 23 32 - # - # therefore, all possible ways to shift the reference such that it - # is contained in the spec are at least 16-3=13 and at most 23-3=20 - # (inclusive) - # - # [-------) [8] - # 13 21 - # - # 1. the starting point is beginning of spec - beginning of reference - # 2. the length is length of spec - length of reference + 1 - - # 1. get the starting point of the shift ROI - shift_begin = ( - spec[key].roi.get_begin() - - reference_spec.roi.get_begin()) - - # 2. get the shape of the shift ROI - shift_shape = ( - spec[key].roi.get_shape() - - reference_spec.roi.get_shape() + - (1,)*reference_spec.roi.dims()) - - # create a ROI... - shift_roi = Roi(shift_begin, shift_shape) - - logger.debug("shift ROI for %s is %s", key, shift_roi) - - # ...and intersect it with previous shift ROIs - if total_shift_roi is None: - total_shift_roi = shift_roi - else: - total_shift_roi = total_shift_roi.intersect(shift_roi) - if total_shift_roi.empty(): - raise RuntimeError("There is no location where the ROIs " - "the reference %s are contained in the " - "request/upstream ROIs " - "%s."%(self.reference, spec)) - - logger.debug("intersected with total shift ROI this yields %s", - total_shift_roi) - - if total_shift_roi is None: - raise RuntimeError("None of the upstream ROIs are bounded (all " - "ROIs are None). Scan needs at least one " - "bounded upstream ROI.") - - return total_shift_roi - - def __enumerate_shifts(self, shift_roi, stride): - '''Produces a sequence of shift coordinates starting at the beginning - of ``shift_roi``, progressing with ``stride``. The maximum shift - coordinate in any dimension will be the last point inside the shift roi - in this dimension.''' - - min_shift = shift_roi.get_offset() - max_shift = max(min_shift, - Coordinate(m - 1 for m in shift_roi.get_end())) - - shift = np.array(min_shift) - shifts = [] - - dims = len(min_shift) - - logger.debug( - "enumerating possible shifts of %s in %s", stride, shift_roi) - - while True: - - logger.debug("adding %s", shift) - shifts.append(Coordinate(shift)) - - if (shift == max_shift).all(): - break - - # count up dimensions - for d in range(dims): - - if shift[d] >= max_shift[d]: - if d == dims - 1: - break - shift[d] = min_shift[d] - else: - shift[d] += stride[d] - # snap to last possible shift, don't overshoot - if shift[d] > max_shift[d]: - shift[d] = max_shift[d] - break - - return shifts - - def __shift_request(self, request, shift): - - shifted = request.copy() - for _, spec in shifted.items(): - spec.roi = spec.roi.shift(shift) - - return shifted - - def __worker_get_chunk(self): - - request = self.request_queue.get() - return self.__get_chunk(request) - - def __get_chunk(self, request): - - return self.get_upstream_provider().request_batch(request) - - def __add_to_batch(self, spec, chunk): - - if self.batch.get_total_roi() is None: - self.batch = self.__setup_batch(spec, chunk) - self.batch.profiling_stats.merge_with(chunk.profiling_stats) - - for (array_key, array) in chunk.arrays.items(): - if array_key not in spec: - continue - self.__fill(self.batch.arrays[array_key].data, array.data, - spec.array_specs[array_key].roi, array.spec.roi, - self.spec[array_key].voxel_size) - - for (graph_key, graphs) in chunk.graphs.items(): - if graph_key not in spec: - continue - self.__fill_points(self.batch.graphs[graph_key], graphs, - spec.graph_specs[graph_key].roi, graphs.spec.roi) - - def __setup_batch(self, batch_spec, chunk): - '''Allocate a batch matching the sizes of ``batch_spec``, using - ``chunk`` as template.''' - - batch = Batch() - - for (array_key, spec) in batch_spec.array_specs.items(): - roi = spec.roi - voxel_size = self.spec[array_key].voxel_size - - # get the 'non-spatial' shape of the chunk-batch - # and append the shape of the request to it - array = chunk.arrays[array_key] - shape = array.data.shape[:-roi.dims()] - shape += (roi.get_shape() // voxel_size) - - spec = self.spec[array_key].copy() - spec.roi = roi - logger.info("allocating array of shape %s for %s", shape, array_key) - batch.arrays[array_key] = Array(data=np.zeros(shape, dtype=spec.dtype), - spec=spec) - - for (graph_key, spec) in batch_spec.graph_specs.items(): - roi = spec.roi - spec = self.spec[graph_key].copy() - spec.roi = roi - batch.graphs[graph_key] = Graph(nodes=[], edges=[], spec=spec) - - logger.debug("setup batch to fill %s", batch) - - return batch - - def __fill(self, a, b, roi_a, roi_b, voxel_size): - logger.debug("filling " + str(roi_b) + " into " + str(roi_a)) - - roi_a = roi_a // voxel_size - roi_b = roi_b // voxel_size - - common_roi = roi_a.intersect(roi_b) - if common_roi.empty(): - return - - common_in_a_roi = common_roi - roi_a.get_offset() - common_in_b_roi = common_roi - roi_b.get_offset() - - slices_a = common_in_a_roi.get_bounding_box() - slices_b = common_in_b_roi.get_bounding_box() - - if len(a.shape) > len(slices_a): - slices_a = (slice(None),)*(len(a.shape) - len(slices_a)) + slices_a - slices_b = (slice(None),)*(len(b.shape) - len(slices_b)) + slices_b - - a[slices_a] = b[slices_b] - - def __fill_points(self, a, b, roi_a, roi_b): - """ - Take points from b and add them to a. - Nodes marked temporary must be ignored. Temporary nodes are nodes - that were created during processing. Since it is impossible to know - in general, that a node created during processing of a subgraph was - not assigned an id that is already used by the full graph, we cannot - include temporary nodes and assume there will not be ambiguous node - id's that correspond to multiple distinct nodes. - """ - logger.debug("filling points of " + str(roi_b) + " into points of" + str(roi_a)) - - common_roi = roi_a.intersect(roi_b) - if common_roi is None: - return - - for node in b.nodes: - if not node.temporary and roi_a.contains(node.location): - a.add_node(node) - for e in b.edges: - bu = b.node(e.u) - bv = b.node(e.v) - if ( - not bu.temporary - and not bv.temporary - and a.contains(bu.id) - and a.contains(bv.id) - ): - a.add_edge(e)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/simple_augment.html b/docs/_modules/gunpowder/nodes/simple_augment.html deleted file mode 100644 index cfcfdaa0..00000000 --- a/docs/_modules/gunpowder/nodes/simple_augment.html +++ /dev/null @@ -1,600 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.simple_augment — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.simple_augment
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.simple_augment

-import logging
-import random
-import numpy as np
-
-from .batch_filter import BatchFilter
-from gunpowder.coordinate import Coordinate
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class SimpleAugment(BatchFilter): - '''Randomly mirror and transpose all :class:`Arrays<Array>` and - :class:`Graph` in a batch. - - Args: - - mirror_only (``list`` of ``int``, optional): - - If set, only mirror between the given axes. This is useful to - exclude channels that have a set direction, like time. - - transpose_only (``list`` of ``int``, optional): - - If set, only transpose between the given axes. This is useful to - limit the transpose to axes with the same resolution or to exclude - non-spatial dimensions. - ''' - - def __init__(self, mirror_only=None, transpose_only=None): - - self.mirror_only = mirror_only - self.transpose_only = transpose_only - self.mirror_mask = None - self.dims = None - self.transpose_dims = None - - def setup(self): - - self.dims = self.spec.get_total_roi().dims() - - # mirror_mask and transpose_dims refer to the indices of the spatial - # dimensions only, starting counting at 0 for the first spatial - # dimension - - if self.mirror_only is None: - self.mirror_mask = [True]*self.dims - else: - self.mirror_mask = [ - d in self.mirror_only - for d in range(self.dims)] - - if self.transpose_only is None: - self.transpose_dims = list(range(self.dims)) - else: - self.transpose_dims = self.transpose_only - - def prepare(self, request): - random.seed(request.random_seed) - - self.mirror = [ - random.randint(0, 1) - if self.mirror_mask[d] else 0 - for d in range(self.dims) - ] - - t = list(self.transpose_dims) - random.shuffle(t) - self.transpose = list(range(self.dims)) - for o, n in zip(self.transpose_dims, t): - self.transpose[o] = n - - logger.debug("mirror = %s", self.mirror) - logger.debug("transpose = %s", self.transpose) - - reverse_transpose = [0]*self.dims - for d in range(self.dims): - reverse_transpose[self.transpose[d]] = d - - logger.debug("downstream request = %s", request) - - self.__transpose_request(request, reverse_transpose) - self.__mirror_request(request, self.mirror) - - logger.debug("upstream request = %s", request) - - return request - - def process(self, batch, request): - - # mirror and transpose ROIs of arrays & points in batch - total_roi = batch.get_total_roi().copy() - requested_keys = request.array_specs.keys() - lcm_voxel_size = self.spec.get_lcm_voxel_size(requested_keys) - - for collection_type in [batch.arrays, batch.graphs]: - for (key, collector) in collection_type.items(): - if key not in request: - continue - if collector.spec.roi is None: - continue - logger.debug("total ROI = %s", batch.get_total_roi()) - logger.debug("upstream %s ROI = %s", key, collector.spec.roi) - self.__mirror_roi( - collector.spec.roi, - total_roi, self.mirror) - logger.debug("mirrored %s ROI = %s", key, collector.spec.roi) - self.__transpose_roi( - collector.spec.roi, - total_roi, - self.transpose, - lcm_voxel_size) - logger.debug("transposed %s ROI = %s", key, collector.spec.roi) - - mirror = tuple( - slice(None, None, -1 if m else 1) - for m in self.mirror - ) - # arrays - for (array_key, array) in batch.arrays.items(): - - if array_key not in request: - continue - - if array.spec.nonspatial: - continue - - num_channels = len(array.data.shape) - self.dims - channel_slices = (slice(None, None),)*num_channels - - array.data = array.data[channel_slices + mirror] - - transpose = [t + num_channels for t in self.transpose] - array.data = array.data = array.data.transpose( - list(range(num_channels)) + transpose) - - # graphs - total_roi_offset = batch.get_total_roi().get_offset() - total_roi_end = batch.get_total_roi().get_end() - - for (graph_key, graph) in batch.graphs.items(): - - if graph_key not in request: - continue - - logger.debug("converting nodes in graph %s", graph_key) - for node in list(graph.nodes): - - logger.debug("old location: %s, %s", node.id, node.location) - - # mirror - location_in_total_offset = ( - np.asarray(node.location) - - total_roi_offset) - node.location[:] = np.asarray( - [ - total_roi_end[dim] - - location_in_total_offset[dim] - if m else node.location[dim] - for dim, m in enumerate(self.mirror) - ]) - - logger.debug("after mirror: %s, %s", node.id, node.location) - - # transpose - location_in_total_offset = ( - np.asarray(node.location) - - total_roi_offset) - - if self.transpose != list(range(self.dims)): - for d in range(self.dims): - node.location[d] = \ - location_in_total_offset[self.transpose[d]] + \ - total_roi_offset[d] - - logger.debug("after transpose: %s, %s", node.id, node.location) - - # due to the mirroring, points at the lower boundary of the ROI - # could fall on the upper one, which excludes them from the ROI - if not graph.spec.roi.contains(node.location): - graph.remove_node(node) - - def __mirror_request(self, request, mirror): - - total_roi = request.get_total_roi().copy() - for key, spec in request.items(): - if spec.roi is not None: - self.__mirror_roi(spec.roi, total_roi, mirror) - - def __transpose_request(self, request, transpose): - total_roi = request.get_total_roi().copy() - requested_keys = request.array_specs.keys() - lcm_voxel_size = self.spec.get_lcm_voxel_size(requested_keys) - for key, spec in request.items(): - if spec.roi is not None: - self.__transpose_roi( - spec.roi, - total_roi, - transpose, - lcm_voxel_size) - - def __mirror_roi(self, roi, total_roi, mirror): - - total_roi_offset = total_roi.get_offset() - total_roi_shape = total_roi.get_shape() - - roi_offset = roi.get_offset() - roi_shape = roi.get_shape() - - roi_in_total_offset = roi_offset - total_roi_offset - end_of_roi_in_total = roi_in_total_offset + roi_shape - roi_in_total_offset_mirrored = total_roi_shape - end_of_roi_in_total - roi_offset = Coordinate( - total_roi_offset[d] + roi_in_total_offset_mirrored[d] - if mirror[d] else roi_offset[d] - for d in range(self.dims) - ) - - roi.set_offset(roi_offset) - - def __transpose_roi(self, roi, total_roi, transpose, lcm_voxel_size): - - logger.debug("original roi = %s", roi) - - center = total_roi.get_center() - if lcm_voxel_size is not None: - nearest_voxel_shift = Coordinate( - (d % v) - for d, v in zip(center, lcm_voxel_size)) - center = center - nearest_voxel_shift - logger.debug("center = %s", center) - - # Get distance from center, then transpose - dist_to_center = center - roi.get_offset() - dist_to_center = Coordinate(dist_to_center[transpose[d]] - for d in range(self.dims)) - logger.debug("dist_to_center = %s", dist_to_center) - - # Using the tranposed distance to center, get the correct offset. - new_offset = center - dist_to_center - logger.debug("new_offset = %s", new_offset) - - shape = tuple(roi.get_shape()[transpose[d]] for d in range(self.dims)) - roi.set_offset(new_offset) - roi.set_shape(shape) - logger.debug("tranposed roi = %s", roi)
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/snapshot.html b/docs/_modules/gunpowder/nodes/snapshot.html deleted file mode 100644 index efd9034f..00000000 --- a/docs/_modules/gunpowder/nodes/snapshot.html +++ /dev/null @@ -1,582 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.snapshot — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.snapshot
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.snapshot

-import logging
-import numpy as np
-import os
-
-from .batch_filter import BatchFilter
-from gunpowder.batch_request import BatchRequest
-from gunpowder.ext import h5py
-from gunpowder.ext import ZarrFile
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Snapshot(BatchFilter): - """Save a passing batch in an HDF file. - - Args: - - dataset_names (``dict``, :class:`ArrayKey` -> ``string``): - - A dictionary from array keys to names of the datasets to store them - in. - - output_dir (``string``): - - The directory to save the snapshots. Will be created, if it does - not exist. - - output_filename (``string``): - - Template for output filenames. ``{id}`` in the string will be - replaced with the ID of the batch. ``{iteration}`` with the training - iteration (if training was performed on this batch). - - every (``int``): - - How often to save a batch. ``every=1`` indicates that every batch - will be stored, ``every=2`` every second and so on. By default, - every batch will be stored. - - additional_request (:class:`BatchRequest`): - - An additional batch request to merge with the passing request, if a - snapshot is to be made. If not given, only the arrays that are in - the batch anyway are recorded. This is useful to request additional - arrays like loss gradients for visualization that are otherwise not - needed. - - compression_type (``string`` or ``int``): - - Compression strategy. Legal values are ``gzip``, ``szip``, - ``lzf``. If an integer between 1 and 10, this indicates ``gzip`` - compression level. - - dataset_dtypes (``dict``, :class:`ArrayKey` -> data type): - - A dictionary from array keys to datatype (eg. ``np.int8``). If - given, arrays are stored using this type. The original arrays - within the pipeline remain unchanged. - - store_value_range (``bool``): - - If set to ``True``, store range of values in data set attributes. - """ - - def __init__( - self, - dataset_names, - output_dir="snapshots", - output_filename="{id}.zarr", - every=1, - additional_request=None, - compression_type=None, - dataset_dtypes=None, - store_value_range=False, - ): - self.dataset_names = dataset_names - self.output_dir = output_dir - self.output_filename = output_filename - self.every = max(1, every) - self.additional_request = ( - BatchRequest() if additional_request is None else additional_request - ) - self.n = 0 - self.compression_type = compression_type - self.store_value_range = store_value_range - if dataset_dtypes is None: - self.dataset_dtypes = {} - else: - self.dataset_dtypes = dataset_dtypes - - self.mode = "w" - - def setup(self): - - for key, _ in self.additional_request.items(): - assert key in self.dataset_names, ( - "%s requested but not in dataset_names"% key) - - for array_key in self.additional_request.array_specs.keys(): - spec = self.spec[array_key] - self.updates(array_key, spec) - for graph_key in self.additional_request.graph_specs.keys(): - spec = self.spec[graph_key] - self.updates(graph_key, spec) - - def prepare(self, request): - - deps = BatchRequest() - for key, spec in request.items(): - if key in self.dataset_names: - deps[key] = spec - - self.record_snapshot = self.n % self.every == 0 - - if self.record_snapshot: - # append additional array requests, don't overwrite existing ones - for array_key, spec in self.additional_request.array_specs.items(): - if array_key not in deps: - deps[array_key] = spec - for graph_key, spec in self.additional_request.graph_specs.items(): - if graph_key not in deps: - deps[graph_key] = spec - - for key in self.dataset_names.keys(): - assert key in deps, ( - "%s wanted for %s, but not in request." % - (key, self.name())) - - return deps - - def process(self, batch, request): - - if self.record_snapshot: - - try: - os.makedirs(self.output_dir) - except: - pass - - snapshot_name = os.path.join( - self.output_dir, - self.output_filename.format( - id=str(batch.id).zfill(8), iteration=int(batch.iteration or 0) - ), - ) - logger.info("saving to %s" % snapshot_name) - if snapshot_name.endswith(".hdf"): - open_func = h5py.File - elif snapshot_name.endswith(".zarr"): - open_func = ZarrFile - else: - logger.warning("ambiguous file type") - open_func = h5py.File - - with open_func(snapshot_name, self.mode) as f: - for (array_key, array) in batch.arrays.items(): - - if array_key not in self.dataset_names: - continue - - ds_name = self.dataset_names[array_key] - - if array_key in self.dataset_dtypes: - dtype = self.dataset_dtypes[array_key] - dataset = f.create_dataset( - name=ds_name, - data=array.data.astype(dtype), - compression=self.compression_type, - ) - - else: - dataset = f.create_dataset( - name=ds_name, - data=array.data, - compression=self.compression_type, - ) - - if not array.spec.nonspatial: - if array.spec.roi is not None: - dataset.attrs["offset"] = array.spec.roi.get_offset() - dataset.attrs["resolution"] = self.spec[array_key].voxel_size - - if self.store_value_range: - dataset.attrs["value_range"] = ( - np.asscalar(array.data.min()), - np.asscalar(array.data.max()), - ) - - # if array has attributes, add them to the dataset - for attribute_name, attribute in array.attrs.items(): - dataset.attrs[attribute_name] = attribute - - for (graph_key, graph) in batch.graphs.items(): - if graph_key not in self.dataset_names: - continue - - ds_name = self.dataset_names[graph_key] - - node_ids = [] - locations = [] - edges = [] - for node in graph.nodes: - node_ids.append(node.id) - locations.append(node.location) - for edge in graph.edges: - edges.append((edge.u, edge.v)) - - f.create_dataset( - name=f"{ds_name}-ids", - data=np.array(node_ids, dtype=int), - compression=self.compression_type, - ) - f.create_dataset( - name=f"{ds_name}-locations", - data=np.array(locations), - compression=self.compression_type, - ) - f.create_dataset( - name=f"{ds_name}-edges", - data=np.array(edges), - compression=self.compression_type, - ) - - if batch.loss is not None: - f["/"].attrs["loss"] = batch.loss - - self.n += 1
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/specified_location.html b/docs/_modules/gunpowder/nodes/specified_location.html deleted file mode 100644 index f5190868..00000000 --- a/docs/_modules/gunpowder/nodes/specified_location.html +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.specified_location — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.specified_location
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.specified_location

-from random import randrange
-from random import choice, seed
-import logging
-import numpy as np
-
-from gunpowder.coordinate import Coordinate
-from gunpowder.batch_request import BatchRequest
-
-from .batch_filter import BatchFilter
-
-logger = logging.getLogger(__name__)
-
-
[docs]class SpecifiedLocation(BatchFilter): - '''Choses a batch at a location from the list provided at init, making sure - it is in the bounding box of the upstream provider. - - Locations should be given in world units. - - Locations will be chosen in order or at random from the list depending on the - ``choose_randomly`` parameter. - - If a location requires a shift outside the bounding box of any upstream provider - the module will skip that location with a warning. - - Args: - - locations (``list`` of locations): - - Locations to center batches around. - - choose_randomly (``bool``): - - Defines whether locations should be picked in order or at random - from the list. - - extra_data (``list`` of array-like): - - A list of data that will be passed along with the arrays provided - by this node. This data will be appended as an attribute to the - dataset so it must be a data format compatible with hdf5. - - jitter (``tuple`` of int): - - How far to allow the point to shift in each direction. - Default is None, which places the point in the center. - Chooses uniformly from [loc - jitter, loc + jitter] in each - direction. - ''' - - def __init__(self, locations, choose_randomly=False, extra_data=None, - jitter=None): - - self.coordinates = locations - self.choose_randomly = choose_randomly - self.jitter = jitter - self.loc_i = -1 - self.upstream_spec = None - self.specified_shift = None - - if extra_data is not None: - assert len(extra_data) == len(locations),\ - "extra_data (%d) should match the length of specified locations (%d)"%(len(extra_data),\ - len(locations)) - - self.extra_data = extra_data - - def setup(self): - - self.upstream_spec = self.get_upstream_provider().spec - - # clear bounding boxes of all provided arrays and points -- - # SpecifiedLocation does know its locations at setup (checks on the fly) - for key, spec in self.spec.items(): - spec.roi.set_shape(None) - self.updates(key, spec) - - def prepare(self, request): - seed(request.random_seed) - np.random.seed(request.random_seed) - lcm_voxel_size = self.spec.get_lcm_voxel_size( - request.array_specs.keys()) - - # shift to center - total_roi = request.get_total_roi() - request_center = total_roi.get_shape()/2 + total_roi.get_offset() - - self.specified_shift = self._get_next_shift(request_center, lcm_voxel_size) - while not self.__check_shift(request): - logger.warning("Location %s (shift %s) skipped" - % (self.coordinates[self.loc_i], self.specified_shift)) - self.specified_shift = self._get_next_shift(request_center, lcm_voxel_size) - - # Set shift for all requests - for specs_type in [request.array_specs, request.graph_specs]: - for (key, spec) in specs_type.items(): - roi = spec.roi.shift(self.specified_shift) - specs_type[key].roi = roi - - logger.debug("{}'th ({}) shift selected: {}".format( - self.loc_i, self.coordinates[self.loc_i], self.specified_shift)) - - deps = request - return deps - - def process(self, batch, request): - # reset ROIs to request - for (array_key, spec) in request.array_specs.items(): - batch.arrays[array_key].spec.roi = spec.roi - if self.extra_data is not None: - batch.arrays[array_key].attrs['specified_location_extra_data'] =\ - self.extra_data[self.loc_i] - - for (graph_key, spec) in request.graph_specs.items(): - batch.points[graph_key].spec.roi = spec.roi - - # change shift point locations to lie within roi - for graph_key in request.graph_specs.keys(): - batch.points[graph_key].shift(-self.specified_shift) - - def _get_next_shift(self, center_shift, voxel_size): - # gets next coordinate from list - - if self.choose_randomly: - self.loc_i = randrange(len(self.coordinates)) - else: - self.loc_i += 1 - if self.loc_i >= len(self.coordinates): - self.loc_i = 0 - logger.warning('Ran out of specified locations, looping list') - next_shift = Coordinate(self.coordinates[self.loc_i]) - center_shift - - if self.jitter is not None: - rnd = [] - for i in range(len(self.jitter)): - rnd.append(np.random.randint(-self.jitter[i], - self.jitter[i]+1)) - next_shift += Coordinate(rnd) - logger.debug("Shift before rounding: %s" % str(next_shift)) - # make sure shift is a multiple of voxel size (round to nearest) - next_shift = Coordinate([int(vs * round(float(shift)/vs)) for vs, shift in zip(voxel_size, next_shift)]) - logger.debug("Shift after rounding: %s" % str(next_shift)) - return next_shift - - def __check_shift(self, request): - for key, spec in request.items(): - request_roi = spec.roi - if key in self.upstream_spec: - provided_roi = self.upstream_spec[key].roi - else: - raise Exception( - "Requested %s, but upstream does not provide it."%key) - shifted_roi = request_roi.shift(self.specified_shift) - if not provided_roi.contains(shifted_roi): - logger.warning("Provided roi %s for key %s does not contain shifted roi %s" - % (provided_roi, key, shifted_roi)) - return False - return True
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/squeeze.html b/docs/_modules/gunpowder/nodes/squeeze.html deleted file mode 100644 index c5f58757..00000000 --- a/docs/_modules/gunpowder/nodes/squeeze.html +++ /dev/null @@ -1,412 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.squeeze — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.nodes.squeeze

-import copy
-from typing import List
-import logging
-
-import numpy as np
-
-from gunpowder.array import ArrayKey
-from gunpowder.batch_request import BatchRequest
-from gunpowder.batch import Batch
-from .batch_filter import BatchFilter
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Squeeze(BatchFilter): - """Squeeze a batch at a given axis - - Args: - arrays (List[ArrayKey]): ArrayKeys to squeeze. - axis: Position of the single-dimensional axis to remove, defaults to 0. - """ - - def __init__(self, arrays: List[ArrayKey], axis: int = 0): - self.arrays = arrays - self.axis = axis - - def setup(self): - self.enable_autoskip() - for array in self.arrays: - self.updates(array, self.spec[array].copy()) - - def prepare(self, request): - deps = BatchRequest() - for array in self.arrays: - if array in request: - deps[array] = request[array].copy() - return deps - - def process(self, batch, request): - outputs = Batch() - for array in self.arrays: - - if array in batch: - if not batch[array].spec.nonspatial: - spatial_dims = request[array].roi.dims() - if self.axis >= batch[array].data.ndim - spatial_dims: - raise ValueError(( - f"Squeeze.axis={self.axis} not permitted. " - "Squeeze only supported for " - "non-spatial dimensions of Array." - )) - - outputs[array] = copy.deepcopy(batch[array]) - outputs[array].data = np.squeeze(batch[array].data, self.axis) - logger.debug(f'{array} shape: {outputs[array].data.shape}') - - return outputs
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/stack.html b/docs/_modules/gunpowder/nodes/stack.html deleted file mode 100644 index bbafb2ba..00000000 --- a/docs/_modules/gunpowder/nodes/stack.html +++ /dev/null @@ -1,409 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.stack — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.nodes.stack

-from .batch_filter import BatchFilter
-from gunpowder.array import Array
-from gunpowder.batch import Batch
-from gunpowder.profiling import Timing
-import numpy as np
-
-
[docs]class Stack(BatchFilter): - '''Request several batches and stack them together, introducing a new - dimension for each array. This is useful to create batches with several - samples and only makes sense if there is a source of randomness upstream. - - This node stacks only arrays, not points. The resulting batch will have the - same point sets as found in the first batch requested upstream. - - Args: - - num_repetitions (``int``): - - How many upstream batches to stack. - ''' - - def __init__(self, num_repetitions): - - self.num_repetitions = num_repetitions - - def provide(self, request): - - batches = [ - self.get_upstream_provider().request_batch(request) - for _ in range(self.num_repetitions) - ] - - timing = Timing(self) - timing.start() - - batch = Batch() - for b in batches: - batch.profiling_stats.merge_with(b.profiling_stats) - - for key, spec in request.array_specs.items(): - - data = np.stack([b[key].data for b in batches]) - batch[key] = Array( - data, - batches[0][key].spec.copy()) - - # copy points of first batch requested - for key, spec in request.points_specs.items(): - batch[key] = batches[0][key] - - timing.stop() - batch.profiling_stats.add(timing) - - return batch
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/unsqueeze.html b/docs/_modules/gunpowder/nodes/unsqueeze.html deleted file mode 100644 index 4e3519dd..00000000 --- a/docs/_modules/gunpowder/nodes/unsqueeze.html +++ /dev/null @@ -1,410 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.unsqueeze — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.unsqueeze
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.unsqueeze

-import copy
-from typing import List
-import logging
-
-import numpy as np
-
-from gunpowder.array import ArrayKey
-from gunpowder.batch import Batch
-from gunpowder.batch_request import BatchRequest
-from .batch_filter import BatchFilter
-
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Unsqueeze(BatchFilter): - """Unsqueeze a batch at a given axis - - Args: - arrays (List[ArrayKey]): ArrayKeys to unsqueeze. - axis: Position where the new axis is placed, defaults to 0. - """ - - def __init__(self, arrays: List[ArrayKey], axis: int = 0): - self.arrays = arrays - self.axis = axis - - def setup(self): - self.enable_autoskip() - for array in self.arrays: - self.updates(array, self.spec[array].copy()) - - def prepare(self, request): - deps = BatchRequest() - for array in self.arrays: - if array in request: - deps[array] = request[array].copy() - return deps - - def process(self, batch, request): - outputs = Batch() - for array in self.arrays: - if array in batch: - if not batch[array].spec.nonspatial: - spatial_dims = request[array].roi.dims() - if self.axis > batch[array].data.ndim - spatial_dims: - raise ValueError(( - f"Unsqueeze.axis={self.axis} not permitted. " - "Unsqueeze only supported for " - "non-spatial dimensions of Array." - )) - - outputs[array] = copy.deepcopy(batch[array]) - outputs[array].data = np.expand_dims(batch[array].data, self.axis) - return outputs
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/upsample.html b/docs/_modules/gunpowder/nodes/upsample.html deleted file mode 100644 index 8d99ff4b..00000000 --- a/docs/_modules/gunpowder/nodes/upsample.html +++ /dev/null @@ -1,454 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.upsample — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.upsample
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.upsample

-from .batch_filter import BatchFilter
-from gunpowder.coordinate import Coordinate
-from gunpowder.array import ArrayKey, Array
-from gunpowder.array_spec import ArraySpec
-from gunpowder.batch_request import BatchRequest
-from gunpowder.batch import Batch
-import logging
-import numbers
-import numpy as np
-
-logger = logging.getLogger(__name__)
-
-
[docs]class UpSample(BatchFilter): - '''Upsample arrays in a batch by given factors. - - Args: - - source (:class:`ArrayKey`): - - The key of the array to upsample. - - factor (``int`` or ``tuple`` of ``int``): - - The factor to upsample with. - - target (:class:`ArrayKey`): - - The key of the array to store the upsampled ``source``. - ''' - - def __init__(self, source, factor, target): - - assert isinstance(source, ArrayKey) - assert isinstance(target, ArrayKey) - assert ( - isinstance(factor, numbers.Number) or isinstance(factor, tuple)), ( - "Scaling factor should be a number or a tuple of numbers.") - - self.source = source - self.factor = factor - self.target = target - - def setup(self): - - spec = self.spec[self.source].copy() - - if not isinstance(self.factor, tuple): - self.factor = (self.factor,)*spec.roi.dims() - - assert spec.voxel_size % self.factor == (0,)*len(spec.voxel_size), \ - "voxel size of upsampled volume is not integer: %s/%s = %s" % ( - spec.voxel_size, - self.factor, - tuple(v/f for v, f in zip(spec.voxel_size, self.factor))) - spec.voxel_size /= self.factor - self.provides(self.target, spec) - - def prepare(self, request): - deps = BatchRequest() - - if self.target not in request: - return - - logger.debug("preparing upsampling of " + str(self.source)) - - request_roi = request[self.target].roi - logger.debug("request ROI is %s"%request_roi) - - # add or merge to batch request - deps[self.source] = ArraySpec(roi=request_roi) - - return deps - - def process(self, batch, request): - outputs = Batch() - - if self.target not in request: - return - - input_roi = batch.arrays[self.source].spec.roi - request_roi = request[self.target].roi - - assert input_roi.contains(request_roi) - - # upsample - - logger.debug("upsampling %s with %s", self.source, self.factor) - - crop = batch.arrays[self.source].crop(request_roi) - data = crop.data - - for d, f in enumerate(self.factor): - data = np.repeat(data, f, axis=d) - - # create output array - spec = self.spec[self.target].copy() - spec.roi = request_roi - outputs.arrays[self.target] = Array(data, spec) - return outputs
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/zarr_source.html b/docs/_modules/gunpowder/nodes/zarr_source.html deleted file mode 100644 index 273acc4a..00000000 --- a/docs/_modules/gunpowder/nodes/zarr_source.html +++ /dev/null @@ -1,417 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.zarr_source — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.zarr_source
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.zarr_source

-from gunpowder.compat import ensure_str
-from gunpowder.coordinate import Coordinate
-from gunpowder.ext import ZarrFile
-from .hdf5like_source_base import Hdf5LikeSource
-
-
[docs]class ZarrSource(Hdf5LikeSource): - '''A `zarr <https://github.com/zarr-developers/zarr>`_ data source. - - Provides arrays from zarr datasets. If the attribute ``resolution`` is set - in a zarr dataset, it will be used as the array's ``voxel_size``. If the - attribute ``offset`` is set in a dataset, it will be used as the offset of - the :class:`Roi` for this array. It is assumed that the offset is given in - world units. - - Args: - - filename (``string``): - - The zarr directory. - - datasets (``dict``, :class:`ArrayKey` -> ``string``): - - Dictionary of array keys to dataset names that this source offers. - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - An optional dictionary of array keys to array specs to overwrite - the array specs automatically determined from the data file. This - is useful to set a missing ``voxel_size``, for example. Only fields - that are not ``None`` in the given :class:`ArraySpec` will be used. - - channels_first (``bool``, optional): - - Specifies the ordering of the dimensions of the HDF5-like data source. - If channels_first is set (default), then the input shape is expected - to be (channels, spatial dimensions). This is recommended because of - better performance. If channels_first is set to false, then the input - data is read in channels_last manner and converted to channels_first. - ''' - - def _get_voxel_size(self, dataset): - - if 'resolution' not in dataset.attrs: - return None - - if self.filename.endswith('.n5'): - return Coordinate(dataset.attrs['resolution'][::-1]) - else: - return Coordinate(dataset.attrs['resolution']) - - def _get_offset(self, dataset): - - if 'offset' not in dataset.attrs: - return None - - if self.filename.endswith('.n5'): - return Coordinate(dataset.attrs['offset'][::-1]) - else: - return Coordinate(dataset.attrs['offset']) - - def _open_file(self, filename): - return ZarrFile(ensure_str(filename), mode='r')
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/nodes/zarr_write.html b/docs/_modules/gunpowder/nodes/zarr_write.html deleted file mode 100644 index fba9e44b..00000000 --- a/docs/_modules/gunpowder/nodes/zarr_write.html +++ /dev/null @@ -1,437 +0,0 @@ - - - - - - - - - - - gunpowder.nodes.zarr_write — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.nodes.zarr_write
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.nodes.zarr_write

-from .hdf5like_write_base import Hdf5LikeWrite
-from gunpowder.coordinate import Coordinate
-from gunpowder.ext import ZarrFile
-from gunpowder.compat import ensure_str
-import logging
-import os
-import traceback
-
-logger = logging.getLogger(__name__)
-
-
[docs]class ZarrWrite(Hdf5LikeWrite): - '''Assemble arrays of passing batches in one zarr container. This is useful - to store chunks produced by :class:`Scan` on disk without keeping the - larger array in memory. The ROIs of the passing arrays will be used to - determine the position where to store the data in the dataset. - - Args: - - dataset_names (``dict``, :class:`ArrayKey` -> ``string``): - - A dictionary from array keys to names of the datasets to store them - in. - - output_dir (``string``): - - The directory to save the zarr container. Will be created, if it does - not exist. - - output_filename (``string``): - - The output filename of the container. Will be created, if it does - not exist, otherwise data is overwritten in the existing container. - - compression_type (``string`` or ``int``): - - Compression strategy. Legal values are ``gzip``, ``szip``, - ``lzf``. If an integer between 1 and 10, this indicates ``gzip`` - compression level. - - dataset_dtypes (``dict``, :class:`ArrayKey` -> data type): - - A dictionary from array keys to datatype (eg. ``np.int8``). If - given, arrays are stored using this type. The original arrays - within the pipeline remain unchanged. - ''' - - def _get_voxel_size(self, dataset): - - if 'resolution' not in dataset.attrs: - return None - - if self.output_filename.endswith('.n5'): - return Coordinate(dataset.attrs['resolution'][::-1]) - else: - return Coordinate(dataset.attrs['resolution']) - - def _get_offset(self, dataset): - - if 'offset' not in dataset.attrs: - return None - - if self.output_filename.endswith('.n5'): - return Coordinate(dataset.attrs['offset'][::-1]) - else: - return Coordinate(dataset.attrs['offset']) - - def _set_voxel_size(self, dataset, voxel_size): - - if self.output_filename.endswith('.n5'): - dataset.attrs['resolution'] = voxel_size[::-1] - else: - dataset.attrs['resolution'] = voxel_size - - def _set_offset(self, dataset, offset): - - if self.output_filename.endswith('.n5'): - dataset.attrs['offset'] = offset[::-1] - else: - dataset.attrs['offset'] = offset - - def _open_file(self, filename): - return ZarrFile(ensure_str(filename), mode='a')
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/points.html b/docs/_modules/gunpowder/points.html deleted file mode 100644 index f0e05e53..00000000 --- a/docs/_modules/gunpowder/points.html +++ /dev/null @@ -1,419 +0,0 @@ - - - - - - - - - - - gunpowder.points — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.points

-from .freezable import Freezable
-import logging
-import numpy as np
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Points(Freezable): - '''A list of :class:`Points<Point>` with a specification describing the - data. - - Args: - - data (``dict``, ``int`` -> :class:`Point`): - - A dictionary of IDs mapping to :class:`Points<Point>`. - - spec (:class:`PointsSpec`): - - A spec describing the data. - ''' - - def __init__(self, data, spec): - self.data = data - self.spec = spec - self.freeze() - - def __repr__(self): - return "%s, %s"%(self.data, self.spec)
- -
[docs]class Point(Freezable): - '''A point with a location, as stored in :class:`Points`. - - Args: - - location (array-like of ``float``): - - The location of this point. - ''' - - def __init__(self, location): - self.location = np.array(location, dtype=np.float32) - self.freeze() - - def __repr__(self): - return str(self.location) - - def copy(self): - return Point(self.location)
- -
[docs]class PointsKey(Freezable): - '''A key to identify lists of points in requests, batches, and across - nodes. - - Used as key in :class:`BatchRequest` and :class:`Batch` to retrieve specs - or lists of points. - - Args: - - identifier (``string``): - - A unique, human readable identifier for this points key. Will be - used in log messages and to look up points in requests and batches. - Should be upper case (like ``CENTER_POINTS``). The identifier is - unique: Two points keys with the same identifier will refer to the - same points. - ''' - - def __init__(self, identifier): - self.identifier = identifier - self.hash = hash(identifier) - self.freeze() - logger.debug("Registering points type %s", self) - setattr(PointsKeys, self.identifier, self) - - def __eq__(self, other): - return hasattr(other, 'identifier') and self.identifier == other.identifier - - def __hash__(self): - return self.hash - - def __repr__(self): - return self.identifier
- -class PointsKeys: - '''Convenience access to all created :class:`PointsKey`s. A key generated - with:: - - centers = PointsKey('CENTER_POINTS') - - can be retrieved as:: - - PointsKeys.CENTER_POINTS - ''' - pass -
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/points_spec.html b/docs/_modules/gunpowder/points_spec.html deleted file mode 100644 index 84601328..00000000 --- a/docs/_modules/gunpowder/points_spec.html +++ /dev/null @@ -1,366 +0,0 @@ - - - - - - - - - - - gunpowder.points_spec — gunpowder 1.0.0rc0.dev0 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.points_spec

-import copy
-from .freezable import Freezable
-
-
[docs]class PointsSpec(Freezable): - '''Contains meta-information about a set of points. This is used by - :class:`BatchProviders<BatchProvider>` to communicate the points they - offer, as well as by :class:`Points` to describe the data they contain. - - Attributes: - - roi (:class:`Roi`): - - The region of interested represented by this set of points. - ''' - - def __init__(self, roi=None): - - self.roi = roi - - self.freeze() - -
[docs] def copy(self): - '''Create a copy of this spec.''' - return copy.deepcopy(self)
- - def __eq__(self, other): - - if isinstance(other, self.__class__): - return self.__dict__ == other.__dict__ - return NotImplemented - - def __ne__(self, other): - - if isinstance(other, self.__class__): - return not self.__eq__(other) - return NotImplemented - - def __repr__(self): - r = "" - r += "ROI: " + str(self.roi) - return r
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/provider_spec.html b/docs/_modules/gunpowder/provider_spec.html deleted file mode 100644 index e1b78307..00000000 --- a/docs/_modules/gunpowder/provider_spec.html +++ /dev/null @@ -1,602 +0,0 @@ - - - - - - - - - - - gunpowder.provider_spec — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.provider_spec

-import math
-from gunpowder.coordinate import Coordinate
-from gunpowder.array import ArrayKey
-from gunpowder.array_spec import ArraySpec
-from gunpowder.graph import GraphKey
-from gunpowder.graph_spec import GraphSpec
-from gunpowder.roi import Roi
-from .freezable import Freezable
-import time
-import logging
-import copy
-
-logger = logging.getLogger(__name__)
-
-
-import logging
-import warnings
-
-logger = logging.getLogger(__file__)
-
-
[docs]class ProviderSpec(Freezable): - '''A collection of (possibly partial) :class:`ArraySpecs<ArraySpec>` and - :class:`GraphSpecs<GraphSpec>` describing a - :class:`BatchProvider's<BatchProvider>` offered arrays and graphs. - - This collection mimics a dictionary. Specs can be added with:: - - provider_spec = ProviderSpec() - provider_spec[array_key] = ArraySpec(...) - provider_spec[graph_key] = GraphSpec(...) - - Here, ``array_key`` and ``graph_key`` are :class:`ArrayKey` and - :class:`GraphKey`. The specs can be queried with:: - - array_spec = provider_spec[array_key] - graph_spec = provider_spec[graph_key] - - Furthermore, pairs of keys/values can be iterated over using - ``provider_spec.items()``. - - To access only array or graph specs, use the dictionaries - ``provider_spec.array_specs`` or ``provider_spec.graph_specs``, - respectively. - - Args: - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`): - - Initial array specs. - - graph_specs (``dict``, :class:`GraphKey` -> :class:`GraphSpec`): - - Initial graph specs. - - Attributes: - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`): - - Contains all array specs contained in this provider spec. - - graph_specs (``dict``, :class:`GraphKey` -> :class:`GraphSpec`): - - Contains all graph specs contained in this provider spec. - ''' - - def __init__(self, array_specs=None, graph_specs=None, points_specs=None): - - self.array_specs = {} - self.graph_specs = {} - self.freeze() - - # use __setitem__ instead of copying the dicts, this ensures type tests - # are run - if array_specs is not None: - for key, spec in array_specs.items(): - self[key] = spec - if graph_specs is not None: - for key, spec in graph_specs.items(): - self[key] = spec - if points_specs is not None: - for key, spec in points_specs.items(): - self[key] = spec - - @property - def points_specs(self): - # Alias to graphs - warnings.warn( - "points_specs are depricated. Please use graph_specs", DeprecationWarning - ) - return self.graph_specs - - def __setitem__(self, key, spec): - - assert isinstance(key, ArrayKey) or isinstance(key, GraphKey), \ - f"Only ArrayKey or GraphKey (not {type(key).__name__} are " \ - "allowed as key for ProviderSpec, " - - if isinstance(key, ArrayKey): - - if isinstance(spec, Roi): - spec = ArraySpec(roi=spec) - - assert isinstance(spec, ArraySpec), \ - f"Only ArraySpec (not {type(spec).__name__}) can be set for " \ - "ArrayKey" - - self.array_specs[key] = spec.copy() - - else: - - if isinstance(spec, Roi): - spec = GraphSpec(roi=spec) - - assert isinstance(spec, GraphSpec), \ - f"Only GraphSpec (not {type(spec).__name__}) can be set for " \ - "GraphKey" - - self.graph_specs[key] = spec.copy() - - def __getitem__(self, key): - - if isinstance(key, ArrayKey): - return self.array_specs[key] - - elif isinstance(key, GraphKey): - return self.graph_specs[key] - else: - raise RuntimeError( - "Only ArrayKey or GraphKey can be used as keys in a " - "%s."%type(self).__name__) - - def __len__(self): - - return len(self.array_specs) + len(self.graph_specs) - - def __contains__(self, key): - - if isinstance(key, ArrayKey): - return key in self.array_specs - - elif isinstance(key, GraphKey): - return key in self.graph_specs - - else: - raise RuntimeError( - "Only ArrayKey or GraphKey, can be used as keys in a " - "%s. Key %s is a %s"%(type(self).__name__, key, type(key).__name__)) - - def __delitem__(self, key): - - if isinstance(key, ArrayKey): - del self.array_specs[key] - - elif isinstance(key, GraphKey): - del self.graph_specs[key] - - else: - raise RuntimeError( - "Only ArrayKey or GraphKey can be used as keys in a " - "%s."%type(self).__name__) - - def remove_placeholders(self): - self.array_specs = {k: v for k, v in self.array_specs.items() if not v.placeholder} - self.graph_specs = {k: v for k, v in self.graph_specs.items() if not v.placeholder} - -
[docs] def items(self): - '''Provides a generator iterating over key/value pairs.''' - - for (k, v) in self.array_specs.items(): - yield k, v - for (k, v) in self.graph_specs.items(): - yield k, v
- - def get_total_roi(self): - '''Get the union of all the ROIs.''' - - total_roi = None - for specs_type in [self.array_specs, self.graph_specs]: - for (_, spec) in specs_type.items(): - if total_roi is None: - total_roi = spec.roi - elif spec.roi is not None: - total_roi = total_roi.union(spec.roi) - return total_roi - - def get_common_roi(self): - '''Get the intersection of all the requested ROIs.''' - - common_roi = None - for specs_type in [self.array_specs, self.graph_specs]: - for (_, spec) in specs_type.items(): - if common_roi is None: - common_roi = spec.roi - else: - common_roi = common_roi.intersect(spec.roi) - - return common_roi - - def get_lcm_voxel_size(self, array_keys=None): - '''Get the least common multiple of the voxel sizes in this spec. - - Args: - - array_keys (list of :class:`ArrayKey`, optional): If given, - consider only the given array types. - ''' - - if array_keys is None: - array_keys = self.array_specs.keys() - - if not array_keys: - return None - - lcm_voxel_size = None - for key in array_keys: - voxel_size = self.array_specs[key].voxel_size - if voxel_size is None: - continue - if lcm_voxel_size is None: - lcm_voxel_size = voxel_size - else: - lcm_voxel_size = Coordinate( - (a * b // math.gcd(a, b) - for a, b in zip(lcm_voxel_size, voxel_size))) - - return lcm_voxel_size - - def __eq__(self, other): - - if isinstance(other, self.__class__): - other_dict = copy.deepcopy(other.__dict__) - self_dict = copy.deepcopy(self.__dict__) - return self_dict == other_dict - return NotImplemented - - def __ne__(self, other): - - if isinstance(other, self.__class__): - return not self.__eq__(other) - return NotImplemented - - def __repr__(self): - - r = "\n" - for (key, spec) in self.items(): - r += "\t%s: %s\n"%(key, spec) - return r
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/roi.html b/docs/_modules/gunpowder/roi.html deleted file mode 100644 index 24425988..00000000 --- a/docs/_modules/gunpowder/roi.html +++ /dev/null @@ -1,777 +0,0 @@ - - - - - - - - - - - gunpowder.roi — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -

Source code for gunpowder.roi

-import copy
-from .coordinate import Coordinate
-from .freezable import Freezable
-import numbers
-import numpy as np
-
-import logging
-
-logger = logging.getLogger(__file__)
-
-
[docs]class Roi(Freezable): - '''A rectangular region of interest, defined by an offset and a shape. - - Similar to :class:`Coordinate`, supports simple arithmetics, e.g.:: - - roi = Roi((1, 1, 1), (10, 10, 10)) - voxel_size = Coordinate((10, 5, 1)) - scale_shift = roi*voxel_size + 1 # == Roi((11, 6, 2), (101, 51, 11)) - - Args: - - offset (array-like of ``int``, optional): - - The starting point (inclusive) of the ROI. Can be ``None`` - (default) if the ROI only characterizes a shape. - - shape (array-like): - - The shape of the ROI. Entries can be ``None`` to indicate - unboundedness. If ``None`` is passed instead of a tuple, all - dimensions are set to ``None``, if the number of dimensions can be - inferred from ``offset``. - ''' - - def __init__(self, offset=None, shape=None): - - self.__offset = None - self.__shape = None - self.freeze() - - self.set_shape(shape) - if offset is not None: - self.set_offset(offset) - - def set_offset(self, offset): - - self.__offset = Coordinate(offset) - self.__consolidate_offset() - -
[docs] def set_shape(self, shape): - '''Set the shape of this ROI. - - Args: - - shape (array-like or ``None``): - - The new shape. Entries can be ``None`` to indicate - unboundedness. If ``None`` is passed instead of a tuple, all - dimensions are set to ``None``, if the number of dimensions can - be inferred from an existing offset or previous shape. - ''' - - if shape is None: - - if self.__shape is not None: - - dims = self.__shape.dims() - - else: - - assert self.__offset is not None, ( - "Can not infer dimension of ROI (there is no offset or " - "previous shape). Call set_shape with a tuple.") - - dims = self.__offset.dims() - - self.__shape = Coordinate((None,)*dims) - - else: - - self.__shape = Coordinate(shape) - - self.__consolidate_offset()
- - def __consolidate_offset(self): - '''Ensure that offsets for unbound dimensions are None.''' - - if self.__offset is not None: - - assert self.__offset.dims() == self.__shape.dims(), ( - "offset dimension %d != shape dimension %d"%( - self.__offset.dims(), - self.__shape.dims())) - - self.__offset = Coordinate(( - o - if s is not None else None - for o, s in zip(self.__offset, self.__shape))) - - def get_offset(self): - return self.__offset - -
[docs] def get_begin(self): - '''Smallest coordinate inside ROI.''' - return self.__offset
- -
[docs] def get_end(self): - '''Smallest coordinate which is component-wise larger than any inside ROI.''' - if not self.__shape: - return self.__offset - - return self.__offset + self.__shape
- -
[docs] def get_shape(self): - '''Get the shape of this ROI.''' - return self.__shape
- -
[docs] def get_center(self): - '''Get the center of this ROI.''' - return self.__offset + self.__shape/2
- -
[docs] def to_slices(self): - '''Get a ``tuple`` of ``slice`` that represent this ROI and can be used - to index arrays.''' - - if self.__offset is None: - return None - - return tuple( - slice( - int(self.__offset[d]) - if self.__shape[d] is not None - else None, - int(self.__offset[d] + self.__shape[d]) - if self.__shape[d] is not None - else None) - for d in range(self.dims()) - )
- -
[docs] def get_bounding_box(self): - '''Alias for ``to_slices()``.''' - return self.to_slices()
- -
[docs] def dims(self): - '''The the number of dimensions of this ROI.''' - - if self.__shape is None: - return 0 - return self.__shape.dims()
- -
[docs] def size(self): - '''Get the volume of this ROI. Returns ``None`` if the ROI is - unbounded.''' - - if self.unbounded(): - return None - - size = 1 - for d in self.__shape: - size *= d - return size
- -
[docs] def empty(self): - '''Test if this ROI is empty.''' - - return self.size() == 0
- -
[docs] def unbounded(self): - '''Test if this ROI is unbounded.''' - - return None in self.__shape
- -
[docs] def contains(self, other): - '''Test if this ROI contains ``other``, which can be another - :class:`Roi` or a :class:`Coordinate`.''' - - if isinstance(other, Roi): - - if other.empty(): - return True - - return ( - self.contains(other.get_begin()) - and - self.contains(other.get_end() - (1,)*other.dims())) - - return all([ - (b is None or p is not None and p >= b) - and - (e is None or p is not None and p < e) - for p, b, e in zip(other, self.get_begin(), self.get_end() ) - ])
- -
[docs] def intersects(self, other): - '''Test if this ROI intersects with another :class:`Roi`.''' - - assert self.dims() == other.dims() - - if self.empty() or other.empty(): - return False - - # separated if at least one dimension is separated - separated = any([ - # a dimension is separated if: - # none of the shapes is unbounded - (None not in [b1, b2, e1, e2]) - and - ( - # either b1 starts after e2 - (b1 >= e2) - or - # or b2 starts after e1 - (b2 >= e1) - ) - for b1, b2, e1, e2 in zip( - self.get_begin(), - other.get_begin(), - self.get_end(), - other.get_end()) - ]) - - return not separated
- -
[docs] def intersect(self, other): - '''Get the intersection of this ROI with another :class:`Roi`.''' - - if not self.intersects(other): - return Roi(shape=(0,)*self.dims()) # empty ROI - - begin = Coordinate(( - self.__left_max(b1, b2) - for b1, b2 in zip(self.get_begin(), other.get_begin()) - )) - end = Coordinate(( - self.__right_min(e1, e2) - for e1, e2 in zip(self.get_end(), other.get_end()) - )) - - return Roi(begin, end - begin)
- -
[docs] def union(self, other): - '''Get the union of this ROI with another :class:`Roi`.''' - - begin = Coordinate(( - self.__left_min(b1, b2) - for b1, b2 in zip(self.get_begin(), other.get_begin()) - )) - end = Coordinate(( - self.__right_max(e1, e2) - for e1, e2 in zip(self.get_end(), other.get_end()) - )) - - return Roi(begin, end - begin)
- -
[docs] def shift(self, by): - '''Shift this ROI.''' - - return Roi(self.__offset + by, self.__shape)
- -
[docs] def snap_to_grid(self, voxel_size, mode='grow'): - '''Align a ROI with a given voxel size. - - Args: - - voxel_size (:class:`Coordinate`): - - The voxel size of the grid to snap to. - - mode (string, optional): - - How to align the ROI if it is not a multiple of the voxel size. - Available modes are 'grow', 'shrink', and 'closest'. Defaults to - 'grow'. - ''' - - begin_in_voxel_fractions = ( - np.asarray(self.get_begin(), dtype=np.float32)/ - np.asarray(voxel_size)) - end_in_voxel_fractions = ( - np.asarray(self.get_end(), dtype=np.float32)/ - np.asarray(voxel_size)) - - if mode == 'closest': - begin_in_voxel = np.round(begin_in_voxel_fractions) - end_in_voxel = np.round(end_in_voxel_fractions) - elif mode == 'grow': - begin_in_voxel = np.floor(begin_in_voxel_fractions) - end_in_voxel = np.ceil(end_in_voxel_fractions) - elif mode == 'shrink': - begin_in_voxel = np.ceil(begin_in_voxel_fractions) - end_in_voxel = np.floor(end_in_voxel_fractions) - else: - assert False, 'Unknown mode %s for snap_to_grid'%mode - - return Roi( - begin_in_voxel*voxel_size, - (end_in_voxel - begin_in_voxel)*voxel_size)
- -
[docs] def grow(self, amount_neg, amount_pos): - '''Grow a ROI by the given amounts in each direction: - - Args: - - amount_neg (:class:`Coordinate` or ``None``): - - Amount (per dimension) to grow into the negative direction. - - amount_pos (:class:`Coordinate` or ``None``): - - Amount (per dimension) to grow into the positive direction. - ''' - - if amount_neg is None: - amount_neg = Coordinate((0,)*self.dims()) - if amount_pos is None: - amount_pos = Coordinate((0,)*self.dims()) - - assert len(amount_neg) == self.dims() - assert len(amount_pos) == self.dims() - - offset = self.__offset - amount_neg - shape = self.__shape + amount_neg + amount_pos - - return Roi(offset, shape)
- -
[docs] def copy(self): - '''Create a copy of this ROI.''' - return copy.deepcopy(self)
- - def __left_min(self, x, y): - - # None is considered -inf - - if x is None or y is None: - return None - return min(x, y) - - def __left_max(self, x, y): - - # None is considered -inf - - if x is None: - return y - if y is None: - return x - return max(x, y) - - def __right_min(self, x, y): - - # None is considered +inf - - if x is None: - return y - if y is None: - return x - return min(x, y) - - def __right_max(self, x, y): - - # None is considered +inf - - if x is None or y is None: - return None - return max(x, y) - - def __add__(self, other): - - assert isinstance(other, tuple), "can only add Coordinate or tuples to Roi" - return self.shift(other) - - def __sub__(self, other): - - assert isinstance(other, Coordinate), "can only subtract Coordinate from Roi" - return self.shift(-other) - - def __mul__(self, other): - - assert isinstance(other, tuple) or isinstance(other, numbers.Number), "can only multiply with a number or tuple of numbers" - return Roi(self.__offset*other, self.__shape*other) - - def __div__(self, other): - - assert isinstance(other, tuple) or isinstance(other, numbers.Number), "can only divide by a number or tuple of numbers" - return Roi(self.__offset/other, self.__shape/other) - - def __truediv__(self, other): - - assert isinstance(other, tuple) or isinstance(other, numbers.Number), "can only divide by a number or tuple of numbers" - return Roi(self.__offset/other, self.__shape/other) - - def __floordiv__(self, other): - - assert isinstance(other, tuple) or isinstance(other, numbers.Number), "can only divide by a number or tuple of numbers" - return Roi(self.__offset//other, self.__shape//other) - - def __eq__(self, other): - - if isinstance(other, self.__class__): - return self.__dict__ == other.__dict__ - return NotImplemented - - def __ne__(self, other): - - if isinstance(other, self.__class__): - return not self.__eq__(other) - return NotImplemented - - def __repr__(self): - if self.empty(): - return "[empty ROI]" - slices = ", ".join( - [ - (str(b) if b is not None else "") + - ":" + - (str(e) if e is not None else "") - for b, e in zip(self.get_begin(), self.get_end()) - ]) - dims = ", ".join( - str(a) if a is not None else "inf" - for a in self.__shape - ) - return "[" + slices + "] (" + dims + ")"
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/tensorflow/nodes/predict.html b/docs/_modules/gunpowder/tensorflow/nodes/predict.html deleted file mode 100644 index fb787f38..00000000 --- a/docs/_modules/gunpowder/tensorflow/nodes/predict.html +++ /dev/null @@ -1,753 +0,0 @@ - - - - - - - - - - - gunpowder.tensorflow.nodes.predict — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.tensorflow.nodes.predict
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.tensorflow.nodes.predict

-import ctypes
-import logging
-import multiprocessing as mp
-import numpy as np
-
-from functools import reduce
-from gunpowder.array import ArrayKey, Array
-from gunpowder.ext import tensorflow as tf
-from gunpowder.nodes.generic_predict import GenericPredict
-from gunpowder.tensorflow.local_server import LocalServer
-from operator import mul
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Predict(GenericPredict): - '''Tensorflow implementation of :class:`gunpowder.nodes.Predict`. - - Args: - - checkpoint (``string``): - - Basename of a tensorflow checkpoint storing the tensorflow graph - and associated tensor values and metadata, as created by - :class:`gunpowder.nodes.Train`, for example. - - inputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of input tensors in the network to - array keys. - - outputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of output tensors in the network to array - keys. New arrays will be generated by this node for each entry (if - requested downstream). - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - Used to set the specs of generated arrays (``outputs``). This is - useful to set the ``voxel_size``, for example, if they differ from - the voxel size of the input arrays. Only fields that are not - ``None`` in the given :class:`ArraySpec` will be used. - - graph: (``string``, optional): - - An optional path to a tensorflow computation graph that should be - used for prediction. The checkpoint is used to restore the values - of matching variable names in the graph. Note that the graph - specified here can differ from the one associated to the - checkpoint. - - skip_empty (``bool``, optional): - - Skip prediction, if all inputs are empty (contain only 0). In this - case, outputs are simply set to 0. - - max_shared_memory (``int``, optional): - - The maximal amount of shared memory in bytes to allocate to send - batches to the GPU processes. Defaults to 1GB. - ''' - - def __init__( - self, - checkpoint, - inputs, - outputs, - array_specs=None, - graph=None, - skip_empty=False, - max_shared_memory=1024*1024*1024): - - super(Predict, self).__init__( - inputs, - outputs, - array_specs) - - self.checkpoint = checkpoint - self.meta_graph = graph - self.session = None - self.graph = None - self.skip_empty = skip_empty - - self.manager = mp.Manager() - self.max_shared_memory = max_shared_memory - self.shared_input_array_config = self.manager.dict() - self.shared_output_array_config = self.manager.dict() - self.shared_input_arrays = {} - self.shared_output_arrays = {} - self.shared_input_memory = mp.RawArray( - ctypes.c_float, - self.max_shared_memory) - self.shared_output_memory = mp.RawArray( - ctypes.c_float, - self.max_shared_memory) - - self.send_lock = mp.Lock() - self.receive_lock = mp.Lock() - self.predict_process_initialized = mp.Event() - self.worker_sent_inputs = mp.Event() - self.predict_received_inputs = mp.Event() - self.predict_sent_outputs = mp.Event() - - self.predict_process = mp.Process(target=self.__predict) - self.predict_process_crashed = mp.Value('i', False) - self.predict_process.start() - self.predict_process_initialized.wait() - - def predict(self, batch, request): - - if not self.shared_output_arrays: - self.__init_shared_output_arrays() - - if self.skip_empty: - - can_skip = True - for array_key in self.inputs.values(): - if batch[array_key].data.sum() != 0: - can_skip = False - break - - if can_skip: - - logger.info("Skipping batch %i (all inputs are 0)"%batch.id) - - for name, array_key in self.outputs.items(): - - shape = self.shared_output_arrays[name].shape - dtype = self.shared_output_arrays[name].dtype - - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi.copy() - batch.arrays[array_key] = Array( - np.zeros(shape, dtype=dtype), - spec) - - return - - logger.debug("predicting in batch %i", batch.id) - - output_tensors = self.__collect_outputs(request) - input_data = self.__collect_provided_inputs(batch) - - self.send_lock.acquire() - - if not self.shared_input_arrays: - if not self.shared_input_array_config: - self.__create_shared_input_array_config(batch, request) - self.__init_shared_input_arrays() - - self.__write_inputs_to_shared(input_data) - self.worker_sent_inputs.set() - - self.receive_lock.acquire() - - self.predict_received_inputs.wait() - self.__check_background_process([self.receive_lock, self.send_lock]) - - self.predict_received_inputs.clear() - self.send_lock.release() - - self.predict_sent_outputs.wait() - - self.predict_sent_outputs.clear() - - output_data = self.__read_outputs_from_shared(output_tensors) - - self.receive_lock.release() - - for array_key in output_tensors: - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - output_data[array_key], - spec) - - logger.debug("predicted in batch %i", batch.id) - - def __predict(self): - '''The background predict process.''' - - try: - # TODO: is the server still needed? - target = LocalServer.get_target() - logger.info("Initializing tf session, connecting to %s...", target) - - self.graph = tf.Graph() - self.session = tf.Session( - target=target, - graph=self.graph) - - with self.graph.as_default(): - self.__read_checkpoint() - - if not self.shared_output_arrays: - if not self.shared_output_array_config: - self.__create_shared_output_array_config() - self.__init_shared_output_arrays() - - # from now on it is save to access the shared array configuration - self.predict_process_initialized.set() - - # loop predict - while True: - - # wait for inputs - self.worker_sent_inputs.wait() - self.worker_sent_inputs.clear() - - if not self.shared_input_arrays: - self.__init_shared_input_arrays() - - # read inputs - input_data = self.__read_inputs_from_shared() - self.predict_received_inputs.set() - - # compute outputs - output_data = self.session.run( - {t: t for t in self.outputs.keys()}, - feed_dict=input_data) - - # write outputs - self.__write_outputs_to_shared(output_data) - self.predict_sent_outputs.set() - - except Exception as e: - - self.predict_process_crashed.value = True - - # release locks and events - self.predict_process_initialized.set() - self.worker_sent_inputs.clear() - self.predict_received_inputs.set() - self.predict_sent_outputs.set() - raise e - - def teardown(self): - - self.predict_process.terminate() - self.predict_process.join() - - def __check_background_process(self, locks=[]): - - if self.predict_process_crashed.value: - # release all locks before raising exception - for l in locks: - l.release() - raise RuntimeError("Background process died.") - - def __read_checkpoint(self): - - # read the graph associated to the checkpoint - if self.meta_graph is None: - meta_graph_file = self.checkpoint + '.meta' - # read alternative, custom graph - else: - meta_graph_file = self.meta_graph - - logger.info( - "Reading graph from %s and weights from %s...", - meta_graph_file, self.checkpoint) - - saver = tf.train.import_meta_graph( - meta_graph_file, - clear_devices=True) - - # restore variables from checkpoint - saver.restore(self.session, self.checkpoint) - - def __collect_outputs(self, request=None): - '''Get a dict: - - array key: tensor name - - If request is not None, return only outputs that are in request. - ''' - - array_outputs = {} - - for tensor_name, array_key in self.outputs.items(): - if request is None or array_key in request: - array_outputs[array_key] = tensor_name - - return array_outputs - - def __collect_provided_inputs(self, batch): - '''Get a dict: - - tensor name: ndarray - ''' - - inputs = {} - - for input_name, input_key in self.inputs.items(): - if isinstance(input_key, ArrayKey): - if input_key in batch.arrays: - inputs[input_name] = batch.arrays[input_key].data - else: - logger.warn("batch does not contain %s, input %s will not " - "be set", input_key, input_name) - elif isinstance(input_key, np.ndarray): - inputs[input_name] = input_key - elif isinstance(input_key, str): - inputs[input_name] = getattr(batch, input_key) - else: - raise Exception( - "Unknown network input key {}, can't be given to " - "network".format(input_key)) - - return inputs - - def __create_shared_input_array_config(self, batch, request): - '''Store the shared array config in a shared dictionary. Should be run - once by the first worker to submit a batch.''' - - begin = 0 - for name, array_key in self.inputs.items(): - - shape = batch[array_key].data.shape - size = reduce(mul, shape, 1) - dtype = batch[array_key].data.dtype - - self.shared_input_array_config[name] = ( - begin, - size, - shape, - dtype) - - begin += size*np.dtype(dtype).itemsize - assert begin <= self.max_shared_memory, ( - "The input arrays exceed the max_shared_memory") - - def __create_shared_output_array_config(self): - '''To be called by predict process.''' - - begin = 0 - for name, array_key in self.outputs.items(): - - tensor = self.graph.get_tensor_by_name(name) - shape = tensor.get_shape().as_list() - size = reduce(mul, shape, 1) - dtype = tensor.dtype.as_numpy_dtype - - self.shared_output_array_config[name] = ( - begin, - size, - tuple(shape), - dtype) - - begin += size*np.dtype(dtype).itemsize - assert begin <= self.max_shared_memory, ( - "The output arrays exceed the max_shared_memory") - - def __init_shared_input_arrays(self): - '''Assign the shared memory to numpy arrays.''' - - for name, (begin, size, shape, dtype) in self.shared_input_array_config.items(): - - self.shared_input_arrays[name] = np.frombuffer( - self.shared_input_memory, - dtype=dtype, - offset=begin, - count=size).reshape(shape) - - def __init_shared_output_arrays(self): - '''Assign the shared memory to numpy arrays.''' - - for name, (begin, size, shape, dtype) in self.shared_output_array_config.items(): - - self.shared_output_arrays[name] = np.frombuffer( - self.shared_output_memory, - dtype=dtype, - offset=begin, - count=size).reshape(shape) - - def __write_inputs_to_shared(self, input_data): - - for tensor_name, data in input_data.items(): - self.shared_input_arrays[tensor_name][:] = data - - def __read_inputs_from_shared(self): - - return { - tensor_name: self.shared_input_arrays[tensor_name].copy() - for tensor_name in self.inputs.keys() - } - - def __write_outputs_to_shared(self, output_data): - - for tensor_name, data in output_data.items(): - self.shared_output_arrays[tensor_name][:] = data - - def __read_outputs_from_shared(self, output_tensors): - - return { - array_key: self.shared_output_arrays[tensor_name].copy() - for array_key, tensor_name in output_tensors.items() - }
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/tensorflow/nodes/train.html b/docs/_modules/gunpowder/tensorflow/nodes/train.html deleted file mode 100644 index 4b6f0f09..00000000 --- a/docs/_modules/gunpowder/tensorflow/nodes/train.html +++ /dev/null @@ -1,724 +0,0 @@ - - - - - - - - - - - gunpowder.tensorflow.nodes.train — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.tensorflow.nodes.train
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.tensorflow.nodes.train

-import logging
-import os
-import numpy as np
-
-from gunpowder.array import ArrayKey, Array
-from gunpowder.ext import tensorflow as tf
-from gunpowder.nodes.generic_train import GenericTrain
-from gunpowder.tensorflow.local_server import LocalServer
-
-logger = logging.getLogger(__name__)
-
-
[docs]class Train(GenericTrain): - '''Tensorflow implementation of :class:`gunpowder.nodes.Train`. - - Args: - - graph (``string``): - - Filename of a tensorflow meta-graph storing the tensorflow graph - containing an optimizer. A meta-graph file can be created by - running:: - - # create tensorflow graph - ... - - # store it - tf.train.export_meta_graph(filename='...') - - optimizer (``string`` or function): - - Either the name of the tensorflow operator performing a training - iteration, or a function that, given the graph of the meta-graph - file, adds a custom loss and optimizer. - - If a function is given, it should return a tuple ``(loss, - optimizer)`` of a tensor and an operator representing the loss and - the optimizer, respectively. In this case, parameter ``loss`` - should be ``None``. - - Example:: - - def add_custom_optimizer(graph): - - # get the output of your graph - output = graph.get_tensor_by_name('...') - - # create your custom loss - loss = custom_loss(output) - - # add an optimizer of your choice - optimizer = tf.train.AdamOptimizer().minimize(loss) - - return (loss, optimizer) - - loss (``string`` or ``None``): - - The name of the tensorflow tensor containing the loss, or ``None`` - if ``optimizer`` is a function. - - inputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of input tensors in the network to - array keys. - - outputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of output tensors in the network to array - keys. New arrays will be generated by this node for each entry (if - requested downstream). - - gradients (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of output tensors in the network to - array keys. New arrays containing the gradient of an output with - respect to the loss will be generated by this node for each entry - (if requested downstream). - - summary (``string`` or - ``dict``, ``string`` -> (``string`` (tensor name), freq), - optional): - - The name of the tensorflow tensor containing the tensorboard - summaries or dictionary for different subcategories of summaires - (key: string, value: tuple with tensor/op name and frequency, - of evaluation). - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - Used to set the specs of generated arrays (``outputs``). This is - useful to set the ``voxel_size``, for example, if they differ from - the voxel size of the input arrays. Only fields that are not - ``None`` in the given :class:`ArraySpec` will be used. - - save_every (``int``, optional): - - After how many iterations to create a checkpoint to store the - learnt weights. - - log_dir (``string``, optional): - - Directory for saving tensorboard summaries. - - log_every (``int``, optional): - - After how many iterations to write out tensorboard summaries. - ''' - - def __init__( - self, - graph, - optimizer, - loss, - inputs, - outputs, - gradients, - summary=None, - array_specs=None, - save_every=2000, - log_dir='./', - log_every=1): - - super(Train, self).__init__( - inputs, - outputs, - gradients, - array_specs, - spawn_subprocess=False) - self.meta_graph_filename = graph - self.optimizer_func = None - self.optimizer_loss_names = None - self.optimizer = None - self.loss = None - self.summary = summary - self.session = None - self.tf_gradient = {} - self.graph = None - self.basic_saver = None - self.full_saver = None - self.save_every = save_every - self.iteration = None - self.iteration_increment = None - self.summary_saver = None - self.log_dir = log_dir - self.log_every = log_every - # Check if optimizer is a str in python 2/3 compatible way. - if isinstance(optimizer, ("".__class__, u"".__class__)): - self.optimizer_loss_names = (optimizer, loss) - else: - self.optimizer_func = optimizer - - # at least for some versions of tensorflow, the checkpoint name has to - # start with a . if it is a relative path - if not os.path.isabs(self.meta_graph_filename): - self.meta_graph_filename = os.path.join('.', self.meta_graph_filename) - - def start(self): - - target = LocalServer.get_target() - logger.info("Initializing tf session, connecting to %s...", target) - - self.graph = tf.Graph() - self.session = tf.Session( - target=target, - graph=self.graph) - - with self.graph.as_default(): - self.__read_meta_graph() - - if self.summary is not None: - self.summary_saver = tf.summary.FileWriter(self.log_dir, self.graph) - - if self.optimizer_func is None: - - # get actual operations/tensors from names - self.optimizer = self.graph.get_operation_by_name(self.optimizer_loss_names[0]) - self.loss = self.graph.get_tensor_by_name(self.optimizer_loss_names[1]) - - # add symbolic gradients - for tensor_name in self.gradients: - tensor = self.graph.get_tensor_by_name(tensor_name) - self.tf_gradient[tensor_name] = tf.gradients( - self.loss, - [tensor])[0] - - def train_step(self, batch, request): - - array_outputs = self.__collect_requested_outputs(request) - inputs = self.__collect_provided_inputs(batch) - - to_compute = { - 'optimizer': self.optimizer, - 'loss': self.loss, - 'iteration': self.iteration_increment} - to_compute.update(array_outputs) - - # compute outputs, gradients, and update variables - if isinstance(self.summary, str): - to_compute["summaries"] = self.summary - elif isinstance(self.summary, dict): - for k, (v, f) in self.summary.items(): - if int(self.current_step+1) % f == 0: - to_compute[k] = v - outputs = self.session.run(to_compute, feed_dict=inputs) - - for array_key in array_outputs: - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - outputs[array_key], - spec) - - batch.loss = outputs['loss'] - batch.iteration = outputs['iteration'][0] - self.current_step = batch.iteration - if self.summary is not None: - if isinstance(self.summary, str) and \ - (batch.iteration % self.log_every == 0 or batch.iteration == 1): - self.summary_saver.add_summary( - outputs['summaries'], batch.iteration) - else: - for k, (_, f) in self.summary.items(): - if int(self.current_step) % f == 0: - self.summary_saver.add_summary( - outputs[k], batch.iteration) - - if batch.iteration%self.save_every == 0: - - checkpoint_name = ( - self.meta_graph_filename + - '_checkpoint_%i'%batch.iteration) - - logger.info( - "Creating checkpoint %s", - checkpoint_name) - - self.full_saver.save( - self.session, - checkpoint_name) - - def stop(self): - - if self.session is not None: - - self.optimizer = None - self.loss = None - if self.summary is not None: - self.summary_saver.close() - self.session.close() - self.graph = None - self.session = None - - def __read_meta_graph(self): - - logger.info("Reading meta-graph...") - - # read the original meta-graph - tf.train.import_meta_graph( - self.meta_graph_filename + '.meta', - clear_devices=True) - - # add custom gunpowder variables - with tf.variable_scope('gunpowder'): - self.iteration = tf.get_variable( - 'iteration', - shape=1, - initializer=tf.zeros_initializer, - trainable=False) - self.iteration_increment = tf.assign( - self.iteration, - self.iteration + 1) - - # Until now, only variables have been added to the graph that are part - # of every checkpoint. We create a 'basic_saver' for only those - # variables. - self.basic_saver = tf.train.Saver(max_to_keep=None) - - # Add custom optimizer and loss, if requested. This potentially adds - # more variables, not covered by the basic_saver. - if self.optimizer_func is not None: - loss, optimizer = self.optimizer_func(self.graph) - self.loss = loss - self.optimizer = optimizer - - # We create a 'full_saver' including those variables. - self.full_saver = tf.train.Saver(max_to_keep=None) - - # find most recent checkpoint - checkpoint_dir = os.path.dirname(self.meta_graph_filename) - checkpoint = tf.train.latest_checkpoint(checkpoint_dir) - - if checkpoint: - - try: - # Try to restore the graph, including the custom optimizer - # state (if a custom optimizer was used). - self.__restore_graph(checkpoint, restore_full=True) - - except tf.errors.NotFoundError: - - # If that failed, we just transitioned from an earlier training - # without the custom optimizer. In this case, restore only the - # variables of the original meta-graph and 'gunpowder' - # variables. Custom optimizer variables will be default - # initialized. - logger.info("Checkpoint did not contain custom optimizer " - "variables") - self.__restore_graph(checkpoint, restore_full=False) - else: - - logger.info("No checkpoint found") - - # initialize all variables - self.session.run(tf.global_variables_initializer()) - - def __restore_graph(self, checkpoint, restore_full): - - logger.info("Restoring model from %s", checkpoint) - - if restore_full: - - logger.info("...using a saver for all variables") - self.full_saver.restore(self.session, checkpoint) - - else: - - # initialize all variables, such that non-basic variables are - # initialized - self.session.run(tf.global_variables_initializer()) - - logger.info("...using a saver for basic variables only") - self.basic_saver.restore(self.session, checkpoint) - - self.current_step = self.session.run(self.iteration) - - def __collect_requested_outputs(self, request): - - array_outputs = {} - - for output_name, array_key in self.outputs.items(): - if array_key in request: - array_outputs[array_key] = output_name - - for output_name, array_key in self.gradients.items(): - if array_key in request: - array_outputs[array_key] = self.tf_gradient[output_name] - - return array_outputs - - def __collect_provided_inputs(self, batch): - - inputs = {} - - for input_name, input_key in self.inputs.items(): - if isinstance(input_key, ArrayKey): - if input_key in batch.arrays: - inputs[input_name] = batch.arrays[input_key].data - else: - logger.warn("batch does not contain %s, input %s will not " - "be set", input_key, input_name) - elif isinstance(input_key, np.ndarray): - inputs[input_name] = input_key - elif isinstance(input_key, str): - inputs[input_name] = getattr(batch, input_key) - else: - raise Exception( - "Unknown network input key {}, can't be given to " - "network".format(input_key)) - - return inputs
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/torch/nodes/predict.html b/docs/_modules/gunpowder/torch/nodes/predict.html deleted file mode 100644 index 0eceb695..00000000 --- a/docs/_modules/gunpowder/torch/nodes/predict.html +++ /dev/null @@ -1,517 +0,0 @@ - - - - - - - - - - - gunpowder.torch.nodes.predict — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.torch.nodes.predict
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.torch.nodes.predict

-from gunpowder.array import ArrayKey, Array
-from gunpowder.array_spec import ArraySpec
-from gunpowder.ext import torch
-from gunpowder.nodes.generic_predict import GenericPredict
-
-import logging
-from typing import Dict, Union
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Predict(GenericPredict): - """Torch implementation of :class:`gunpowder.nodes.Predict`. - - Args: - - model (subclass of ``torch.nn.Module``): - - The model to use for prediction. - - inputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of input tensors (argument names of the - ``forward`` method) in the model to array keys. - - outputs (``dict``, ``string`` or ``int`` -> :class:`ArrayKey`): - - Dictionary from the names of tensors in the network to array - keys. If the key is a string, the tensor will be retrieved - by checking the model for an attribute with the key as its name. - If the key is an integer, it is interpreted as a tuple index of - the outputs of the network. - New arrays will be generated by this node for each entry (if - requested downstream). - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - Used to set the specs of generated arrays (``outputs``). This is - useful to set the ``voxel_size``, for example, if they differ from - the voxel size of the input arrays. Only fields that are not - ``None`` in the given :class:`ArraySpec` will be used. - - checkpoint: (``string``, optional): - - An optional path to the saved parameters for your torch module. - These will be loaded and used for prediction if provided. - - device (``string``, optional): - - Which device to use for prediction (``"cpu"`` or ``"cuda"``). - Default is ``"cuda"``, which falls back to CPU if CUDA is not - available. - - spawn_subprocess (bool, optional): Whether to run ``predict`` in a - separate process. Default is false. - """ - - def __init__( - self, - model, - inputs: Dict[str, ArrayKey], - outputs: Dict[Union[str, int], ArrayKey], - array_specs: Dict[ArrayKey, ArraySpec] = None, - checkpoint: str = None, - device="cuda", - spawn_subprocess=False - ): - - self.array_specs = array_specs if array_specs is not None else {} - - if model.training: - logger.warning( - "Model is in training mode during prediction. " - "Consider using model.eval()" - ) - - super(Predict, self).__init__( - inputs, - outputs, - array_specs, - spawn_subprocess=spawn_subprocess) - - self.device_string = device - self.device = None # to be set in start() - self.model = model - self.checkpoint = checkpoint - - self.intermediate_layers = {} - self.register_hooks() - - def start(self): - - self.use_cuda = ( - torch.cuda.is_available() and - self.device_string == "cuda") - logger.info(f"Predicting on {'gpu' if self.use_cuda else 'cpu'}") - self.device = torch.device("cuda" if self.use_cuda else "cpu") - - try: - self.model = self.model.to(self.device) - except RuntimeError as e: - raise RuntimeError( - "Failed to move model to device. If you are using a child process " - "to run your model, maybe you already initialized CUDA by sending " - "your model to device in the main process." - ) from e - - if self.checkpoint is not None: - checkpoint = torch.load(self.checkpoint, map_location=self.device) - if "model_state_dict" in checkpoint: - self.model.load_state_dict(checkpoint["model_state_dict"]) - else: - self.model.load_state_dict() - - def predict(self, batch, request): - inputs = self.get_inputs(batch) - with torch.no_grad(): - out = self.model.forward(**inputs) - outputs = self.get_outputs(out, request) - self.update_batch(batch, request, outputs) - - def get_inputs(self, batch): - model_inputs = { - key: torch.as_tensor(batch[value].data, device=self.device) - for key, value in self.inputs.items() - } - return model_inputs - - def register_hooks(self): - for key in self.outputs: - if isinstance(key, str): - layer = getattr(self.model, key) - layer.register_forward_hook(self.create_hook(key)) - - def create_hook(self, key): - def save_layer(module, input, output): - self.intermediate_layers[key] = output - - return save_layer - - def get_outputs(self, module_out, request): - outputs = {} - if isinstance(module_out, tuple): - module_outs = module_out - else: - module_outs = (module_out,) - for key, value in self.outputs.items(): - if value in request: - if isinstance(key, str): - outputs[value] = self.intermediate_layers[key] - elif isinstance(key, int): - outputs[value] = module_outs[key] - return outputs - - def update_batch(self, batch, request, requested_outputs): - for array_key, tensor in requested_outputs.items(): - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array(tensor.cpu().detach().numpy(), spec) - - def stop(self): - pass
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/gunpowder/torch/nodes/train.html b/docs/_modules/gunpowder/torch/nodes/train.html deleted file mode 100644 index 462d436d..00000000 --- a/docs/_modules/gunpowder/torch/nodes/train.html +++ /dev/null @@ -1,719 +0,0 @@ - - - - - - - - - - - gunpowder.torch.nodes.train — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Module code »
  • - -
  • gunpowder.torch.nodes.train
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

Source code for gunpowder.torch.nodes.train

-import logging
-import numpy as np
-
-from gunpowder.array import ArrayKey, Array
-from gunpowder.array_spec import ArraySpec
-from gunpowder.ext import torch, tensorboardX, NoSuchModule
-from gunpowder.nodes.generic_train import GenericTrain
-
-from typing import Dict, Union, Optional
-
-logger = logging.getLogger(__name__)
-
-
-
[docs]class Train(GenericTrain): - """Torch implementation of :class:`gunpowder.nodes.GenericTrain`. - - Args: - - model (subclass of ``torch.nn.Module``): - - The model to train. - - loss: - - The torch loss to use. - - optimizer: - - The torch optimizer to use. - - inputs (``dict``, ``string`` -> :class:`ArrayKey`): - - Dictionary from the names of input tensors (argument names of the - ``forward`` method) in the model to array keys. - - loss_inputs (``dict``, ``string`` or ``int`` -> :class:`ArrayKey`): - - Dictionary with the names of input variables to the loss function as - keys, and ArrayKeys containing the desired data as values. Keys can - be either strings or integers. If the key is an integer, it will - be treated as a positional argument to the loss function, a - string will be used as a named argument - - outputs (``dict``, ``string`` or ``int`` -> :class:`ArrayKey`): - - Dictionary from the names of tensors in the network to array - keys. If the key is a string, the tensor will be retrieved - by checking the model for an attribute with they key as its name. - If the key is an integer, it is interpreted as a tuple index of - the outputs of the network. - New arrays will be generated by this node for each entry (if - requested downstream). - - array_specs (``dict``, :class:`ArrayKey` -> :class:`ArraySpec`, optional): - - Used to set the specs of generated arrays (at the moment only - ``output``). This is useful to set the ``voxel_size``, for example, - if they differ from the voxel size of the input arrays. Only fields - that are not ``None`` in the given :class:`ArraySpec` will be used. - - checkpoint_basename (``string``, optional): - - The basename used for checkpoint files. Defaults to ``model``. - - save_every (``int``, optional): - - After how many iterations to create a checkpoint to store the - learnt weights. - - log_dir (``string``, optional): - - Directory for saving tensorboard summaries. - - log_every (``int``, optional): - - After how many iterations to write out tensorboard summaries. - - spawn_subprocess (``bool``, optional): - - Whether to run the ``train_step`` in a separate process. Default is false. - """ - - def __init__( - self, - model, - loss, - optimizer, - inputs: Dict[str, ArrayKey], - outputs: Dict[Union[int, str], ArrayKey], - loss_inputs: Dict[Union[int, str], ArrayKey], - gradients: Dict[Union[int, str], ArrayKey] = {}, - array_specs: Optional[Dict[ArrayKey, ArraySpec]] = None, - checkpoint_basename: str = "model", - save_every: int = 2000, - log_dir: str = None, - log_every: int = 1, - spawn_subprocess: bool = False, - ): - - if not model.training: - logger.warning( - "Model is in evaluation mode during training. " - "Consider using model.train()" - ) - - # not yet implemented - gradients = gradients - inputs.update( - {k: v for k, v in loss_inputs.items() if v not in outputs.values()} - ) - - super(Train, self).__init__( - inputs, outputs, gradients, array_specs, spawn_subprocess=spawn_subprocess - ) - - self.model = model - self.loss = loss - self.optimizer = optimizer - self.loss_inputs = loss_inputs - self.checkpoint_basename = checkpoint_basename - self.save_every = save_every - - self.iteration = 0 - - if not isinstance(tensorboardX, NoSuchModule) and log_dir is not None: - self.summary_writer = tensorboardX.SummaryWriter(log_dir) - self.log_every = log_every - else: - self.summary_writer = None - if log_dir is not None: - logger.warning("log_dir given, but tensorboardX is not installed") - - self.intermediate_layers = {} - self.register_hooks() - - def register_hooks(self): - for key in self.outputs: - if isinstance(key, str): - layer = getattr(self.model, key) - layer.register_forward_hook(self.create_hook(key)) - - def create_hook(self, key): - def save_layer(module, input, output): - self.intermediate_layers[key] = output - - return save_layer - - def retain_gradients(self, request, outputs): - for array_name, array_key in self.gradients.items(): - if array_key not in request: - continue - if isinstance(array_name, int): - tensor = outputs[array_name] - elif isinstance(array_name, str): - tensor = getattr(self.model, array_name) - else: - raise RuntimeError( - "only ints and strings are supported as gradients keys" - ) - tensor.retain_grad() - - def start(self): - - self.use_cuda = torch.cuda.is_available() - self.device = torch.device("cuda" if self.use_cuda else "cpu") - - try: - self.model = self.model.to(self.device) - except RuntimeError as e: - raise RuntimeError( - "Failed to move model to device. If you are using a child process " - "to run your model, maybe you already initialized CUDA by sending " - "your model to device in the main process." - ) from e - if isinstance(self.loss, torch.nn.Module): - self.loss = self.loss.to(self.device) - - checkpoint, self.iteration = self._get_latest_checkpoint( - self.checkpoint_basename - ) - - if checkpoint is not None: - - logger.info("Resuming training from iteration %d", self.iteration) - logger.info("Loading %s", checkpoint) - - checkpoint = torch.load(checkpoint, map_location=self.device) - self.model.load_state_dict(checkpoint["model_state_dict"]) - self.optimizer.load_state_dict(checkpoint["optimizer_state_dict"]) - - else: - - logger.info("Starting training from scratch") - - logger.info("Using device %s", self.device) - - def train_step(self, batch, request): - - inputs = self.__collect_provided_inputs(batch) - requested_outputs = self.__collect_requested_outputs(request) - - # keys are argument names of model forward pass - device_inputs = { - k: torch.as_tensor(v, device=self.device) for k, v in inputs.items() - } - - # get outputs. Keys are tuple indices or model attr names as in self.outputs - self.optimizer.zero_grad() - model_outputs = self.model(**device_inputs) - if isinstance(model_outputs, tuple): - outputs = {i: model_outputs[i] for i in range(len(model_outputs))} - elif isinstance(model_outputs, torch.Tensor): - outputs = {0: model_outputs} - else: - raise RuntimeError( - "Torch train node only supports return types of tuple", - f"and torch.Tensor from model.forward(). not {type(model_outputs)}", - ) - outputs.update(self.intermediate_layers) - - # Some inputs to the loss should come from the batch, not the model - provided_loss_inputs = self.__collect_provided_loss_inputs(batch) - - device_loss_inputs = { - k: torch.as_tensor(v, device=self.device) - for k, v in provided_loss_inputs.items() - } - - # Some inputs to the loss function should come from the outputs of the model - # Update device loss inputs with tensors from outputs if available - flipped_outputs = {v: outputs[k] for k, v in self.outputs.items()} - device_loss_inputs = { - k: flipped_outputs.get(v, device_loss_inputs.get(k)) - for k, v in self.loss_inputs.items() - } - - device_loss_args = [] - for i in range(len(device_loss_inputs)): - if i in device_loss_inputs: - device_loss_args.append(device_loss_inputs.pop(i)) - else: - break - device_loss_kwargs = {} - for k, v in list(device_loss_inputs.items()): - if isinstance(k, str): - device_loss_kwargs[k] = device_loss_inputs.pop(k) - assert ( - len(device_loss_inputs) == 0 - ), f"Not all loss inputs could be interpreted. Failed keys: {device_loss_inputs.keys()}" - - self.retain_gradients(request, outputs) - - logger.debug( - "model outputs: %s", - {k: v.shape for k, v in outputs.items()}) - logger.debug( - "loss inputs: %s %s", - [v.shape for v in device_loss_args], - {k: v.shape for k, v in device_loss_kwargs.items()}) - loss = self.loss(*device_loss_args, **device_loss_kwargs) - loss.backward() - self.optimizer.step() - - # add requested model outputs to batch - for array_key, array_name in requested_outputs.items(): - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - outputs[array_name].cpu().detach().numpy(), spec - ) - - for array_name, array_key in self.gradients.items(): - if array_key not in request: - continue - if isinstance(array_name, int): - tensor = outputs[array_name] - elif isinstance(array_name, str): - tensor = getattr(self.model, array_name) - else: - raise RuntimeError( - "only ints and strings are supported as gradients keys" - ) - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - tensor.grad.cpu().detach().numpy(), spec - ) - - for array_key, array_name in requested_outputs.items(): - spec = self.spec[array_key].copy() - spec.roi = request[array_key].roi - batch.arrays[array_key] = Array( - outputs[array_name].cpu().detach().numpy(), spec - ) - - batch.loss = loss.cpu().detach().numpy() - self.iteration += 1 - batch.iteration = self.iteration - - if batch.iteration % self.save_every == 0: - - checkpoint_name = self._checkpoint_name( - self.checkpoint_basename, batch.iteration - ) - - logger.info("Creating checkpoint %s", checkpoint_name) - - torch.save( - { - "model_state_dict": self.model.state_dict(), - "optimizer_state_dict": self.optimizer.state_dict(), - }, - checkpoint_name, - ) - - if self.summary_writer and batch.iteration % self.log_every == 0: - self.summary_writer.add_scalar("loss", batch.loss, batch.iteration) - - def __collect_requested_outputs(self, request): - - array_outputs = {} - - for output_name, array_key in self.outputs.items(): - if array_key in request: - array_outputs[array_key] = output_name - - return array_outputs - - def __collect_provided_inputs(self, batch): - - return self.__collect_provided_arrays( - {k: v for k, v in self.inputs.items() if k not in self.loss_inputs}, batch - ) - - def __collect_provided_loss_inputs(self, batch): - - return self.__collect_provided_arrays( - self.loss_inputs, batch, expect_missing_arrays=True - ) - - def __collect_provided_arrays(self, reference, batch, expect_missing_arrays=False): - - arrays = {} - - for array_name, array_key in reference.items(): - if isinstance(array_key, ArrayKey): - msg = f"batch does not contain {array_key}, array {array_name} will not be set" - if array_key in batch.arrays: - arrays[array_name] = batch.arrays[array_key].data - elif not expect_missing_arrays: - logger.warn(msg) - else: - logger.debug(msg) - elif isinstance(array_key, np.ndarray): - arrays[array_name] = array_key - elif isinstance(array_key, str): - arrays[array_name] = getattr(batch, array_key) - else: - raise Exception( - "Unknown network array key {}, can't be given to " - "network".format(array_key) - ) - - return arrays
-
- -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_modules/index.html b/docs/_modules/index.html deleted file mode 100644 index b798a3e7..00000000 --- a/docs/_modules/index.html +++ /dev/null @@ -1,405 +0,0 @@ - - - - - - - - - - - Overview: module code — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Overview: module code
  • - - -
  • - -
  • - -
- - -
-
-
-
- -

All modules for which code is available

- - -
- -
- - -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/_sources/api.rst.txt b/docs/_sources/api.rst.txt deleted file mode 100644 index fd48727d..00000000 --- a/docs/_sources/api.rst.txt +++ /dev/null @@ -1,323 +0,0 @@ -.. _sec_api: - -API Reference -============= - -.. automodule:: gunpowder - :noindex: - -Data Containers ---------------- - -Batch -^^^^^ - .. autoclass:: Batch - :members: - -Array -^^^^^ - .. autoclass:: Array - :members: - -Graph -^^^^^ - .. autoclass:: Graph - :members: - -Node -^^^^ - .. autoclass:: Node - :members: - -Edge -^^^^ - .. autoclass:: Edge - :members: - -ArrayKey -^^^^^^^^ - .. autoclass:: ArrayKey - -GraphKey -^^^^^^^^ - .. autoclass:: GraphKey - -Requests and Specifications ---------------------------- - -ProviderSpec -^^^^^^^^^^^^ - .. autoclass:: ProviderSpec - :members: array_specs, points_specs, items - -BatchRequest -^^^^^^^^^^^^ - .. autoclass:: BatchRequest - :members: add - -ArraySpec -^^^^^^^^^ - .. autoclass:: ArraySpec - :members: - -GraphSpec -^^^^^^^^^ - .. autoclass:: GraphSpec - :members: - -Geometry --------- - -Coordinate -^^^^^^^^^^ - .. autoclass:: Coordinate - :members: - -Roi -^^^ - .. autoclass:: Roi - :members: - -Node Base Classes ------------------ - -BatchProvider -^^^^^^^^^^^^^ - .. autoclass:: BatchProvider - :members: setup, provides, provide, teardown, spec, request_batch - -BatchFilter -^^^^^^^^^^^ - .. autoclass:: BatchFilter - :members: setup, updates, provides, enable_autoskip, prepare, process, teardown, spec, request_batch - -.. _sec_api_source_nodes: - -Source Nodes ------------- - -ZarrSource -^^^^^^^^^^ - .. autoclass:: ZarrSource - -Hdf5Source -^^^^^^^^^^ - .. autoclass:: Hdf5Source - -KlbSource -^^^^^^^^^ - .. autoclass:: KlbSource - -DvidSource -^^^^^^^^^^ - .. autoclass:: DvidSource - -CsvPointsSource -^^^^^^^^^^^^^^^ - .. autoclass:: CsvPointsSource - -.. _sec_api_augmentation_nodes: - -Augmentation Nodes ------------------- - -DefectAugment -^^^^^^^^^^^^^ - .. autoclass:: DefectAugment - -ElasticAugment -^^^^^^^^^^^^^^ - .. autoclass:: ElasticAugment - -IntensityAugment -^^^^^^^^^^^^^^^^ - .. autoclass:: IntensityAugment - -NoiseAugment -^^^^^^^^^^^^^^^^ - .. autoclass:: NoiseAugment - -SimpleAugment -^^^^^^^^^^^^^ - .. autoclass:: SimpleAugment - -Location Manipulation Nodes ---------------------------- - -Crop -^^^^ - .. autoclass:: Crop - -Pad -^^^ - .. autoclass:: Pad - -.. _sec_api_random_location: - -RandomLocation -^^^^^^^^^^^^^^ - .. autoclass:: RandomLocation - -Reject -^^^^^^ - .. autoclass:: Reject - -SpecifiedLocation -^^^^^^^^^^^^^^^^^ - .. autoclass:: SpecifiedLocation - -.. _sec_api_array_manipulation_nodes: - -Array Manipulation Nodes ------------------------- - -Squeeze -^^^^^^^ - .. autoclass:: Squeeze - -Unsqueeze -^^^^^^^^^ - .. autoclass:: Unsqueeze - -.. _sec_api_image_processing_nodes: - -Image Processing Nodes ----------------------- - -DownSample -^^^^^^^^^^ - .. autoclass:: DownSample - -UpSample -^^^^^^^^ - .. autoclass:: UpSample - -IntensityScaleShift -^^^^^^^^^^^^^^^^^^^ - .. autoclass:: IntensityScaleShift - -Normalize -^^^^^^^^^ - .. autoclass:: Normalize - -Label Manipulation Nodes ------------------------- - -AddAffinities -^^^^^^^^^^^^^ - .. autoclass:: AddAffinities - -BalanceLabels -^^^^^^^^^^^^^ - .. autoclass:: BalanceLabels - -ExcludeLabels -^^^^^^^^^^^^^ - .. autoclass:: ExcludeLabels - -GrowBoundary -^^^^^^^^^^^^ - .. autoclass:: GrowBoundary - -RenumberConnectedComponents -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - .. autoclass:: RenumberConnectedComponents - -Point Processing Nodes ----------------------- - -RasterizeGraph -^^^^^^^^^^^^^^ - .. autoclass:: RasterizeGraph - .. autoclass:: RasterizationSettings - -Provider Combination Nodes --------------------------- - -MergeProvider -^^^^^^^^^^^^^ - .. autoclass:: MergeProvider - -RandomProvider -^^^^^^^^^^^^^^ - .. autoclass:: RandomProvider - -.. _sec_api_training_and_prediction_nodes: - -Training and Prediction Nodes ------------------------------ - -Stack -^^^^^ - .. autoclass:: Stack - - .. automodule:: gunpowder.torch - -torch.Train -^^^^^^^^^^^ - .. autoclass:: Train - -torch.Predict -^^^^^^^^^^^^^ - .. autoclass:: Predict - - - .. automodule:: gunpowder.tensorflow - -tensorflow.Train -^^^^^^^^^^^^^^^^ - .. autoclass:: Train - -tensorflow.Predict -^^^^^^^^^^^^^^^^^^ - .. autoclass:: Predict - - -.. _sec_api_output_nodes: - -Output Nodes ------------- - -.. automodule:: gunpowder - -Hdf5Write -^^^^^^^^^ - .. autoclass:: Hdf5Write - -ZarrWrite -^^^^^^^^^ - .. autoclass:: ZarrWrite - -.. _sec_api_snapshot: - -Snapshot -^^^^^^^^ - .. autoclass:: Snapshot - -.. _sec_api_performance_nodes: - -Performance Nodes ------------------ - -.. _sec_api_precache: - -PreCache -^^^^^^^^ - .. autoclass:: PreCache - -.. _sec_api_profiling: - -PrintProfilingStats -^^^^^^^^^^^^^^^^^^^ - .. autoclass:: PrintProfilingStats - -Iterative Processing Nodes --------------------------- - -Scan -^^^^ - .. autoclass:: Scan - -DaisyRequestBlocks -^^^^^^^^^^^^^^^^^^ - .. autoclass:: DaisyRequestBlocks diff --git a/docs/_sources/custom_providers.rst.txt b/docs/_sources/custom_providers.rst.txt deleted file mode 100644 index 1d9f9d05..00000000 --- a/docs/_sources/custom_providers.rst.txt +++ /dev/null @@ -1,32 +0,0 @@ -.. _sec_custom_providers: - -Writing Custom Batch Providers -============================== - -The simplest batch provider is a :class:`BatchFilter`, -which has exactly one upstream provider. To create a new one, subclass it and -override :meth:`prepare` and/or -:meth:`process`: - -.. code-block:: python - - class ExampleFilter(BatchFilter): - - def prepare(self, request): - pass - - def process(self, batch, request): - pass - -``prepare`` and ``process`` will be called in an alternating fashion. -``prepare`` is called first, when a ``BatchRequest`` is passed upstream through -the filter. Your filter is free to change the request in any way it needs to, -for example, by increasing the requested sizes. After ``prepare``, ``process`` -will be called with a batch going downstream, which is the upstream's response -to the request you modified in ``prepare``. In ``process``, your filter should -make all necessary changes to the batch and ensure it meets the original -downstream request earlier communicated to ``prepare`` (given as ``request`` -parameter in ``process`` for convenience). - -For an example of a batch filter changing both the spec going upstream and the -batch going downstream, see :class:`ElasticAugment`. diff --git a/docs/_sources/example_boundaries.rst.txt b/docs/_sources/example_boundaries.rst.txt deleted file mode 100644 index 2c9dae89..00000000 --- a/docs/_sources/example_boundaries.rst.txt +++ /dev/null @@ -1,399 +0,0 @@ -.. _sec_tutorial: - -Example: Boundary Prediction for Instance Segmentation -====================================================== - -(written by Sherry Ding) - -.. automodule:: gunpowder - :noindex: - -This is a tutorial about how to use ``gunpowder`` to assemble pipelines to train and test a neural network. As an -example, here we do neuron segmentation on the `cremi dataset `_ using a *3D U-Net*. To segment -neurons, we predict inter-voxel affinities from volumes of raw data. A ``gunpowder`` processing pipeline consists -of nodes that can be chained together using **+**. The major nodes of our training pipeline in this example includes -reading in sources, data augmentation, processing the labels, classifier training, and batch saving. Now we'll describe -the `code `_ in parts. - -Before we start, packages *malis* and *tensorflow* need to be installed for this example. - -.. code-block:: bash - - sudo apt-get install libboost-all-dev gcc # necessary for package malis (example for Ubuntu) - pip install malis - conda install tensorflow-gpu - - -Create a network to train with ------------------------------- - -Before assembling a pipeline and training on the data, it is required to build the neural network first, as it will be -called in the pipeline to train with. In this example, we build a *3D U-Net* with *tensorflow* as our neural network, and -store it in a *meta* file with its configuration in a *json* file for calling in the pipeline. The following script creates -a network for training and a larger network for faster prediction/testing. - -.. code-block:: bash - - python mknet.py - - -Assemble the training pipeline ------------------------------- - -Now we can assemble the training pipeline using ``gunpowder``. - -.. code-block:: python - - from __future__ import print_function - import gunpowder as gp - import json - import math - import logging - - logging.basicConfig(level=logging.INFO) - -First of all, we have to create :class:`ArrayKeys` for all arrays that the pipeline will use, i.e., give names to -our :class:`Arrays` for later requests or access. We create :class:`ArrayKeys` for raw intensities, ground -truth labels with unique IDs, ground truth affinities, weight to use to balance the loss, predicted affinities, and gredient -of the loss with regard to the predicted affinities. - -.. code-block:: python - - # raw intensities - raw = gp.ArrayKey('RAW') - - # objects labeled with unique IDs - gt_labels = gp.ArrayKey('LABELS') - - # array of per-voxel affinities to direct neighbors - gt_affs= gp.ArrayKey('AFFINITIES') - - # weights to use to balance the loss - loss_weights = gp.ArrayKey('LOSS_WEIGHTS') - - # the predicted affinities - pred_affs = gp.ArrayKey('PRED_AFFS') - - # the gredient of the loss wrt to the predicted affinities - pred_affs_gradients = gp.ArrayKey('PRED_AFFS_GRADIENTS') - -Next, we load the *3D U-Net* that we built and saved for training, and use its configurations to set the input and output size. - -.. code-block:: python - - with open('train_net_config.json', 'r') as f: - net_config = json.load(f) - - # get the input and output size in world units (nm, in this case) - voxel_size = gp.Coordinate((40, 4, 4)) - input_size = gp.Coordinate(net_config['input_shape'])*voxel_size - output_size = gp.Coordinate(net_config['output_shape'])*voxel_size - -We use :class:`BatchRequest` to formulate the request for what a batch should contain. For training, a batch -should contain raw data, ground truth affinities, and loss weights. In this example, we also request a batch for snapshot. -:class:`Snapshot` saves a passing batch in an *hdf* file for inspection. - -.. code-block:: python - - # formulate the request for what a batch should (at least) contain - request = gp.BatchRequest() - request.add(raw, input_size) - request.add(gt_affs, output_size) - request.add(loss_weights, output_size) - - # when we make a snapshot for inspection (see below), we also want to - # request the predicted affinities and gradients of the loss wrt the - # affinities - snapshot_request = gp.BatchRequest() - snapshot_request[pred_affs] = request[gt_affs] - snapshot_request[pred_affs_gradients] = request[gt_affs] - -Now we are going to assemble the training pipeline. As mentioned before, a ``gunpowder`` pipeline consists of nodes that are -chained using **+**. In this example, the first node deals with the sources. - -.. code-block:: python - - pipeline = ( - - # a tuple of sources, one for each sample (A, B, and C) provided by the CREMI challenge - tuple( - - # read batches from the HDF5 file - gp.Hdf5Source( - 'sample_'+s+'_padded_20160501.hdf', - datasets = { - raw: 'volumes/raw', - gt_labels: 'volumes/labels/neuron_ids' - } - ) + - - # convert raw to float in [0, 1] - gp.Normalize(raw) + - - # chose a random location for each requested batch - gp.RandomLocation() - - for s in ['A', 'B', 'C'] - ) + - -Here, :class:`Hdf5Source` provides arrays from samples that are in HDF5 format. :class:`Normalize` -normalizes values of the array to be floats between 0 and 1. :class:`RandomLocation` chooses a random -loacation for each request batch. - -Next we choose a random source, and do data augmentation. TODO: random source. Data augmentation "increases" the amount -of training data by augmenting them via a number of random transformations. The augmentations we use here are elastic -augmentation, transpose and mirror augmentation, as well as scaling and shifting the intensity. - -.. code-block:: python - - # chose a random source (i.e., sample) from the above - gp.RandomProvider() + - - # elastically deform the batch - gp.ElasticAugment( - [4,40,40], - [0,2,2], - [0,math.pi/2.0], - prob_slip=0.05, - prob_shift=0.05, - max_misalign=25) + - - # apply transpose and mirror augmentations - gp.SimpleAugment(transpose_only=[1, 2]) + - - # scale and shift the intensity of the raw array - gp.IntensityAugment( - raw, - scale_min=0.9, - scale_max=1.1, - shift_min=-0.1, - shift_max=0.1, - z_section_wise=True) + - -We also need to process the ground truth labels and affinities, e.g., grow a boundary between labels, convert labels -into affinities, and balance samples. - -.. code-block:: python - - # grow a boundary between labels - gp.GrowBoundary( - gt_labels, - steps=3, - only_xy=True) + - - # convert labels into affinities between voxels - gp.AddAffinities( - [[-1, 0, 0], [0, -1, 0], [0, 0, -1]], - gt_labels, - gt_affs) + - - # create a weight array that balances positive and negative samples in - # the affinity array - gp.BalanceLabels( - gt_affs, - loss_weights) + - -In this example, as our batch requests are repeatly the same, we pre-cache batches. :class:`PreCache` -means that a set of workers is spawned to pre-cache the batches in parallel processes for serving subsequent -requests quickly. - -.. code-block:: python - - # pre-cache batches from the point upstream - gp.PreCache( - cache_size=10, - num_workers=5) + - -The next node performs one training iteration for each passing batch. - -.. code-block:: python - - # perform one training iteration for each passing batch (here we use - # the tensor names earlier stored in train_net.config) - gp.tensorflow.Train( - 'train_net', - net_config['optimizer'], - net_config['loss'], - inputs={ - net_config['raw']: raw, - net_config['gt_affs']: gt_affs, - net_config['loss_weights']: loss_weights - }, - outputs={ - net_config['pred_affs']: pred_affs - }, - gradients={ - net_config['pred_affs']: pred_affs_gradients - }, - save_every=1) + - -We save the passing batch using :class:`Snapshot` and show a summary of time consuming. - -.. code-block:: python - - # save the passing batch as an HDF5 file for inspection - gp.Snapshot( - { - raw: '/volumes/raw', - gt_labels: '/volumes/labels/neuron_ids', - gt_affs: '/volumes/labels/affs', - pred_affs: '/volumes/pred_affs', - pred_affs_gradients: '/volumes/pred_affs_gradients' - }, - output_dir='snapshots', - output_filename='batch_{iteration}.hdf', - every=100, - additional_request=snapshot_request, - compression_type='gzip') + - - # show a summary of time spend in each node every 10 iterations - gp.PrintProfilingStats(every=10) - ) - -The final thing we need to do is requesting batches for the pipeline. - -.. code-block:: python - - print("Training for", iterations, "iterations") - - with gp.build(pipeline): - for i in range(iterations): - pipeline.request_batch(request) - - print("Finished") - -Let's put all above codes into a function called *train*, with an input parameter *iterations*. One iteration means -training on one batch once. - -.. code-block:: python - - def train(iterations): - ... - -In this example, we repeatly request a batch and train on it for 200000 times. - -.. code-block:: python - - if __name__ == "__main__": - train(200000) - - -Assemble the testing pipeline ------------------------------ - -After trained the network, we also use ``gunpowder`` to assemble the testing pipeline. - -.. code-block:: python - - from __future__ import print_function - import gunpowder as gp - import json - -The first is still creating :class:`ArrayKeys` for all arrays. We create :class:`ArrayKeys` -for raw intensities of testing data and predicted affinities. - -.. code-block:: python - - # raw intensities - raw = gp.ArrayKey('RAW') - - # the predicted affinities - pred_affs = gp.ArrayKey('PRED_AFFS') - -Load the *3D U-Net* that we built and saved for testing, and use its configurations to set the input and output size. - -.. code-block:: python - - with open('test_net_config.json', 'r') as f: - net_config = json.load(f) - - # get the input and output size in world units (nm, in this case) - voxel_size = gp.Coordinate((40, 4, 4)) - input_size = gp.Coordinate(net_config['input_shape'])*voxel_size - output_size = gp.Coordinate(net_config['output_shape'])*voxel_size - context = input_size - output_size - -We formulate the request for what a batch should contain. For testing, a batch should contain raw data and predicted -affinities. - -.. code-block:: python - - # formulate the request for what a batch should contain - request = gp.BatchRequest() - request.add(raw, input_size) - request.add(pred_affs, output_size) - -Next is to assemble the testing pipeline. The pipeline for testing/prediction is much simpler. It should at least -include a source node and a prediction node. - -.. code-block:: python - - source = gp.Hdf5Source( - 'sample_A_padded_20160501.hdf', - datasets = { - raw: 'volumes/raw' - }) - - # get the ROI provided for raw (we need it later to calculate the ROI in - # which we can make predictions) - with gp.build(source): - raw_roi = source.spec[raw].roi - - pipeline = ( - - # read from HDF5 file - source + - - # convert raw to float in [0, 1] - gp.Normalize(raw) + - - # perform one training iteration for each passing batch (here we use - # the tensor names earlier stored in train_net.config) - gp.tensorflow.Predict( - graph='test_net.meta', - checkpoint='train_net_checkpoint_%d'%iteration, - inputs={ - net_config['raw']: raw - }, - outputs={ - net_config['pred_affs']: pred_affs - }, - array_specs={ - pred_affs: gp.ArraySpec(roi=raw_roi.grow(-context, -context)) - }) + - -We also contain a :class:`Hdf5Write` node to store all passing batches, and a node showing a summary -of time consuming. - -.. code-block:: python - - # store all passing batches in the same HDF5 file - gp.Hdf5Write( - { - raw: '/volumes/raw', - pred_affs: '/volumes/pred_affs', - }, - output_filename='predictions_sample_A.hdf', - compression_type='gzip' - ) + - - # show a summary of time spend in each node every 10 iterations - gp.PrintProfilingStats(every=10) + - -Last :class:`Scan` node is used to iteratively request batches over the whole dataset in a scanning fashion - -.. code-block:: python - - # iterate over the whole dataset in a scanning fashion, emitting - # requests that match the size of the network - gp.Scan(reference=request) - ) - -Finally, we request an empty batch from :class:`Scan` to trigger scanning of the dataset. - -.. code-block:: python - - with gp.build(pipeline): - # request an empty batch from Scan to trigger scanning of the dataset - # without keeping the complete dataset in memory - pipeline.request_batch(gp.BatchRequest()) diff --git a/docs/_sources/first_steps.rst.txt b/docs/_sources/first_steps.rst.txt deleted file mode 100644 index e53dc2b0..00000000 --- a/docs/_sources/first_steps.rst.txt +++ /dev/null @@ -1,127 +0,0 @@ -.. _sec_first_steps: - -First steps -=========== - -.. automodule:: gunpowder - -Declaring arrays ----------------- - -Before you start assembling a training of prediction pipeline, you have to -create :class:`ArrayKeys` for all arrays your pipeline will use. -These keys are used later to formulate a request for an array or to access the -actual array associated with that key. - -In the example here, we assume we have a raw dataset, together with -ground-truth labels and a mask which lets us know where ground-truth is -available. - -.. code-block:: python - - import gunpowder as gp - - raw = gp.ArrayKey('RAW') - gt = gp.ArrayKey('GT') - gt_mask = gp.ArrayKey('MASK') - - -Creating a source ------------------ - -In ``gunpowder``, you assemble a training pipeline as a directed acyclic -graph (DAG) of :class:`BatchProvider`. The leaves of -your DAG are called sources, i.e., batch providers with no inputs: - -.. code-block:: python - - source = - gp.Hdf5Source( - 'example.hdf', - { - raw: 'volumes/raw', - gt: 'volumes/labels/neuron_ids', - gt_mask_dataset: 'volumes/labels/mask' - } - ) - -Chaining batch providers ------------------------- - -Every batch provider can be asked for a batch via a :class:`BatchRequest` -(e.g., shape, offset, which kind of volumes to provide) to provide a -:class:`Batch`. Starting from one or multiple sources, you can chain batch -providers to build a DAG. When a non-source batch provider is asked for a -batch, it passes the request on *upstream* (i.e., towards a source) to receive -a batch, possibly modifies it, and passes the batch on *downstream*. - -As an example, this scheme allows the modelling of on-the-fly data augmentation -as a batch provider: - -.. code-block:: python - - augment = - gp.ElasticAugment( - control_point_spacing=[4, 40, 40], - jitter_sigma=[0, 2, 2], - rotation_interval=[0, math.pi/2.0]) - -When :class:`ElasticAugment` is asked for a batch via a request, the -request is automatically changed to request an upstream batch large enough to -perform the elastic augmentation seamlessly. - -Another example is the random selection of locations inside a source: - -.. code-block:: python - - random = - gp.RandomLocation() - -:class:`RandomLocation` does only modify the request (by changing the offset). - -Training --------- - -:class:`Training` itself is modelled as a batch provider. It -takes a batch and performs one training iteration: - -.. code-block:: python - - train = - gp.tensorflow.Train(...) - -Putting it together, a very simple pipeline for training 1000 iterations would -be - -.. code-block:: python - - pipeline = source + random + augment + train - - request = gp.BatchRequest() - request.add(raw, (84, 268, 268)) - request.add(gt, (56, 56, 56)) - request.add(gt_mask, (56, 56, 56)) - - with gp.build(pipeline) as p: - for i in range(1000): - p.request_batch(request) - -Note that we use a :class:`BatchRequest` object to communicate -downstream the requirements for a batch. In the example, we are interested in -batches of certain sizes (fitting the network we want to train) with raw data, -ground-truth labels, and a mask. - -Going Further -------------- - -``gunpowder`` provides much more nodes to chain together, including a -:ref:`pre-cache` node for easy parallel fetching of batches, -several :ref:`augmentation nodes`, and nodes for -:ref:`profiling` and :ref:`inspection`. -For a complete list see the :ref:`API reference`. - -Continue reading :ref:`here` to learn how to write your -own ``gunpowder`` batch providers. - -Working examples (with many more batch providers) can be found in `the example -directory `_. diff --git a/docs/_sources/index.rst.txt b/docs/_sources/index.rst.txt deleted file mode 100644 index 03a035b2..00000000 --- a/docs/_sources/index.rst.txt +++ /dev/null @@ -1,42 +0,0 @@ -.. gunpowder documentation master file, created by - sphinx-quickstart on Fri Jun 30 12:59:21 2017. - -Gunpowder Documentation -======================= - -What is Gunpowder? -^^^^^^^^^^^^^^^^^^ - -Gunpowder is a library to facilitate machine learning on large, -multi-dimensional arrays. - -Gunpowder allows you to assemble a pipeline from :ref:`data -loading ` over -:ref:`pre-processing `, -:ref:`random batch -sampling `, :ref:`data -augmentation `, -:ref:`pre-caching `, -:ref:`training/prediction `, -to :ref:`storage of results ` -on arbitrarily large volumes of multi-dimensional images. Gunpowder is not -tied to a particular learning framework, and thus complements libraries like -`PyTorch `_ or `TensorFlow -`_. - -.. toctree:: - :maxdepth: 2 - - overview - install - tutorial_simple_pipeline - tutorial_batch_provider - api - example_boundaries - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/docs/_sources/install.rst.txt b/docs/_sources/install.rst.txt deleted file mode 100644 index 9206f209..00000000 --- a/docs/_sources/install.rst.txt +++ /dev/null @@ -1,13 +0,0 @@ -.. _sec_install: - -Installation -============ - -.. automodule:: gunpowder - :noindex: - -.. code-block:: bash - - pip install gunpowder - -That's all. diff --git a/docs/_sources/overview.rst.txt b/docs/_sources/overview.rst.txt deleted file mode 100644 index 277a6970..00000000 --- a/docs/_sources/overview.rst.txt +++ /dev/null @@ -1,32 +0,0 @@ -.. _sec_overview: - -Overview -======== - -Many data loading, training, and prediction tasks can be thought of as chaining -a sequence of operations. For example, to train a model to segment cells in a -large 2D+t movie, one might want to: - - 1. **Read the data** (the movie) and meta data (spatial resolution, data - type, ground-truth annotations). - 2. **Pick a sample** to train on from a random frame, at a random location. - 3. **Augment the sample** (rotate, mirror, flip, elastically deform, change - intensity, etc.). - 4. **Stack several samples** together into a batch. - 5. **Perform a training iteration** on the batch - -In ``gunpowder``, a sequence of operations like the example above is assembled -in the form of a **pipeline** of linked **nodes**. Once the pipeline is built, -**requests** can be made at the end of the pipeline (e.g, "give me a batch with -ten images of size ``(100, 100)``"). This request will then be passed upstream -from node to node. Nodes will update the request to ask for additional data -they need (e.g., a node performing a rotation of 45° will require an image of -size ``(142, 142)`` to satisfy the requested size ``(100, 100)``). Once the -request hits a source node, a **batch** with the requested data will be -created. This batch is then sent downstream the pipeline, once again visiting -each node along the path to perform the actual operation (e.g., rotate by 45° -and crop to ``(100, 100)``). - -The :ref:`Simple Pipeline` demonstrates how such -a pipeline in assembled in ``gunpowder`` (and also how to use a similar -pipeline for prediction). diff --git a/docs/_sources/pipeline.rst.txt b/docs/_sources/pipeline.rst.txt deleted file mode 100644 index 3d4a4810..00000000 --- a/docs/_sources/pipeline.rst.txt +++ /dev/null @@ -1,15 +0,0 @@ -.. _sec_pipeline: - -Pipelines -========= - -.. automodule:: gunpowder - -A ``gunpowder`` processing pipeline consists of nodes, which can be chained -together to form a directed acyclic graph. - -All nodes inherit from :class:`BatchProvider` and can be asked to provide a -batch by formulating a :class:`BatchRequest` and passing it to -:func:`BatchProvider.request_batch`. - -See :ref:`sec_custom_providers` for how to write your own node. diff --git a/docs/_sources/requests_batches.rst.txt b/docs/_sources/requests_batches.rst.txt deleted file mode 100644 index 5a1a706b..00000000 --- a/docs/_sources/requests_batches.rst.txt +++ /dev/null @@ -1,6 +0,0 @@ -.. _sec_requests_batches: - -Batch Requests and Batches -========================== - -TODO: describe up/down passing of requests/batches. diff --git a/docs/_sources/tutorial.rst.txt b/docs/_sources/tutorial.rst.txt deleted file mode 100644 index 8450ee8e..00000000 --- a/docs/_sources/tutorial.rst.txt +++ /dev/null @@ -1,398 +0,0 @@ -.. _sec_tutorial: - -Tutorial: boundary prediction for instance segmentation -======================================================= - -(written by Sherry Ding) - -.. automodule:: gunpowder - -This is a tutorial about how to use ``gunpowder`` to assemble pipelines to train and test a neural network. As an -example, here we do neuron segmentation on the `cremi dataset `_ using a *3D U-Net*. To segment -neurons, we predict inter-voxel affinities from volumes of raw data. A ``gunpowder`` processing pipeline consists -of nodes that can be chained together using **+**. The major nodes of our training pipeline in this example includes -reading in sources, data augmentation, processing the labels, classifier training, and batch saving. Now we'll describe -the `code `_ in parts. - -Before we start, packages *malis* and *tensorflow* need to be installed for this example. - -.. code-block:: bash - - sudo apt-get install libboost-all-dev gcc # necessary for package malis (example for Ubuntu) - pip install malis - conda install tensorflow-gpu - - -Create a network to train with ------------------------------- - -Before assembling a pipeline and training on the data, it is required to build the neural network first, as it will be -called in the pipeline to train with. In this example, we build a *3D U-Net* with *tensorflow* as our neural network, and -store it in a *meta* file with its configuration in a *json* file for calling in the pipeline. The following script creates -a network for training and a larger network for faster prediction/testing. - -.. code-block:: bash - - python mknet.py - - -Assemble the training pipeline ------------------------------- - -Now we can assemble the training pipeline using ``gunpowder``. - -.. code-block:: python - - from __future__ import print_function - import gunpowder as gp - import json - import math - import logging - - logging.basicConfig(level=logging.INFO) - -First of all, we have to create :class:`ArrayKeys` for all arrays that the pipeline will use, i.e., give names to -our :class:`Arrays` for later requests or access. We create :class:`ArrayKeys` for raw intensities, ground -truth labels with unique IDs, ground truth affinities, weight to use to balance the loss, predicted affinities, and gredient -of the loss with regard to the predicted affinities. - -.. code-block:: python - - # raw intensities - raw = gp.ArrayKey('RAW') - - # objects labeled with unique IDs - gt_labels = gp.ArrayKey('LABELS') - - # array of per-voxel affinities to direct neighbors - gt_affs= gp.ArrayKey('AFFINITIES') - - # weights to use to balance the loss - loss_weights = gp.ArrayKey('LOSS_WEIGHTS') - - # the predicted affinities - pred_affs = gp.ArrayKey('PRED_AFFS') - - # the gredient of the loss wrt to the predicted affinities - pred_affs_gradients = gp.ArrayKey('PRED_AFFS_GRADIENTS') - -Next, we load the *3D U-Net* that we built and saved for training, and use its configurations to set the input and output size. - -.. code-block:: python - - with open('train_net_config.json', 'r') as f: - net_config = json.load(f) - - # get the input and output size in world units (nm, in this case) - voxel_size = gp.Coordinate((40, 4, 4)) - input_size = gp.Coordinate(net_config['input_shape'])*voxel_size - output_size = gp.Coordinate(net_config['output_shape'])*voxel_size - -We use :class:`BatchRequest` to formulate the request for what a batch should contain. For training, a batch -should contain raw data, ground truth affinities, and loss weights. In this example, we also request a batch for snapshot. -:class:`Snapshot` saves a passing batch in an *hdf* file for inspection. - -.. code-block:: python - - # formulate the request for what a batch should (at least) contain - request = gp.BatchRequest() - request.add(raw, input_size) - request.add(gt_affs, output_size) - request.add(loss_weights, output_size) - - # when we make a snapshot for inspection (see below), we also want to - # request the predicted affinities and gradients of the loss wrt the - # affinities - snapshot_request = gp.BatchRequest() - snapshot_request[pred_affs] = request[gt_affs] - snapshot_request[pred_affs_gradients] = request[gt_affs] - -Now we are going to assemble the training pipeline. As mentioned before, a ``gunpowder`` pipeline consists of nodes that are -chained using **+**. In this example, the first node deals with the sources. - -.. code-block:: python - - pipeline = ( - - # a tuple of sources, one for each sample (A, B, and C) provided by the CREMI challenge - tuple( - - # read batches from the HDF5 file - gp.Hdf5Source( - 'sample_'+s+'_padded_20160501.hdf', - datasets = { - raw: 'volumes/raw', - gt_labels: 'volumes/labels/neuron_ids' - } - ) + - - # convert raw to float in [0, 1] - gp.Normalize(raw) + - - # chose a random location for each requested batch - gp.RandomLocation() - - for s in ['A', 'B', 'C'] - ) + - -Here, :class:`Hdf5Source` provides arrays from samples that are in HDF5 format. :class:`Normalize` -normalizes values of the array to be floats between 0 and 1. :class:`RandomLocation` chooses a random -loacation for each request batch. - -Next we choose a random source, and do data augmentation. TODO: random source. Data augmentation "increases" the amount -of training data by augmenting them via a number of random transformations. The augmentations we use here are elastic -augmentation, transpose and mirror augmentation, as well as scaling and shifting the intensity. - -.. code-block:: python - - # chose a random source (i.e., sample) from the above - gp.RandomProvider() + - - # elastically deform the batch - gp.ElasticAugment( - [4,40,40], - [0,2,2], - [0,math.pi/2.0], - prob_slip=0.05, - prob_shift=0.05, - max_misalign=25) + - - # apply transpose and mirror augmentations - gp.SimpleAugment(transpose_only=[1, 2]) + - - # scale and shift the intensity of the raw array - gp.IntensityAugment( - raw, - scale_min=0.9, - scale_max=1.1, - shift_min=-0.1, - shift_max=0.1, - z_section_wise=True) + - -We also need to process the ground truth labels and affinities, e.g., grow a boundary between labels, convert labels -into affinities, and balance samples. - -.. code-block:: python - - # grow a boundary between labels - gp.GrowBoundary( - gt_labels, - steps=3, - only_xy=True) + - - # convert labels into affinities between voxels - gp.AddAffinities( - [[-1, 0, 0], [0, -1, 0], [0, 0, -1]], - gt_labels, - gt_affs) + - - # create a weight array that balances positive and negative samples in - # the affinity array - gp.BalanceLabels( - gt_affs, - loss_weights) + - -In this example, as our batch requests are repeatly the same, we pre-cache batches. :class:`PreCache` -means that a set of workers is spawned to pre-cache the batches in parallel processes for serving subsequent -requests quickly. - -.. code-block:: python - - # pre-cache batches from the point upstream - gp.PreCache( - cache_size=10, - num_workers=5) + - -The next node performs one training iteration for each passing batch. - -.. code-block:: python - - # perform one training iteration for each passing batch (here we use - # the tensor names earlier stored in train_net.config) - gp.tensorflow.Train( - 'train_net', - net_config['optimizer'], - net_config['loss'], - inputs={ - net_config['raw']: raw, - net_config['gt_affs']: gt_affs, - net_config['loss_weights']: loss_weights - }, - outputs={ - net_config['pred_affs']: pred_affs - }, - gradients={ - net_config['pred_affs']: pred_affs_gradients - }, - save_every=1) + - -We save the passing batch using :class:`Snapshot` and show a summary of time consuming. - -.. code-block:: python - - # save the passing batch as an HDF5 file for inspection - gp.Snapshot( - { - raw: '/volumes/raw', - gt_labels: '/volumes/labels/neuron_ids', - gt_affs: '/volumes/labels/affs', - pred_affs: '/volumes/pred_affs', - pred_affs_gradients: '/volumes/pred_affs_gradients' - }, - output_dir='snapshots', - output_filename='batch_{iteration}.hdf', - every=100, - additional_request=snapshot_request, - compression_type='gzip') + - - # show a summary of time spend in each node every 10 iterations - gp.PrintProfilingStats(every=10) - ) - -The final thing we need to do is requesting batches for the pipeline. - -.. code-block:: python - - print("Training for", iterations, "iterations") - - with gp.build(pipeline): - for i in range(iterations): - pipeline.request_batch(request) - - print("Finished") - -Let's put all above codes into a function called *train*, with an input parameter *iterations*. One iteration means -training on one batch once. - -.. code-block:: python - - def train(iterations): - ... - -In this example, we repeatly request a batch and train on it for 200000 times. - -.. code-block:: python - - if __name__ == "__main__": - train(200000) - - -Assemble the testing pipeline ------------------------------ - -After trained the network, we also use ``gunpowder`` to assemble the testing pipeline. - -.. code-block:: python - - from __future__ import print_function - import gunpowder as gp - import json - -The first is still creating :class:`ArrayKeys` for all arrays. We create :class:`ArrayKeys` -for raw intensities of testing data and predicted affinities. - -.. code-block:: python - - # raw intensities - raw = gp.ArrayKey('RAW') - - # the predicted affinities - pred_affs = gp.ArrayKey('PRED_AFFS') - -Load the *3D U-Net* that we built and saved for testing, and use its configurations to set the input and output size. - -.. code-block:: python - - with open('test_net_config.json', 'r') as f: - net_config = json.load(f) - - # get the input and output size in world units (nm, in this case) - voxel_size = gp.Coordinate((40, 4, 4)) - input_size = gp.Coordinate(net_config['input_shape'])*voxel_size - output_size = gp.Coordinate(net_config['output_shape'])*voxel_size - context = input_size - output_size - -We formulate the request for what a batch should contain. For testing, a batch should contain raw data and predicted -affinities. - -.. code-block:: python - - # formulate the request for what a batch should contain - request = gp.BatchRequest() - request.add(raw, input_size) - request.add(pred_affs, output_size) - -Next is to assemble the testing pipeline. The pipeline for testing/prediction is much simpler. It should at least -include a source node and a prediction node. - -.. code-block:: python - - source = gp.Hdf5Source( - 'sample_A_padded_20160501.hdf', - datasets = { - raw: 'volumes/raw' - }) - - # get the ROI provided for raw (we need it later to calculate the ROI in - # which we can make predictions) - with gp.build(source): - raw_roi = source.spec[raw].roi - - pipeline = ( - - # read from HDF5 file - source + - - # convert raw to float in [0, 1] - gp.Normalize(raw) + - - # perform one training iteration for each passing batch (here we use - # the tensor names earlier stored in train_net.config) - gp.tensorflow.Predict( - graph='test_net.meta', - checkpoint='train_net_checkpoint_%d'%iteration, - inputs={ - net_config['raw']: raw - }, - outputs={ - net_config['pred_affs']: pred_affs - }, - array_specs={ - pred_affs: gp.ArraySpec(roi=raw_roi.grow(-context, -context)) - }) + - -We also contain a :class:`Hdf5Write` node to store all passing batches, and a node showing a summary -of time consuming. - -.. code-block:: python - - # store all passing batches in the same HDF5 file - gp.Hdf5Write( - { - raw: '/volumes/raw', - pred_affs: '/volumes/pred_affs', - }, - output_filename='predictions_sample_A.hdf', - compression_type='gzip' - ) + - - # show a summary of time spend in each node every 10 iterations - gp.PrintProfilingStats(every=10) + - -Last :class:`Scan` node is used to iteratively request batches over the whole dataset in a scanning fashion - -.. code-block:: python - - # iterate over the whole dataset in a scanning fashion, emitting - # requests that match the size of the network - gp.Scan(reference=request) - ) - -Finally, we request an empty batch from :class:`Scan` to trigger scanning of the dataset. - -.. code-block:: python - - with gp.build(pipeline): - # request an empty batch from Scan to trigger scanning of the dataset - # without keeping the complete dataset in memory - pipeline.request_batch(gp.BatchRequest()) diff --git a/docs/_sources/tutorial_batch_provider.rst.txt b/docs/_sources/tutorial_batch_provider.rst.txt deleted file mode 100644 index 5a395044..00000000 --- a/docs/_sources/tutorial_batch_provider.rst.txt +++ /dev/null @@ -1,568 +0,0 @@ -.. _sec_tutorial_batch_provider: - -.. automodule:: gunpowder - -Tutorial: Writing Your Own Node -------------------------------- - -This tutorial illustrates how to write your own ``gunpowder`` node. We will -cover the following topics: - -.. contents:: - :depth: 1 - :local: - -We will use the same example data used in :ref:`the previous -tutorial`. To follow along with the tutorial, -have a look at the following preliminaries: - -.. admonition:: Tutorial Preliminaries: Data Preparation and Helpers - :class: toggle - - To follow the example here, install those packages...:: - - pip install gunpowder - pip install zarr - pip install matplotlib - - ...and run the following code to set up the dataset and define a helper - function to display images: - - .. jupyter-execute:: - - import matplotlib.pyplot as plt - import numpy as np - import random - import zarr - from skimage import data - from skimage import filters - - # make sure we all see the same - np.random.seed(23619) - random.seed(23619) - - # open a sample image (channels first) - raw_data = data.astronaut().transpose(2, 0, 1) - - # create some dummy "ground-truth" to train on - gt_data = filters.gaussian(raw_data[0], sigma=3.0) > 0.75 - gt_data = gt_data[np.newaxis,:].astype(np.float32) - - # store image in zarr container - f = zarr.open('sample_data.zarr', 'w') - f['raw'] = raw_data - f['raw'].attrs['resolution'] = (1, 1) - f['ground_truth'] = gt_data - f['ground_truth'].attrs['resolution'] = (1, 1) - - # helper function to show image(s), channels first - def imshow(raw1, raw2=None): - rows = 1 - if raw2 is not None: - rows += 1 - cols = raw1.shape[0] if len(raw1.shape) > 3 else 1 - fig, axes = plt.subplots(rows, cols, figsize=(10, 4), sharex=True, sharey=True, squeeze=False) - if len(raw1.shape) == 3: - axes[0][0].imshow(raw1.transpose(1, 2, 0)) - else: - for i, im in enumerate(raw1): - axes[0][i].imshow(im.transpose(1, 2, 0)) - row = 1 - if raw2 is not None: - if len(raw2.shape) == 3: - axes[row][0].imshow(raw2.transpose(1, 2, 0)) - else: - for i, im in enumerate(raw2): - axes[row][i].imshow(im.transpose(1, 2, 0)) - plt.show() - -The data we are working with is shown below. It is stored in a ``zarr`` -container ``sample_data.zarr`` in dataset called ``raw``, which has one -attribute ``resolution = (1, 1)``: - -.. jupyter-execute:: - - imshow(zarr.open('sample_data.zarr')['raw'][:]) - -The basics: ``prepare`` and ``process`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -As we have already seen in :ref:`the previous -tutorial`, the concepts of **requests** and -**batches** are central to ``gunpowder``. As a reminder, requests are send -*upstream* in a pipeline to ask for data, and batches are sent *downstream*, -being modified by the nodes they pass through. - -This concept is illustrated by the following simple pipeline that reads image -data from a ``zarr`` source, picks a random location in it, and augments the -data (by random mirrors and transpose operations): - -.. jupyter-execute:: - - import gunpowder as gp - - raw = gp.ArrayKey('RAW') - - source = gp.ZarrSource( - 'sample_data.zarr', # the zarr container - {raw: 'raw'}, # which dataset to associate to the array key - {raw: gp.ArraySpec(interpolatable=True)} # meta-information - ) - random_location = gp.RandomLocation() - simple_augment = gp.SimpleAugment() - pipeline = source + random_location + simple_augment - - request = gp.BatchRequest() - request[raw] = gp.Roi((0, 0), (64, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -After building the pipeline, we request a batch by sending a specific -``request``. On its way up, this request gets modified by the nodes in the -pipeline it visits. When the request hits ``source``, this node creates the -actual batch and fills it with the requested data. The batch is then passed -down again through the pipeline to visit each node a second time. - -Most of the nodes in ``gunpowder`` are :class:`BatchFilters`, -which implement two methods: - -1. :func:`BatchFilter.prepare` is being called for a request that passes - through the node on its way up the pipeline. -2. :func:`BatchFilter.process` is being called for a batch that passes through - the node on its way down the pipeline. - -You can write your own node by sub-classing :class:`BatchFilter` and implement -either of the two methods. To see how that works, let's start with a simple -node that does nothing but to print the request and the batch that pass through -it: - -.. jupyter-execute:: - - class Print(gp.BatchFilter): - - def __init__(self, prefix): - self.prefix = prefix - - def prepare(self, request): - print(f"{self.prefix}\tRequest going upstream: {request}") - - def process(self, batch, request): - print(f"{self.prefix}\tBatch going downstream: {batch}") - -The argument to ``prepare`` is the current request being sent upstream. -``process``, on the other hand, is called with the batch. It also receives the -original request (the same one sent earlier to ``prepare``) as a second -argument for convenience. - -If we plug this new node into our pipeline, we see the following output: - -.. jupyter-execute:: - - pipeline = ( - source + - Print("A") + - random_location + - Print("B") + - simple_augment + - Print("C")) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -Our print node with the prefix ``C`` directly receives the request we sent. -After passing through ``simple_augment``, we can now see that the request was -modified: ``simple_augment`` apparently decided to perform a transpose on the -batch, and is consequently requesting raw data in a transposed ROI, as we can -see from the request that print node ``B`` received. Notably, the new request -is technically out of bounds (the y dimension has a negative offset). -``random_location``, however, shifts whatever request it receives to a random -location *inside* the area provided upstream. We see the effect of that in -print node ``A``, where the request has been modified to start at ``(177, -289)``. This is the request that is ultimately passed to ``source``, which -creates a batch with raw data from exactly this location. - -As the batch goes down the pipeline again, we see that each node undoes the -changes it made to the request. For example: ``random_location`` was asked to -provide data from ``[-32:96, 32:96]``. Although it modified the request with a -random shift to read from ``[177:305, 289:353]``, it still claims the data came -from ``[-32:96, 32:96]``. - -This is a deliberate design decision in ``gunpowder``: Every node provides a -batch with exactly the ROIs that were requested. It would be quite surprising -if a request to a ROI ``[-32:96, 32:96]`` was answered with data in a ROI -``[177:305, 289:353]``. Instead, we treat nodes like :class:`RandomLocation` or -:class:`SimpleAugment` as **views** into some virtual data. This data does not -have to be static, it can change between different requests on the discretion -of the node. -A good way to think about :class:`RandomLocation` is therefore that it provides -data in an infinitely large region. No matter where in this region you request -data, it will return a random sample of the data that is provided upstream, as -if this data just happened to be where you requested it. - -Changing an array in-place -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The following example shows how to perform a simple in-place operation on an -array. For that, we will create a node that inverts the intensity of the raw -data passing through it. We will use the ``invert()`` method from ``skimage`` -to do that: - -.. jupyter-execute:: - - from skimage import util - - class InvertIntensities(gp.BatchFilter): - - def __init__(self, array): - self.array = array - - def process(self, batch, request): - - data = batch[self.array].data - batch[self.array].data = util.invert(data) - - # ensure that raw is float in [0, 1] - normalize = gp.Normalize(raw) - - pipeline = ( - source + - normalize + - random_location + - InvertIntensities(raw)) - - # increase size of request to better see the result - request[raw] = gp.Roi((0, 0), (128, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -This example shows how to get access to the data of an array stored in a batch. -This is, in fact, not different from how we accessed the data of the batch -after it was returned from the pipeline. A batch acts as a dictionary, mapping -:class:`ArrayKeys` to :class:`Arrays`. Each :class:`Array`, in -turn, has a ``data`` attribute (the ``numpy`` array containing the actual data) -and a ``spec`` attribute (an instance of :class:`ArraySpec`, containing the -ROI, resolution, and other meta-information). - -.. note:: - - It is good practice to pass the array key of arrays that are supposed to be - modified by a node to its constructor and store it in the node. Here, we tell - ``InvertIntensities`` to only modify ``raw``. If our batch would contain more - than one array, this allows us to modify only the one we are interested in. - This does not apply to nodes that modify all arrays in a batch equally, like - :class:`RandomLocation` or :class:`ElasticAugment`. - -Since our simple ``InvertIntensities`` node does not need to change the request -(it does not require additional data or change the ROI of an array in the -passing through batch), we did not have to implement the ``prepare()`` method -in this case. - -Requesting additional data -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Sometimes, the output of a node depends on additional data. Consider, for -example, the case of simple Gaussian smoothing of the image. A naive in-place -implementation would look something like this: - -.. jupyter-execute:: - - from skimage import filters - - class NaiveSmooth(gp.BatchFilter): - - def __init__(self, array, sigma): - self.array = array - self.sigma = sigma - - def process(self, batch, request): - - data = batch[self.array].data - batch[self.array].data = filters.gaussian(data, sigma=self.sigma) - - pipeline = ( - source + - normalize + - NaiveSmooth(raw, sigma=5.0)) - - # request data in a specific location - request[raw] = gp.Roi((100, 100), (128, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -This does not look bad, but there is a subtle problem here: Gaussian smoothing -close to the boundary will have to fantasize some data that is not present -beyond the boundary. The ``skimage.filter.gaussian`` implementation will simply -repeat the last observed value at the boundary by default. We can see that this -leads to border artifacts if we make two requests of ROIs that are neighboring -and look at their concatenated output: - -.. jupyter-execute:: - - request_left = gp.BatchRequest() - request_left[raw] = gp.Roi((100, 100), (128, 128)) - request_right = gp.BatchRequest() - request_right[raw] = gp.Roi((100, 228), (128, 128)) - - with gp.build(pipeline): - batch_left = pipeline.request_batch(request_left) - batch_right = pipeline.request_batch(request_right) - - concatenated = np.concatenate([batch_left[raw].data, batch_right[raw].data], axis=2) - imshow(concatenated) - -In order to avoid this border artifact, we will need to have access to more -data than just requested by the ROI we received. In particular, the amount of -**context** we need is given by ``sigma`` and the ``truncate`` value used by -``skimage.filters.gaussian``. The product of the two defines the radius of the -kernel that ``skimage`` uses to smooth the image. For a pixel at the boundary, -this means that it needs at most ``sigma * truncate`` additional pixels beyond -the boundary to compute the correct result. - -The next version of our smooth node will therefore do the following: - -1. Compute the context needed in each direction. -2. Increase the requested ROI by this context, effectively asking for more data - upstream than what was requested from downstream. -3. Smooth the whole image it receives. -4. Crop the result back to the requested ROI. - -.. jupyter-execute:: - - class Smooth(gp.BatchFilter): - - def __init__(self, array, sigma): - self.array = array - self.sigma = sigma - self.truncate = 4 - - def prepare(self, request): - - # the requested ROI for array - roi = request[self.array].roi - - # 1. compute the context - context = gp.Coordinate((self.truncate,)*roi.dims) * self.sigma - - # 2. enlarge the requested ROI by the context - context_roi = roi.grow(context, context) - - # create a new request with our dependencies - deps = gp.BatchRequest() - deps[self.array] = context_roi - - # return the request - return deps - - def process(self, batch, request): - - # 3. smooth the whole array (including the context) - data = batch[self.array].data - batch[self.array].data = filters.gaussian( - data, - sigma=self.sigma, - truncate=self.truncate) - - # 4. crop the array back to the request - batch[self.array] = batch[self.array].crop(request[self.array].roi) - - pipeline = ( - source + - normalize + - Smooth(raw, sigma=5.0)) - - with gp.build(pipeline): - batch_left = pipeline.request_batch(request_left) - batch_right = pipeline.request_batch(request_right) - - concatenated = np.concatenate([batch_left[raw].data, batch_right[raw].data], axis=2) - imshow(concatenated) - -As expected, we used the ``prepare()`` method to enlarge the ROI of the -requested ``array``. For that, we first compute the ``context`` needed as a -:class:`Coordinate`. A :class:`Coordinate` in ``gunpowder`` is really just a -tuple of integers, with some operators attached such that it is convenient to -add, subtract, multiply, and divide coordinates. All of those operations are -dimension independent. In fact, the node we have just written would equally -work for requests with an arbitrary number of spacial dimensions. - -.. note:: - - :class:`Coordinate` to be a tuple of integers is a deliberate design - decision. Those coordinates do also underly :class:`Roi`, i.e., a ROI is also - always defined by an integer offset and size. - -Still within ``prepare()``, we use :func:`Roi.grow` to create a ROI that is -enlarged by ``context`` in both the negative and positive direction. Finally, -we create a new batch request with the enlarged ROI for ``array`` and return it -from ``prepare()``. This instructs ``gunpowder`` to merge this dependency with -whatever else might be contained in the current request and pass this request -upstream. - -When we receive the batch in ``process``, it does contain data for ``array`` in -the enlarged ROI. After applying the Gaussian filter to it, we crop it using -the convenience function :func:`Array.crop`. This function uses the -meta-information stored in an :class:`Array` to figure out where exactly to -crop the data (in particular, it uses the ``spec.roi`` and ``spec.voxel_size`` -attribute stored in the array). - -Finally, we will have a look at the sequence of requests made in our updated -pipeline, using the ``Print`` node we wrote at the beginning of this tutorial: - -.. jupyter-execute:: - - pipeline = ( - source + - normalize + - Print("before Smooth") + - Smooth(raw, sigma=5.0) + - Print("after Smooth")) - - request = gp.BatchRequest() - request[raw] = gp.Roi((100, 100), (128, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - -This confirms that ``Smooth`` did indeed increase the ROI for ``raw``. We asked -to smooth with a ``sigma`` of 5.0 and set the ``truncate`` value to 4.0, which -gives us a context of 20. Consequently, the request send upstream out of -``Smooth`` starts at 80 instead of 100, and the size of the ROI was grown by -40. - -Although we did request more data for the same array we produce in this -example, this is not required. In your ``prepare()`` method, you can ask for -any ROI of any array. This might be useful if your node produces outputs that -should be stored in a new array (leaving the original one as-is) or to combine -multiple arrays into one. - -Creating new arrays -^^^^^^^^^^^^^^^^^^^ - -If your node creates a new array (in contrast to modifying existing ones), one -additional step is required: We have to tell the downstream nodes about the new -array and where it is defined. This is done by overwriting the -:func:`BatchFilter.setup` function. - -For the example here, we will revisit the ``InvertIntensities`` node. This -time, however, we will create a new array with the inverted data instead of -replacing the content of the array. - -.. jupyter-execute:: - - class InvertIntensities(gp.BatchFilter): - - def __init__(self, in_array, out_array): - self.in_array = in_array - self.out_array = out_array - - def setup(self): - - # tell downstream nodes about the new array - self.provides( - self.out_array, - self.spec[self.in_array].copy()) - - def prepare(self, request): - - # to deliver inverted raw data, we need raw data in the same ROI - deps = gp.BatchRequest() - deps[self.in_array] = request[self.out_array].copy() - - return deps - - def process(self, batch, request): - - # get the data from in_array and invert it - data = util.invert(batch[self.in_array].data) - - # create the array spec for the new array - spec = batch[self.in_array].spec.copy() - spec.roi = request[self.out_array].roi.copy() - - # create a new batch to hold the new array - batch = gp.Batch() - - # create a new array - inverted = gp.Array(data, spec) - - # store it in the batch - batch[self.out_array] = inverted - - # return the new batch - return batch - - # declare a new array key for inverted raw - inverted_raw = gp.ArrayKey('INVERTED_RAW') - - pipeline = ( - source + - normalize + - random_location + - InvertIntensities(raw, inverted_raw)) - - request = gp.BatchRequest() - request[raw] = gp.Roi((0, 0), (128, 128)) - request[inverted_raw] = gp.Roi((0, 0), (128, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, batch[inverted_raw].data) - -The main change compared to the earlier ``InvertIntensities`` is that we now -announce a new array in the ``setup()`` function. This is done by calling -:func:`BatchFilter.provides`. We pass it the key of the array we provide, -together with a :class:`ArraySpec`. The :class:`ArraySpec` describes where the -new array is defined (via a ROI), what resolution it has, what the data type -is, and a few more bits of meta-information. In the case here, we simply create -a copy of the :class:`ArraySpec` of ``self.in_array``. We have access to the -spec of ``self.in_array`` through ``self.spec``, which acts as a dictionary -from array keys to array specs for each array that is provided upstream in the -pipeline. We can simply copy the spec here, since this is already the correct -spec for the output array. In more involved cases, it might be necessary to -change the spec accordingly. - -Another significant difference to the earlier implementation occurs in the -``process()`` method: Instead of changing the passing through batch in-place, -we now create a new batch, add the new array we produce to it, and return this -new batch. ``gunpowder`` will take the result of ``process`` and merge it with -the original batch. In fact, when we return ``None`` (as we did earlier), -``gunpowder`` implicitly assumed that we returned the complete, modified batch. - -This might seem complex at first, but there is a good reason for it: -The ``raw`` array we requested in ``InvertIntensities`` (to deliver -``inverted_raw``) might be different to what was requested independently -downstream. In other words, at some stages in the pipeline, there might be -different requests for the same array. ``gunpowder`` shields those conflicting -requests from you, i.e., the ``raw`` array you see in ``process()`` is exactly -the one you requested, independent of other requests that might have been made -to ``raw``. By requiring nodes to return a new batch with whatever they -produced or changed, we simply eliminate some guesswork for ``gunpowder``. - -This allows us to run the following pipeline. Here we request ``raw`` in one -ROI, and ``inverted_raw`` in another, partially overlapping, ROI. Upstream of -``InvertIntensities`` we now have two requests for ``raw``: One to satisfy the -original request for ``raw``, and the other one as a dependency of -``InvertIntensities``. - -.. jupyter-execute:: - - request = gp.BatchRequest() - request[raw] = gp.Roi((0, 0), (128, 128)) - request[inverted_raw] = gp.Roi((64, 64), (128, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, batch[inverted_raw].data) diff --git a/docs/_sources/tutorial_simple_pipeline.rst.txt b/docs/_sources/tutorial_simple_pipeline.rst.txt deleted file mode 100644 index 68354a82..00000000 --- a/docs/_sources/tutorial_simple_pipeline.rst.txt +++ /dev/null @@ -1,720 +0,0 @@ -.. _sec_tutorial_simple_pipeline: - -.. automodule:: gunpowder - -Tutorial: A Simple Pipeline ---------------------------- - -The following illustrates how a pipeline like the one above is built using -``gunpowder``. We will build the pipeline incrementally and see what effect -each change has. Therefore, this tutorial is best read in that order. -Nevertheless, feel free to jump ahead to any of the following topics we are -covering here: - -.. contents:: - :depth: 1 - :local: - - -To rerun the example given here yourself, have a look at the -following preliminaries (or simply head over to this tutorial's -`Colab notebook `_): - -.. admonition:: Tutorial Preliminaries: Data Preparation and Helpers - :class: toggle - - To follow the example here, install those packages:: - - pip install gunpowder - pip install zarr - pip install matplotlib - - .. jupyter-execute:: - - import matplotlib.pyplot as plt - import numpy as np - import random - import zarr - from skimage import data - from skimage import filters - - # make sure we all see the same - np.random.seed(19623) - random.seed(19623) - - # open a sample image (channels first) - raw_data = data.astronaut().transpose(2, 0, 1) - - # create some dummy "ground-truth" to train on - gt_data = filters.gaussian(raw_data[0], sigma=3.0) > 0.75 - gt_data = gt_data[np.newaxis,:].astype(np.float32) - - # store image in zarr container - f = zarr.open('sample_data.zarr', 'w') - f['raw'] = raw_data - f['raw'].attrs['resolution'] = (1, 1) - f['ground_truth'] = gt_data - f['ground_truth'].attrs['resolution'] = (1, 1) - - # helper function to show image(s), channels first - def imshow(raw, ground_truth=None, prediction=None): - rows = 1 - if ground_truth is not None: - rows += 1 - if prediction is not None: - rows += 1 - cols = raw.shape[0] if len(raw.shape) > 3 else 1 - fig, axes = plt.subplots(rows, cols, figsize=(10, 4), sharex=True, sharey=True, squeeze=False) - if len(raw.shape) == 3: - axes[0][0].imshow(raw.transpose(1, 2, 0)) - else: - for i, im in enumerate(raw): - axes[0][i].imshow(im.transpose(1, 2, 0)) - row = 1 - if ground_truth is not None: - if len(ground_truth.shape) == 3: - axes[row][0].imshow(ground_truth[0]) - else: - for i, gt in enumerate(ground_truth): - axes[row][i].imshow(gt[0]) - row += 1 - if prediction is not None: - if len(prediction.shape) == 3: - axes[row][0].imshow(prediction[0]) - else: - for i, gt in enumerate(prediction): - axes[row][i].imshow(gt[0]) - plt.show() - -The data we are working with is shown below. It is stored in a ``zarr`` -container ``sample_data.zarr`` in dataset called ``raw``, which has one -attribute ``resolution = (1, 1)``: - -.. jupyter-execute:: - - imshow(zarr.open('sample_data.zarr')['raw'][:]) - -.. note:: - - The ``resolution`` attribute in the zarr dataset will be read by - ``gunpowder``. ``gunpowder`` supports anisotropic resultions and even - datasets with different resolutions in the same pipeline. Here, it tells - ``gunpowder`` that this is a 2D dataset, with the remaining dimension to be - interpreted as channels. More on this later. - -.. _sub_minimal_pipeline: - -A minimal pipeline -^^^^^^^^^^^^^^^^^^ - -The first step for every pipeline is to declare the **arrays** that will be -used. For now, we will need only one array which we call ``raw``: - -.. jupyter-execute:: - - import gunpowder as gp - - # declare arrays to use in the pipeline - raw = gp.ArrayKey('RAW') - -Next we assemble the pipeline itself. To illustrate how ``gunpowder`` works, we -will do this step by step and look at the changes each step introduces. We -start with a "pipeline" consisting only of a data source. - -.. jupyter-execute:: - - # create "pipeline" consisting only of a data source - source = gp.ZarrSource( - 'sample_data.zarr', # the zarr container - {raw: 'raw'}, # which dataset to associate to the array key - {raw: gp.ArraySpec(interpolatable=True)} # meta-information - ) - pipeline = source - -The pipeline by itself does nothing until we request data from it. What exactly -is requested is specified by a :class:`BatchRequest`. The following shows how -to create a request for "raw" data, starting at ``(0, 0)`` with a size of -``(64, 64)``. - -.. jupyter-execute:: - - # formulate a request for "raw" - request = gp.BatchRequest() - request[raw] = gp.Roi((0, 0), (64, 64)) - -The request behaves like a dictionary, mapping each array key to a region of -interest (ROI), i.e., an offset and a size. - -It remains to **build** the pipeline and request a :class:`Batch`: - -.. jupyter-execute:: - - # build the pipeline... - with gp.build(pipeline): - - # ...and request a batch - batch = pipeline.request_batch(request) - - # show the content of the batch - print(f"batch returned: {batch}") - imshow(batch[raw].data) - -The returned batch contains a crop of the source image, located in the top left -corner. This is indeed exactly what we requested, as an inspection of our -request reveals: - -.. jupyter-execute:: - - print(request) - -As we can see, the request for ``RAW`` (the name we gave to our array key) is -for a ROI that begins at 0 and ends at 64 for each dimension, giving it a shape -of ``(64, 64)``. The :class:`ZarrSource` simply delivered on exactly this -request. - -.. admonition:: Further Example: Change Request Offset - :class: toggle - - To create a request for data in a specific area of the source, we simply - change the offset in the request :class:`Roi`: - - .. jupyter-execute:: - - request[raw] = gp.Roi((50, 150), (64, 64)) - # ^^^^^^^^^ - # changed offset - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - print(f"batch returned: {batch}") - imshow(batch[raw].data) - -Random samples -^^^^^^^^^^^^^^ - -In training pipelines, however, it might be useful to randomly select a -location to crop data from. Doing this manually by changing the offset of the -ROI in the request we send for every iteration would be cumbersome. It would -also require that we know the size of the data in the source. - -Instead, ``gunpowder`` provides a node :class:`RandomLocation` that does that -for us, we simply have to add it to our pipeline: - -.. jupyter-execute:: - - # add a RandomLocation node to the pipeline to randomly select a sample - - random_location = gp.RandomLocation() - pipeline = source + random_location - - print(pipeline) - -When we now issue the same request, it will first be shifted by -``random_location`` to a random location *within* the provided data. - -.. jupyter-execute:: - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -This example illustrates two important concepts in ``gunpowder``: - -1. Request can (and will be) changed as they are passed upstream through the - pipeline. In this example, :class:`RandomLocation` changes the offset of the - request for us, such that we get data from a random location. -2. ``gunpowder`` nodes know what kind of data is provided upstream, and what - its extents are. Here, :class:`RandomLocation` uses this information to find - out where it can safely shift the request to. - -Geometric augmentation -^^^^^^^^^^^^^^^^^^^^^^ - -``gunpowder`` provides many more nodes to be added to a pipeline, most of them -tailored towards training pipelines. The following example shows how to add -simple random *mirror* and *transpose* augmentations: - -.. jupyter-execute:: - - simple_augment = gp.SimpleAugment() - pipeline = source + random_location + simple_augment - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -The :class:`SimpleAugment` node will (by default) randomly mirror and/or -transpose batches passing through it. Notably, the transpose operation is -transparent, i.e., if we were to request data in a non-square ROI, we will -still get the size we asked for, transposed or not: - -.. jupyter-execute:: - - request[raw] = gp.Roi((0, 0), (64, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -Simple augmentations like this are complemented by random rotations and elastic -deformations, which are provided by the :class:`ElasticAugment` node: - -.. jupyter-execute:: - - import math - - elastic_augment = gp.ElasticAugment( - control_point_spacing=(16, 16), - jitter_sigma=(4.0, 4.0), - rotation_interval=(0, math.pi/2)) - pipeline = source + random_location + simple_augment + elastic_augment - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -Intensity augmentation -^^^^^^^^^^^^^^^^^^^^^^ - -Intensity values can be modified and random noise added in a similar fashion: - -.. jupyter-execute:: - - normalize = gp.Normalize(raw) - intensity_augment = gp.IntensityAugment( - raw, - scale_min=0.8, - scale_max=1.2, - shift_min=-0.2, - shift_max=0.2) - noise_augment = gp.NoiseAugment(raw) - - pipeline = ( - source + - normalize + - random_location + - simple_augment + - elastic_augment + - intensity_augment + - noise_augment) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -We introduced two new concepts in this snippet: - -First, we added a :class:`Normalize` node for ``raw``. This node ensures that -the data type of the given array is ``np.float`` from there on through the -pipeline. We have so far been agnostic about the exact datatype of ``raw`` (it -was ``uint8``, by the way). However, in order to shift intensities and to add -random noise, it is helpful to ensure we are dealing with float values between -0 and 1. The normalization applied by :class:`Normalize` is data independent, -it is based on the data type of the source (or, optionally, on a user-specified -scaling factor). - -Second, we introduced nodes that take array keys as arguments -(:class:`Normalize`, :class:`IntensityAugment`, and :class:`NoiseAugment`). -Those nodes limit their operation to the given keys, which is useful if our -batch also contains other arrays (like a ground-truth segmentation) that we do -not wish to modify. - -Creating batches with multiple samples -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -So far we have seen how to request a single sample in a "batch". Normally, -however, batches consist of several samples drawn independently. This can be -done using the :class:`Stack` node: - -.. jupyter-execute:: - - stack = gp.Stack(5) - pipeline = ( - source + - normalize + - random_location + - simple_augment + - elastic_augment + - intensity_augment + - noise_augment + - stack) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data) - -Requesting multiple arrays -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -To train a model on data, we need a training signal as well. This signal can -come, for example, in the form of a binary segmentation stored alongside the -raw image data. For this tutorial, we will assume that such a binary -segmentation exists and is stored in the same ``zarr`` container in a dataset -called ``ground_truth``. At the beginning of this tutorial, we created a dummy -segmentation to work with: - -.. jupyter-execute:: - - imshow( - zarr.open('sample_data.zarr')['raw'][:], - zarr.open('sample_data.zarr')['ground_truth'][:]) - -With a slight modification to the source node and our request, we can now -simultaneously request raw data and a segmentation: - -.. jupyter-execute:: - - gt = gp.ArrayKey('GROUND_TRUTH') - - source = gp.ZarrSource( - 'sample_data.zarr', - { - raw: 'raw', - gt: 'ground_truth' - }, - { - raw: gp.ArraySpec(interpolatable=True), - gt: gp.ArraySpec(interpolatable=False) - }) - - request[gt] = gp.Roi((0, 0), (64, 128)) - - pipeline = ( - source + - normalize + - random_location + - simple_augment + - elastic_augment + - intensity_augment + - noise_augment + - stack) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, batch[gt].data) - -As we can see, our batch does now contain aligned data for both ``raw`` and -``gt``. Notably, both arrays have been transformed in the same way as they were -passed through the pipeline, except for the intensity augmentation parts that -were exclusive to ``raw``. This works even if the requested ROIs for ``raw`` -and ``gt`` are not identical. Here we see the effect of requesting a -ground-truth ROI that is offset relative to the raw ROI: - -.. jupyter-execute:: - - # request an offset ROI for ground-truth - odd_request = request.copy() - odd_request[gt] = gp.Roi((20, 20), (64, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(odd_request) - - imshow(batch[raw].data, batch[gt].data) - -This highlights another feature of ``gunpowder``: Requests can contain ROIs -with different offsets and sizes. Internally, ``gunpowder`` will figure out -what areas in the source have to be read to satisfy those heterogeneous -requests, and will only read as much as needed to satisfy the request. This is -useful in many applications where ground-truth is not needed for the whole -input image (e.g., because of the use of valid convolutions in neural networks -and the correspondingly smaller network output). - -.. admonition:: Further Example: Multiple Sources - :class: toggle - - For now we assumed that both arrays we are interested in (``raw`` and ``gt``) - are read from the same source, i.e., they are stored in the same ``zarr`` - container in this example. This might not always be the case. ``gunpowder`` - allows you to have multiple sources for different arrays and merge them - together into one. The following example shows this functionality: - - .. jupyter-execute:: - - source_raw = gp.ZarrSource( - 'sample_data.zarr', - {raw: 'raw'}, - {raw: gp.ArraySpec(interpolatable=True)} - ) - source_gt = gp.ZarrSource( - 'sample_data.zarr', - {gt: 'ground_truth'}, - {gt: gp.ArraySpec(interpolatable=False)} - ) - combined_source = (source_raw, source_gt) + gp.MergeProvider() - - pipeline = ( - combined_source + - normalize + - random_location + - simple_augment + - elastic_augment + - intensity_augment + - noise_augment + - stack) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, batch[gt].data) - -Training a network -^^^^^^^^^^^^^^^^^^ - -We have seen so far how ``gunpowder`` can be used to generate training batches. -In the following we will see how to train a neural network directly in this -pipeline. For the example, we will train a 2D U-Net (``model``) on the binary -ground-truth using a binary cross-entropy loss (``loss``). We will use `PyTorch -`_, but the same can be done with a `TensorFlow -`_ model as well. - -.. admonition:: Training Preliminaries: Create Model, Loss, and Optimizer - :class: toggle - - We will use the U-Net implemention from `funlib.learn.torch - `_, but any PyTorch model can - be used. To follow the example, install those packages:: - - pip install git+https://github.com/funkelab/funlib.learn.torch@fe60a7d9a375d64208266f96a739ab01f62a0c78 - pip install torch - - Here, we create a very simple 2D U-Net mapping from three channels (RGB of - the raw data) to one channel (the segmentation output). The U-Net has two - downsampling modules, downsampling isotropically with a factor of two. We use - 'same' padding here, meaning that the output size of the U-Net will be the - same as the input size. The number of feature maps will be four in the - top-most level of the U-Net, and increase with a factor of two for each of - the two following levels. The output of the U-Net is further passed through a - sigmoid function to ensure values are between 0 and 1. - - .. jupyter-execute:: - - import torch - from funlib.learn.torch.models import UNet, ConvPass - - # make sure we all see the same - torch.manual_seed(18) - - unet = UNet( - in_channels=3, - num_fmaps=4, - fmap_inc_factor=2, - downsample_factors=[[2, 2], [2, 2]], - kernel_size_down=[[[3, 3], [3, 3]]]*3, - kernel_size_up=[[[3, 3], [3, 3]]]*2, - padding='same') - - model = torch.nn.Sequential( - unet, - ConvPass(4, 1, [(1, 1)], activation=None), - torch.nn.Sigmoid()) - - loss = torch.nn.BCELoss() - - optimizer = torch.optim.Adam(model.parameters()) - -Training itself is implemented in a ``gunpowder`` node, in this case -:class:`torch.Train`. The main benefit of using this node in a -``gunpowder`` pipeline (compared to just taking the batches we requested so far -and feeding them manually to the model) is that the output of the network -itself can be mapped to a ``gunpowder`` array, and subsequently be used in the -pipeline. In the following, we will create a new array key ``prediction`` to do -exactly that: - -.. jupyter-execute:: - - # create new array key for the network output - prediction = gp.ArrayKey('PREDICTION') - - # create a train node using our model, loss, and optimizer - train = gp.torch.Train( - model, - loss, - optimizer, - inputs = { - 'input': raw - }, - loss_inputs = { - 0: prediction, - 1: gt - }, - outputs = { - 0: prediction - }) - - pipeline = ( - source + - normalize + - random_location + - simple_augment + - elastic_augment + - intensity_augment + - noise_augment + - stack + - train) - - # add the prediction to the request - request[prediction] = gp.Roi((0, 0), (64, 128)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, batch[gt].data, batch[prediction].data) - -As we can see, our batch does now contain an array ``prediction``, which is the -output of the :class:`torch.Train` node. This illustrates another feature of -``gunpowder``: Arrays can be generated by any node, this functionality is not -limited to source nodes (and in fact, source nodes are in no way special, they -are simply ``gunpowder`` nodes that do not require an input and provide an -array). - -But the train node above did not just produce a prediction: Since we also told -it which loss and optimizer to use, and since we linked the output of our -network and the ground-truth to the loss via ``loss_inputs``, the train node -did also perform a training iteration for us. This becomes more evident if we -keep training for a few iterations: - -.. jupyter-execute:: - - with gp.build(pipeline): - for i in range(1000): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, batch[gt].data, batch[prediction].data) - -.. note:: - - The predictions are only included in the batch because we requested them here - to visualize them. To keep the example simple, we request the predictions in - every iteration. In a production setting, however, it is advisable to request - only what is needed for each iteration. This saves a potentially expensive - copy from GPU memory. - -Predicting on a whole image -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -``gunpowder`` and its pipeline concept can not just be used for training, but -also to perform the final predictions once training is finished. The following -example shows how to assemble a pipeline to take the model we just trained and -apply it on the whole image. The main difficulty in doing that is that the -model was trained for a particular input size. Consequently, the whole image -will have to be chunked into pieces of the correct size, and the network has to -be applied to each chunk in a scanning fashion, creating predictions one chunk -at a time. Those chunks then have to be reassembled into a prediction for the -whole image. This whole procedure is orchestrated by another ``gunpowder`` -node: :class:`Scan`. - -.. jupyter-execute:: - - # set model into evaluation mode - model.eval() - - predict = gp.torch.Predict( - model, - inputs = { - 'input': raw - }, - outputs = { - 0: prediction - }) - - stack = gp.Stack(1) - - # request matching the model input and output sizes - scan_request = gp.BatchRequest() - scan_request[raw] = gp.Roi((0, 0), (64, 128)) - scan_request[prediction] = gp.Roi((0, 0), (64, 128)) - - scan = gp.Scan(scan_request) - - pipeline = ( - source + - normalize + - stack + - predict + - scan) - - # request for raw and prediction for the whole image - request = gp.BatchRequest() - request[raw] = gp.Roi((0, 0), (512, 512)) - request[prediction] = gp.Roi((0, 0), (512, 512)) - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - imshow(batch[raw].data, None, batch[prediction].data) - -The main difference to the training pipeline used earlier is that there is no -longer a need for data augmentation. We also replaced the :class:`torch.Train` -node with its equivalent :class:`torch.Predict`. - -.. admonition:: Further Example: Prediction in Large nD Arrays - :class: toggle - - Here, we make a request to :class:`Scan` for the whole image and the - prediction. This is fine as long as both arrays are small enough to fit into - memory. However, ``gunpowder`` was designed to work with arbitrarily large - nD arrays. Therefore, :class:`Scan` accepts empty requests as well, which - will still result in small ``scan_request`` s being performed in a scanning - fashion over the whole input range--the only difference is that :class:`Scan` - does not keep the individual results and consequently that the batch returned - by :class:`Scan` will be empty. - - So how do we get access to the prediction then to store it, for example, in a - ``zarr`` container? The answer is to add a node **between** predict and scan, - through which every batch will pass before it is being discarded. The - :class:`ZarrWrite` node will, for instance, assemble a ``zarr`` container of - all the arrays passing through it. - - The following example illustrates that: - - .. jupyter-execute:: - - # prepare the zarr dataset to write to - f = zarr.open('sample_data.zarr') - ds = f.create_dataset('prediction', shape=(1, 1, 512, 512)) - ds.attrs['resolution'] = (1, 1) - ds.attrs['offset'] = (0, 0) - - # create a zarr write node to store the predictions - zarr_write = gp.ZarrWrite( - output_filename='sample_data.zarr', - dataset_names={ - prediction: 'prediction' - }) - - pipeline = ( - source + - normalize + - stack + - predict + - zarr_write + - scan) - - # request an empty batch from scan - request = gp.BatchRequest() - - with gp.build(pipeline): - batch = pipeline.request_batch(request) - - print(batch) - imshow( - zarr.open('sample_data.zarr')['raw'][:], - None, - zarr.open('sample_data.zarr')['prediction'][:]) - -What next? -^^^^^^^^^^ - -``gunpowder`` provides much more nodes to chain together, including a -:ref:`pre-cache` node for easy parallel fetching of batches, -several :ref:`augmentation nodes`, and nodes for -:ref:`profiling` and :ref:`inspection`. -For a complete list see the :ref:`API reference`. diff --git a/docs/_static/basic.css b/docs/_static/basic.css deleted file mode 100644 index 24a49f09..00000000 --- a/docs/_static/basic.css +++ /dev/null @@ -1,856 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -div.section::after { - display: block; - content: ''; - clear: left; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; - word-wrap: break-word; - overflow-wrap : break-word; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar #searchbox form.search { - overflow: hidden; -} - -div.sphinxsidebar #searchbox input[type="text"] { - float: left; - width: 80%; - padding: 0.25em; - box-sizing: border-box; -} - -div.sphinxsidebar #searchbox input[type="submit"] { - float: left; - width: 20%; - border-left: none; - padding: 0.25em; - box-sizing: border-box; -} - - -img { - border: 0; - max-width: 100%; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; - margin-left: auto; - margin-right: auto; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable ul { - margin-top: 0; - margin-bottom: 0; - list-style-type: none; -} - -table.indextable > tbody > tr > td > ul { - padding-left: 0em; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- domain module index --------------------------------------------------- */ - -table.modindextable td { - padding: 2px; - border-collapse: collapse; -} - -/* -- general body styles --------------------------------------------------- */ - -div.body { - min-width: 450px; - max-width: 800px; -} - -div.body p, div.body dd, div.body li, div.body blockquote { - -moz-hyphens: auto; - -ms-hyphens: auto; - -webkit-hyphens: auto; - hyphens: auto; -} - -a.headerlink { - visibility: hidden; -} - -a.brackets:before, -span.brackets > a:before{ - content: "["; -} - -a.brackets:after, -span.brackets > a:after { - content: "]"; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink, -caption:hover > a.headerlink, -p.caption:hover > a.headerlink, -div.code-block-caption:hover > a.headerlink { - visibility: visible; -} - -div.body p.caption { - text-align: inherit; -} - -div.body td { - text-align: left; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -img.align-left, .figure.align-left, object.align-left { - clear: left; - float: left; - margin-right: 1em; -} - -img.align-right, .figure.align-right, object.align-right { - clear: right; - float: right; - margin-left: 1em; -} - -img.align-center, .figure.align-center, object.align-center { - display: block; - margin-left: auto; - margin-right: auto; -} - -img.align-default, .figure.align-default { - display: block; - margin-left: auto; - margin-right: auto; -} - -.align-left { - text-align: left; -} - -.align-center { - text-align: center; -} - -.align-default { - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px; - background-color: #ffe; - width: 40%; - float: right; - clear: right; - overflow-x: auto; -} - -p.sidebar-title { - font-weight: bold; -} - -div.admonition, div.topic, blockquote { - clear: left; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.body p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- content of sidebars/topics/admonitions -------------------------------- */ - -div.sidebar > :last-child, -div.topic > :last-child, -div.admonition > :last-child { - margin-bottom: 0; -} - -div.sidebar::after, -div.topic::after, -div.admonition::after, -blockquote::after { - display: block; - content: ''; - clear: both; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -table.align-center { - margin-left: auto; - margin-right: auto; -} - -table.align-default { - margin-left: auto; - margin-right: auto; -} - -table caption span.caption-number { - font-style: italic; -} - -table caption span.caption-text { -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -th > :first-child, -td > :first-child { - margin-top: 0px; -} - -th > :last-child, -td > :last-child { - margin-bottom: 0px; -} - -/* -- figures --------------------------------------------------------------- */ - -div.figure { - margin: 0.5em; - padding: 0.5em; -} - -div.figure p.caption { - padding: 0.3em; -} - -div.figure p.caption span.caption-number { - font-style: italic; -} - -div.figure p.caption span.caption-text { -} - -/* -- field list styles ----------------------------------------------------- */ - -table.field-list td, table.field-list th { - border: 0 !important; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.field-name { - -moz-hyphens: manual; - -ms-hyphens: manual; - -webkit-hyphens: manual; - hyphens: manual; -} - -/* -- hlist styles ---------------------------------------------------------- */ - -table.hlist { - margin: 1em 0; -} - -table.hlist td { - vertical-align: top; -} - - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -:not(li) > ol > li:first-child > :first-child, -:not(li) > ul > li:first-child > :first-child { - margin-top: 0px; -} - -:not(li) > ol > li:last-child > :last-child, -:not(li) > ul > li:last-child > :last-child { - margin-bottom: 0px; -} - -ol.simple ol p, -ol.simple ul p, -ul.simple ol p, -ul.simple ul p { - margin-top: 0; -} - -ol.simple > li:not(:first-child) > p, -ul.simple > li:not(:first-child) > p { - margin-top: 0; -} - -ol.simple p, -ul.simple p { - margin-bottom: 0; -} - -dl.footnote > dt, -dl.citation > dt { - float: left; - margin-right: 0.5em; -} - -dl.footnote > dd, -dl.citation > dd { - margin-bottom: 0em; -} - -dl.footnote > dd:after, -dl.citation > dd:after { - content: ""; - clear: both; -} - -dl.field-list { - display: grid; - grid-template-columns: fit-content(30%) auto; -} - -dl.field-list > dt { - font-weight: bold; - word-break: break-word; - padding-left: 0.5em; - padding-right: 5px; -} - -dl.field-list > dt:after { - content: ":"; -} - -dl.field-list > dd { - padding-left: 0.5em; - margin-top: 0em; - margin-left: 0em; - margin-bottom: 0em; -} - -dl { - margin-bottom: 15px; -} - -dd > :first-child { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dl > dd:last-child, -dl > dd:last-child > :last-child { - margin-bottom: 0; -} - -dt:target, span.highlighted { - background-color: #fbe54e; -} - -rect.highlighted { - fill: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.optional { - font-size: 1.3em; -} - -.sig-paren { - font-size: larger; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa; -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -.classifier:before { - font-style: normal; - margin: 0.5em; - content: ":"; -} - -abbr, acronym { - border-bottom: dotted 1px; - cursor: help; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - overflow-y: hidden; /* fixes display issues on Chrome browsers */ -} - -pre, div[class*="highlight-"] { - clear: both; -} - -span.pre { - -moz-hyphens: none; - -ms-hyphens: none; - -webkit-hyphens: none; - hyphens: none; -} - -div[class*="highlight-"] { - margin: 1em 0; -} - -td.linenos pre { - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - display: block; -} - -table.highlighttable tbody { - display: block; -} - -table.highlighttable tr { - display: flex; -} - -table.highlighttable td { - margin: 0; - padding: 0; -} - -table.highlighttable td.linenos { - padding-right: 0.5em; -} - -table.highlighttable td.code { - flex: 1; - overflow: hidden; -} - -.highlight .hll { - display: block; -} - -div.highlight pre, -table.highlighttable pre { - margin: 0; -} - -div.code-block-caption + div { - margin-top: 0; -} - -div.code-block-caption { - margin-top: 1em; - padding: 2px 5px; - font-size: small; -} - -div.code-block-caption code { - background-color: transparent; -} - -table.highlighttable td.linenos, -span.linenos, -div.doctest > div.highlight span.gp { /* gp: Generic.Prompt */ - user-select: none; -} - -div.code-block-caption span.caption-number { - padding: 0.1em 0.3em; - font-style: italic; -} - -div.code-block-caption span.caption-text { -} - -div.literal-block-wrapper { - margin: 1em 0; -} - -code.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -code.descclassname { - background-color: transparent; -} - -code.xref, a code { - background-color: transparent; - font-weight: bold; -} - -h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.body div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -span.eqno a.headerlink { - position: absolute; - z-index: 1; -} - -div.math:hover a.headerlink { - visibility: visible; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} \ No newline at end of file diff --git a/docs/_static/css/badge_only.css b/docs/_static/css/badge_only.css deleted file mode 100644 index 23602728..00000000 --- a/docs/_static/css/badge_only.css +++ /dev/null @@ -1,224 +0,0 @@ -@charset "UTF-8"; -.fa:before { - -webkit-font-smoothing: antialiased; -} - -.clearfix { - *zoom: 1; -} -.clearfix:before, .clearfix:after { - display: table; - content: ""; -} -.clearfix:after { - clear: both; -} - -@font-face { - font-family: FontAwesome; - font-weight: normal; - font-style: normal; - src: url("../fonts/fontawesome-webfont.eot"); - src: url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/fontawesome-webfont.woff") format("woff"), url("../fonts/fontawesome-webfont.ttf") format("truetype"), url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg"); -} -.fa:before { - display: inline-block; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - line-height: 1; - text-decoration: inherit; -} - -a .fa { - display: inline-block; - text-decoration: inherit; -} - -li .fa { - display: inline-block; -} -li .fa-large:before, -li .fa-large:before { - /* 1.5 increased font size for fa-large * 1.25 width */ - width: 1.875em; -} - -ul.fas { - list-style-type: none; - margin-left: 2em; - text-indent: -0.8em; -} -ul.fas li .fa { - width: 0.8em; -} -ul.fas li .fa-large:before, -ul.fas li .fa-large:before { - /* 1.5 increased font size for fa-large * 1.25 width */ - vertical-align: baseline; -} - -.fa-book:before { - content: ""; -} - -.icon-book:before { - content: ""; -} - -.fa-caret-down:before { - content: ""; -} - -.icon-caret-down:before { - content: ""; -} - -.fa-caret-up:before { - content: ""; -} - -.icon-caret-up:before { - content: ""; -} - -.fa-caret-left:before { - content: ""; -} - -.icon-caret-left:before { - content: ""; -} - -.fa-caret-right:before { - content: ""; -} - -.icon-caret-right:before { - content: ""; -} - -.rst-versions { - position: fixed; - bottom: 0; - left: 0; - overflow-y: scroll; - width: 300px; - color: #fcfcfc; - background: #1f1d1d; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - z-index: 400; -} -.rst-versions a { - color: #60c557; - text-decoration: none; -} -.rst-versions .rst-badge-small { - display: none; -} -.rst-versions .rst-current-version { - padding: 12px; - background-color: #272525; - display: block; - text-align: right; - font-size: 90%; - cursor: pointer; - color: #84d27d; - *zoom: 1; -} -.rst-versions .rst-current-version:before, .rst-versions .rst-current-version:after { - display: table; - content: ""; -} -.rst-versions .rst-current-version:after { - clear: both; -} -.rst-versions .rst-current-version .fa { - color: #fcfcfc; -} -.rst-versions .rst-current-version .fa-book { - float: left; -} -.rst-versions .rst-current-version .icon-book { - float: left; -} -.rst-versions .rst-current-version.rst-out-of-date { - background-color: #E74C3C; - color: #fff; -} -.rst-versions .rst-current-version.rst-active-old-version { - background-color: #F1C40F; - color: #000; -} -.rst-versions.shift-up { - max-height: 100%; -} -.rst-versions.shift-up .rst-other-versions { - display: block; -} -.rst-versions .rst-other-versions { - font-size: 90%; - padding: 12px; - color: gray; - display: none; -} -.rst-versions .rst-other-versions hr { - display: block; - height: 1px; - border: 0; - margin: 20px 0; - padding: 0; - border-top: solid 1px #413d3d; -} -.rst-versions .rst-other-versions dd { - display: inline-block; - margin: 0; -} -.rst-versions .rst-other-versions dd a { - display: inline-block; - padding: 6px; - color: #fcfcfc; -} -.rst-versions.rst-badge { - width: auto; - bottom: 20px; - right: 20px; - left: auto; - border: none; - max-width: 300px; -} -.rst-versions.rst-badge .icon-book { - float: none; -} -.rst-versions.rst-badge .fa-book { - float: none; -} -.rst-versions.rst-badge.shift-up .rst-current-version { - text-align: right; -} -.rst-versions.rst-badge.shift-up .rst-current-version .fa-book { - float: left; -} -.rst-versions.rst-badge.shift-up .rst-current-version .icon-book { - float: left; -} -.rst-versions.rst-badge .rst-current-version { - width: auto; - height: 30px; - line-height: 30px; - padding: 0 6px; - display: block; - text-align: center; -} - -@media screen and (max-width: 768px) { - .rst-versions { - width: 85%; - display: none; - } - .rst-versions.shift { - display: block; - } -} - -/*# sourceMappingURL=badge_only.css.map */ diff --git a/docs/_static/css/badge_only.css.map b/docs/_static/css/badge_only.css.map deleted file mode 100644 index 8e6887d0..00000000 --- a/docs/_static/css/badge_only.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": ";AAyDA,UAAY;EACV,sBAAsB,EAAE,WAAW;;;AAqDrC,SAAS;EARP,KAAK,EAAE,CAAC;;AACR,iCAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,eAAO;EACL,KAAK,EAAE,IAAI;;;AC1Gb,UAkBC;EAjBC,WAAW,ECFJ,WAAW;EDGlB,WAAW,EAHqC,MAAM;EAItD,UAAU,EAJsD,MAAM;EAapE,GAAG,EAAE,uCAAwB;EAC7B,GAAG,EAAE,kQAG2D;;ACftE,UAAU;EACR,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,WAAW;EACxB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,MAAM;EACnB,WAAW,EAAE,CAAC;EACd,eAAe,EAAE,OAAO;;;AAG1B,KAAK;EACH,OAAO,EAAE,YAAY;EACrB,eAAe,EAAE,OAAO;;;AAIxB,MAAG;EACD,OAAO,EAAE,YAAY;;AACvB;mBAAiB;;EAGf,KAAK,EAAE,OAAY;;;AAEvB,MAAM;EACJ,eAAe,EAAE,IAAI;EACrB,WAAW,EAAE,GAAG;EAChB,WAAW,EAAE,MAAM;;AAEjB,aAAG;EACD,KAAK,EAAE,KAAI;;AACb;0BAAiB;;EAGf,cAAc,EAAE,QAAQ;;;AAG9B,eAAe;EACb,OAAO,EAAE,GAAO;;;AAElB,iBAAiB;EACf,OAAO,EAAE,GAAO;;;AAElB,qBAAqB;EACnB,OAAO,EAAE,GAAO;;;AAElB,uBAAuB;EACrB,OAAO,EAAE,GAAO;;;AAElB,mBAAmB;EACjB,OAAO,EAAE,GAAO;;;AAElB,qBAAqB;EACnB,OAAO,EAAE,GAAO;;;AAElB,qBAAqB;EACnB,OAAO,EAAE,GAAO;;;AAElB,uBAAuB;EACrB,OAAO,EAAE,GAAO;;;AAElB,sBAAsB;EACpB,OAAO,EAAE,GAAO;;;AAElB,wBAAwB;EACtB,OAAO,EAAE,GAAO;;;ACnElB,aAAa;EACX,QAAQ,EAAE,KAAK;EACf,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EACP,UAAU,EAAE,MAAM;EAClB,KAAK,EC4E+B,KAAK;ED3EzC,KAAK,EEkD+B,OAAyB;EFjD7D,UAAU,EAAE,OAAkC;EAC9C,WAAW,EE8DyB,2DAA2D;EF7D/F,OAAO,EC+E6B,GAAG;;AD9EvC,eAAC;EACC,KAAK,EEH6B,OAAmB;EFIrD,eAAe,EAAE,IAAI;;AACvB,8BAAgB;EACd,OAAO,EAAE,IAAI;;AACf,kCAAoB;EAClB,OAAO,EAAE,IAAqB;EAC9B,gBAAgB,EAAE,OAAkC;EACpD,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,KAAK;EACjB,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,OAAO;EACf,KAAK,EEC6B,OAAM;ELgF1C,KAAK,EAAE,CAAC;;AACR,mFAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,wCAAO;EACL,KAAK,EAAE,IAAI;;AGrFX,sCAAG;EACD,KAAK,EE+B2B,OAAyB;;AF9B3D,2CAAQ;EACN,KAAK,EAAE,IAAI;;AACb,6CAAU;EACR,KAAK,EAAE,IAAI;;AACb,kDAAiB;EACf,gBAAgB,ECQgB,OAAI;EDPpC,KAAK,EEmB2B,IAAM;;AFlBxC,yDAAwB;EACtB,gBAAgB,EEkCgB,OAAO;EFjCvC,KAAK,ECzB2B,IAAI;;AD0BxC,sBAAU;EACR,UAAU,EAAE,IAAI;;AAClB,0CAA8B;EAC5B,OAAO,EAAE,KAAK;;AAChB,iCAAmB;EACjB,SAAS,EAAE,GAAG;EACd,OAAO,EAAE,IAAqB;EAC9B,KAAK,EEM6B,IAAY;EFL9C,OAAO,EAAE,IAAI;;AACb,oCAAE;EACA,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,GAAG;EACX,MAAM,EAAE,CAAC;EACT,MAAM,EAAE,MAAM;EACd,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,iBAA6C;;AAC3D,oCAAE;EACA,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,CAAC;;AACT,sCAAC;EACC,OAAO,EAAE,YAAY;EACrB,OAAO,EAAE,GAAqB;EAC9B,KAAK,EEFyB,OAAyB;;AFG7D,uBAAW;EACT,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,IAAI,EAAE,IAAI;EACV,MAAM,EAAE,IAAI;EACZ,SAAS,ECgByB,KAAK;;ADfvC,kCAAU;EACR,KAAK,EAAE,IAAI;;AACb,gCAAQ;EACN,KAAK,EAAE,IAAI;;AACb,qDAA+B;EAC7B,UAAU,EAAE,KAAK;;AACjB,8DAAQ;EACN,KAAK,EAAE,IAAI;;AACb,gEAAU;EACR,KAAK,EAAE,IAAI;;AACf,4CAAoB;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,KAAuB;EAChC,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,MAAM;;;AGlDpB,oCAAsB;EHqDxB,aAAa;IACX,KAAK,EAAE,GAAG;IACV,OAAO,EAAE,IAAI;;EACb,mBAAO;IACL,OAAO,EAAE,KAAK", -"sources": ["../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/bourbon/dist/css3/_font-face.scss","../../../sass/_theme_badge_fa.sass","../../../sass/_theme_badge.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss"], -"names": [], -"file": "badge_only.css" -} diff --git a/docs/_static/css/theme.css b/docs/_static/css/theme.css deleted file mode 100644 index 0f5a806a..00000000 --- a/docs/_static/css/theme.css +++ /dev/null @@ -1,5778 +0,0 @@ -@charset "UTF-8"; -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { - display: block; -} - -audio, canvas, video { - display: inline-block; - *display: inline; - *zoom: 1; -} - -audio:not([controls]) { - display: none; -} - -[hidden] { - display: none; -} - -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -body { - margin: 0; -} - -a:hover, a:active { - outline: 0; -} - -abbr[title] { - border-bottom: 1px dotted; -} - -b, strong { - font-weight: bold; -} - -blockquote { - margin: 0; -} - -dfn { - font-style: italic; -} - -ins { - background: #ff9; - color: #000; - text-decoration: none; -} - -mark { - background: #ff0; - color: #000; - font-style: italic; - font-weight: bold; -} - -pre, code, .rst-content tt, .rst-content code, kbd, samp { - font-family: monospace, serif; - _font-family: "courier new", monospace; - font-size: 1em; -} - -pre { - white-space: pre; -} - -q { - quotes: none; -} - -q:before, q:after { - content: ""; - content: none; -} - -small { - font-size: 85%; -} - -sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -ul, ol, dl { - margin: 0; - padding: 0; - list-style: none; - list-style-image: none; -} - -li { - list-style: none; -} - -dd { - margin: 0; -} - -img { - border: 0; - -ms-interpolation-mode: bicubic; - vertical-align: middle; - max-width: 100%; -} - -svg:not(:root) { - overflow: hidden; -} - -figure { - margin: 0; -} - -form { - margin: 0; -} - -fieldset { - border: 0; - margin: 0; - padding: 0; -} - -label { - cursor: pointer; -} - -legend { - border: 0; - *margin-left: -7px; - padding: 0; - white-space: normal; -} - -button, input, select, textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; -} - -button, input { - line-height: normal; -} - -button, input[type="button"], input[type="reset"], input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; - *overflow: visible; -} - -button[disabled], input[disabled] { - cursor: default; -} - -input[type="checkbox"], input[type="radio"] { - box-sizing: border-box; - padding: 0; - *width: 13px; - *height: 13px; -} - -input[type="search"] { - -webkit-appearance: textfield; - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; -} - -input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; -} - -textarea { - overflow: auto; - vertical-align: top; - resize: vertical; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td { - vertical-align: top; -} - -.chromeframe { - margin: 0.2em 0; - background: #ccc; - color: black; - padding: 0.2em 0; -} - -.ir { - display: block; - border: 0; - text-indent: -999em; - overflow: hidden; - background-color: transparent; - background-repeat: no-repeat; - text-align: left; - direction: ltr; - *line-height: 0; -} - -.ir br { - display: none; -} - -.hidden { - display: none !important; - visibility: hidden; -} - -.visuallyhidden { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} - -.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { - clip: auto; - height: auto; - margin: 0; - overflow: visible; - position: static; - width: auto; -} - -.invisible { - visibility: hidden; -} - -.relative { - position: relative; -} - -big, small { - font-size: 100%; -} - -@media print { - html, body, section { - background: none !important; - } - - * { - box-shadow: none !important; - text-shadow: none !important; - filter: none !important; - -ms-filter: none !important; - } - - a, a:visited { - text-decoration: underline; - } - - .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { - content: ""; - } - - pre, blockquote { - page-break-inside: avoid; - } - - thead { - display: table-header-group; - } - - tr, img { - page-break-inside: avoid; - } - - img { - max-width: 100% !important; - } - - @page { - margin: 0.5cm; - } - p, h2, .rst-content .toctree-wrapper p.caption, h3 { - orphans: 3; - widows: 3; - } - - h2, .rst-content .toctree-wrapper p.caption, h3 { - page-break-after: avoid; - } -} -.fa:before, .wy-menu-vertical li span.toctree-expand:before, .wy-menu-vertical li.on a span.toctree-expand:before, .wy-menu-vertical li.current > a span.toctree-expand:before, .rst-content .admonition-title:before, .rst-content h1 .headerlink:before, .rst-content h2 .headerlink:before, .rst-content h3 .headerlink:before, .rst-content h4 .headerlink:before, .rst-content h5 .headerlink:before, .rst-content h6 .headerlink:before, .rst-content dl dt .headerlink:before, .rst-content p.caption .headerlink:before, .rst-content table > caption .headerlink:before, .rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before, .icon:before, .wy-dropdown .caret:before, .wy-inline-validate.wy-inline-validate-success .wy-input-context:before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before, .wy-alert, .rst-content .note, .rst-content .attention, .rst-content .caution, .rst-content .danger, .rst-content .error, .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .warning, .rst-content .seealso, .rst-content .admonition-todo, .rst-content .admonition, .btn, input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"], select, textarea, .wy-menu-vertical li.on a, .wy-menu-vertical li.current > a, .wy-side-nav-search > a, .wy-side-nav-search .wy-dropdown > a, .wy-nav-top a { - -webkit-font-smoothing: antialiased; -} - -.clearfix { - *zoom: 1; -} -.clearfix:before, .clearfix:after { - display: table; - content: ""; -} -.clearfix:after { - clear: both; -} - -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */ -/* FONT PATH - * -------------------------- */ -@font-face { - font-family: 'FontAwesome'; - src: url("../fonts/fontawesome-webfont.eot?v=4.7.0"); - src: url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"), url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"), url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"), url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"), url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg"); - font-weight: normal; - font-style: normal; -} -.fa, .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand, .rst-content .admonition-title, .rst-content h1 .headerlink, .rst-content h2 .headerlink, .rst-content h3 .headerlink, .rst-content h4 .headerlink, .rst-content h5 .headerlink, .rst-content h6 .headerlink, .rst-content dl dt .headerlink, .rst-content p.caption .headerlink, .rst-content table > caption .headerlink, .rst-content tt.download span:first-child, .rst-content code.download span:first-child, .icon { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/* makes the font 33% larger relative to the icon container */ -.fa-lg { - font-size: 1.3333333333em; - line-height: 0.75em; - vertical-align: -15%; -} - -.fa-2x { - font-size: 2em; -} - -.fa-3x { - font-size: 3em; -} - -.fa-4x { - font-size: 4em; -} - -.fa-5x { - font-size: 5em; -} - -.fa-fw { - width: 1.2857142857em; - text-align: center; -} - -.fa-ul { - padding-left: 0; - margin-left: 2.1428571429em; - list-style-type: none; -} -.fa-ul > li { - position: relative; -} - -.fa-li { - position: absolute; - left: -2.1428571429em; - width: 2.1428571429em; - top: 0.1428571429em; - text-align: center; -} -.fa-li.fa-lg { - left: -1.8571428571em; -} - -.fa-border { - padding: .2em .25em .15em; - border: solid 0.08em #eee; - border-radius: .1em; -} - -.fa-pull-left { - float: left; -} - -.fa-pull-right { - float: right; -} - -.fa.fa-pull-left, .wy-menu-vertical li span.fa-pull-left.toctree-expand, .wy-menu-vertical li.on a span.fa-pull-left.toctree-expand, .wy-menu-vertical li.current > a span.fa-pull-left.toctree-expand, .rst-content .fa-pull-left.admonition-title, .rst-content h1 .fa-pull-left.headerlink, .rst-content h2 .fa-pull-left.headerlink, .rst-content h3 .fa-pull-left.headerlink, .rst-content h4 .fa-pull-left.headerlink, .rst-content h5 .fa-pull-left.headerlink, .rst-content h6 .fa-pull-left.headerlink, .rst-content dl dt .fa-pull-left.headerlink, .rst-content p.caption .fa-pull-left.headerlink, .rst-content table > caption .fa-pull-left.headerlink, .rst-content tt.download span.fa-pull-left:first-child, .rst-content code.download span.fa-pull-left:first-child, .fa-pull-left.icon { - margin-right: .3em; -} -.fa.fa-pull-right, .wy-menu-vertical li span.fa-pull-right.toctree-expand, .wy-menu-vertical li.on a span.fa-pull-right.toctree-expand, .wy-menu-vertical li.current > a span.fa-pull-right.toctree-expand, .rst-content .fa-pull-right.admonition-title, .rst-content h1 .fa-pull-right.headerlink, .rst-content h2 .fa-pull-right.headerlink, .rst-content h3 .fa-pull-right.headerlink, .rst-content h4 .fa-pull-right.headerlink, .rst-content h5 .fa-pull-right.headerlink, .rst-content h6 .fa-pull-right.headerlink, .rst-content dl dt .fa-pull-right.headerlink, .rst-content p.caption .fa-pull-right.headerlink, .rst-content table > caption .fa-pull-right.headerlink, .rst-content tt.download span.fa-pull-right:first-child, .rst-content code.download span.fa-pull-right:first-child, .fa-pull-right.icon { - margin-left: .3em; -} - -/* Deprecated as of 4.4.0 */ -.pull-right { - float: right; -} - -.pull-left { - float: left; -} - -.fa.pull-left, .wy-menu-vertical li span.pull-left.toctree-expand, .wy-menu-vertical li.on a span.pull-left.toctree-expand, .wy-menu-vertical li.current > a span.pull-left.toctree-expand, .rst-content .pull-left.admonition-title, .rst-content h1 .pull-left.headerlink, .rst-content h2 .pull-left.headerlink, .rst-content h3 .pull-left.headerlink, .rst-content h4 .pull-left.headerlink, .rst-content h5 .pull-left.headerlink, .rst-content h6 .pull-left.headerlink, .rst-content dl dt .pull-left.headerlink, .rst-content p.caption .pull-left.headerlink, .rst-content table > caption .pull-left.headerlink, .rst-content tt.download span.pull-left:first-child, .rst-content code.download span.pull-left:first-child, .pull-left.icon { - margin-right: .3em; -} -.fa.pull-right, .wy-menu-vertical li span.pull-right.toctree-expand, .wy-menu-vertical li.on a span.pull-right.toctree-expand, .wy-menu-vertical li.current > a span.pull-right.toctree-expand, .rst-content .pull-right.admonition-title, .rst-content h1 .pull-right.headerlink, .rst-content h2 .pull-right.headerlink, .rst-content h3 .pull-right.headerlink, .rst-content h4 .pull-right.headerlink, .rst-content h5 .pull-right.headerlink, .rst-content h6 .pull-right.headerlink, .rst-content dl dt .pull-right.headerlink, .rst-content p.caption .pull-right.headerlink, .rst-content table > caption .pull-right.headerlink, .rst-content tt.download span.pull-right:first-child, .rst-content code.download span.pull-right:first-child, .pull-right.icon { - margin-left: .3em; -} - -.fa-spin { - -webkit-animation: fa-spin 2s infinite linear; - animation: fa-spin 2s infinite linear; -} - -.fa-pulse { - -webkit-animation: fa-spin 1s infinite steps(8); - animation: fa-spin 1s infinite steps(8); -} - -@-webkit-keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -.fa-rotate-90 { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; - -webkit-transform: rotate(90deg); - -ms-transform: rotate(90deg); - transform: rotate(90deg); -} - -.fa-rotate-180 { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} - -.fa-rotate-270 { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; - -webkit-transform: rotate(270deg); - -ms-transform: rotate(270deg); - transform: rotate(270deg); -} - -.fa-flip-horizontal { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; - -webkit-transform: scale(-1, 1); - -ms-transform: scale(-1, 1); - transform: scale(-1, 1); -} - -.fa-flip-vertical { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; - -webkit-transform: scale(1, -1); - -ms-transform: scale(1, -1); - transform: scale(1, -1); -} - -:root .fa-rotate-90, -:root .fa-rotate-180, -:root .fa-rotate-270, -:root .fa-flip-horizontal, -:root .fa-flip-vertical { - filter: none; -} - -.fa-stack { - position: relative; - display: inline-block; - width: 2em; - height: 2em; - line-height: 2em; - vertical-align: middle; -} - -.fa-stack-1x, .fa-stack-2x { - position: absolute; - left: 0; - width: 100%; - text-align: center; -} - -.fa-stack-1x { - line-height: inherit; -} - -.fa-stack-2x { - font-size: 2em; -} - -.fa-inverse { - color: #fff; -} - -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen - readers do not read off random characters that represent icons */ -.fa-glass:before { - content: ""; -} - -.fa-music:before { - content: ""; -} - -.fa-search:before, .icon-search:before { - content: ""; -} - -.fa-envelope-o:before { - content: ""; -} - -.fa-heart:before { - content: ""; -} - -.fa-star:before { - content: ""; -} - -.fa-star-o:before { - content: ""; -} - -.fa-user:before { - content: ""; -} - -.fa-film:before { - content: ""; -} - -.fa-th-large:before { - content: ""; -} - -.fa-th:before { - content: ""; -} - -.fa-th-list:before { - content: ""; -} - -.fa-check:before { - content: ""; -} - -.fa-remove:before, -.fa-close:before, -.fa-times:before { - content: ""; -} - -.fa-search-plus:before { - content: ""; -} - -.fa-search-minus:before { - content: ""; -} - -.fa-power-off:before { - content: ""; -} - -.fa-signal:before { - content: ""; -} - -.fa-gear:before, -.fa-cog:before { - content: ""; -} - -.fa-trash-o:before { - content: ""; -} - -.fa-home:before, .icon-home:before { - content: ""; -} - -.fa-file-o:before { - content: ""; -} - -.fa-clock-o:before { - content: ""; -} - -.fa-road:before { - content: ""; -} - -.fa-download:before, .rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before { - content: ""; -} - -.fa-arrow-circle-o-down:before { - content: ""; -} - -.fa-arrow-circle-o-up:before { - content: ""; -} - -.fa-inbox:before { - content: ""; -} - -.fa-play-circle-o:before { - content: ""; -} - -.fa-rotate-right:before, -.fa-repeat:before { - content: ""; -} - -.fa-refresh:before { - content: ""; -} - -.fa-list-alt:before { - content: ""; -} - -.fa-lock:before { - content: ""; -} - -.fa-flag:before { - content: ""; -} - -.fa-headphones:before { - content: ""; -} - -.fa-volume-off:before { - content: ""; -} - -.fa-volume-down:before { - content: ""; -} - -.fa-volume-up:before { - content: ""; -} - -.fa-qrcode:before { - content: ""; -} - -.fa-barcode:before { - content: ""; -} - -.fa-tag:before { - content: ""; -} - -.fa-tags:before { - content: ""; -} - -.fa-book:before, .icon-book:before { - content: ""; -} - -.fa-bookmark:before { - content: ""; -} - -.fa-print:before { - content: ""; -} - -.fa-camera:before { - content: ""; -} - -.fa-font:before { - content: ""; -} - -.fa-bold:before { - content: ""; -} - -.fa-italic:before { - content: ""; -} - -.fa-text-height:before { - content: ""; -} - -.fa-text-width:before { - content: ""; -} - -.fa-align-left:before { - content: ""; -} - -.fa-align-center:before { - content: ""; -} - -.fa-align-right:before { - content: ""; -} - -.fa-align-justify:before { - content: ""; -} - -.fa-list:before { - content: ""; -} - -.fa-dedent:before, -.fa-outdent:before { - content: ""; -} - -.fa-indent:before { - content: ""; -} - -.fa-video-camera:before { - content: ""; -} - -.fa-photo:before, -.fa-image:before, -.fa-picture-o:before { - content: ""; -} - -.fa-pencil:before { - content: ""; -} - -.fa-map-marker:before { - content: ""; -} - -.fa-adjust:before { - content: ""; -} - -.fa-tint:before { - content: ""; -} - -.fa-edit:before, -.fa-pencil-square-o:before { - content: ""; -} - -.fa-share-square-o:before { - content: ""; -} - -.fa-check-square-o:before { - content: ""; -} - -.fa-arrows:before { - content: ""; -} - -.fa-step-backward:before { - content: ""; -} - -.fa-fast-backward:before { - content: ""; -} - -.fa-backward:before { - content: ""; -} - -.fa-play:before { - content: ""; -} - -.fa-pause:before { - content: ""; -} - -.fa-stop:before { - content: ""; -} - -.fa-forward:before { - content: ""; -} - -.fa-fast-forward:before { - content: ""; -} - -.fa-step-forward:before { - content: ""; -} - -.fa-eject:before { - content: ""; -} - -.fa-chevron-left:before { - content: ""; -} - -.fa-chevron-right:before { - content: ""; -} - -.fa-plus-circle:before { - content: ""; -} - -.fa-minus-circle:before { - content: ""; -} - -.fa-times-circle:before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before { - content: ""; -} - -.fa-check-circle:before, .wy-inline-validate.wy-inline-validate-success .wy-input-context:before { - content: ""; -} - -.fa-question-circle:before { - content: ""; -} - -.fa-info-circle:before { - content: ""; -} - -.fa-crosshairs:before { - content: ""; -} - -.fa-times-circle-o:before { - content: ""; -} - -.fa-check-circle-o:before { - content: ""; -} - -.fa-ban:before { - content: ""; -} - -.fa-arrow-left:before { - content: ""; -} - -.fa-arrow-right:before { - content: ""; -} - -.fa-arrow-up:before { - content: ""; -} - -.fa-arrow-down:before { - content: ""; -} - -.fa-mail-forward:before, -.fa-share:before { - content: ""; -} - -.fa-expand:before { - content: ""; -} - -.fa-compress:before { - content: ""; -} - -.fa-plus:before { - content: ""; -} - -.fa-minus:before { - content: ""; -} - -.fa-asterisk:before { - content: ""; -} - -.fa-exclamation-circle:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before, .rst-content .admonition-title:before { - content: ""; -} - -.fa-gift:before { - content: ""; -} - -.fa-leaf:before { - content: ""; -} - -.fa-fire:before, .icon-fire:before { - content: ""; -} - -.fa-eye:before { - content: ""; -} - -.fa-eye-slash:before { - content: ""; -} - -.fa-warning:before, -.fa-exclamation-triangle:before { - content: ""; -} - -.fa-plane:before { - content: ""; -} - -.fa-calendar:before { - content: ""; -} - -.fa-random:before { - content: ""; -} - -.fa-comment:before { - content: ""; -} - -.fa-magnet:before { - content: ""; -} - -.fa-chevron-up:before { - content: ""; -} - -.fa-chevron-down:before { - content: ""; -} - -.fa-retweet:before { - content: ""; -} - -.fa-shopping-cart:before { - content: ""; -} - -.fa-folder:before { - content: ""; -} - -.fa-folder-open:before { - content: ""; -} - -.fa-arrows-v:before { - content: ""; -} - -.fa-arrows-h:before { - content: ""; -} - -.fa-bar-chart-o:before, -.fa-bar-chart:before { - content: ""; -} - -.fa-twitter-square:before { - content: ""; -} - -.fa-facebook-square:before { - content: ""; -} - -.fa-camera-retro:before { - content: ""; -} - -.fa-key:before { - content: ""; -} - -.fa-gears:before, -.fa-cogs:before { - content: ""; -} - -.fa-comments:before { - content: ""; -} - -.fa-thumbs-o-up:before { - content: ""; -} - -.fa-thumbs-o-down:before { - content: ""; -} - -.fa-star-half:before { - content: ""; -} - -.fa-heart-o:before { - content: ""; -} - -.fa-sign-out:before { - content: ""; -} - -.fa-linkedin-square:before { - content: ""; -} - -.fa-thumb-tack:before { - content: ""; -} - -.fa-external-link:before { - content: ""; -} - -.fa-sign-in:before { - content: ""; -} - -.fa-trophy:before { - content: ""; -} - -.fa-github-square:before { - content: ""; -} - -.fa-upload:before { - content: ""; -} - -.fa-lemon-o:before { - content: ""; -} - -.fa-phone:before { - content: ""; -} - -.fa-square-o:before { - content: ""; -} - -.fa-bookmark-o:before { - content: ""; -} - -.fa-phone-square:before { - content: ""; -} - -.fa-twitter:before { - content: ""; -} - -.fa-facebook-f:before, -.fa-facebook:before { - content: ""; -} - -.fa-github:before, .icon-github:before { - content: ""; -} - -.fa-unlock:before { - content: ""; -} - -.fa-credit-card:before { - content: ""; -} - -.fa-feed:before, -.fa-rss:before { - content: ""; -} - -.fa-hdd-o:before { - content: ""; -} - -.fa-bullhorn:before { - content: ""; -} - -.fa-bell:before { - content: ""; -} - -.fa-certificate:before { - content: ""; -} - -.fa-hand-o-right:before { - content: ""; -} - -.fa-hand-o-left:before { - content: ""; -} - -.fa-hand-o-up:before { - content: ""; -} - -.fa-hand-o-down:before { - content: ""; -} - -.fa-arrow-circle-left:before, .icon-circle-arrow-left:before { - content: ""; -} - -.fa-arrow-circle-right:before, .icon-circle-arrow-right:before { - content: ""; -} - -.fa-arrow-circle-up:before { - content: ""; -} - -.fa-arrow-circle-down:before { - content: ""; -} - -.fa-globe:before { - content: ""; -} - -.fa-wrench:before { - content: ""; -} - -.fa-tasks:before { - content: ""; -} - -.fa-filter:before { - content: ""; -} - -.fa-briefcase:before { - content: ""; -} - -.fa-arrows-alt:before { - content: ""; -} - -.fa-group:before, -.fa-users:before { - content: ""; -} - -.fa-chain:before, -.fa-link:before, -.icon-link:before { - content: ""; -} - -.fa-cloud:before { - content: ""; -} - -.fa-flask:before { - content: ""; -} - -.fa-cut:before, -.fa-scissors:before { - content: ""; -} - -.fa-copy:before, -.fa-files-o:before { - content: ""; -} - -.fa-paperclip:before { - content: ""; -} - -.fa-save:before, -.fa-floppy-o:before { - content: ""; -} - -.fa-square:before { - content: ""; -} - -.fa-navicon:before, -.fa-reorder:before, -.fa-bars:before { - content: ""; -} - -.fa-list-ul:before { - content: ""; -} - -.fa-list-ol:before { - content: ""; -} - -.fa-strikethrough:before { - content: ""; -} - -.fa-underline:before { - content: ""; -} - -.fa-table:before { - content: ""; -} - -.fa-magic:before { - content: ""; -} - -.fa-truck:before { - content: ""; -} - -.fa-pinterest:before { - content: ""; -} - -.fa-pinterest-square:before { - content: ""; -} - -.fa-google-plus-square:before { - content: ""; -} - -.fa-google-plus:before { - content: ""; -} - -.fa-money:before { - content: ""; -} - -.fa-caret-down:before, .wy-dropdown .caret:before, .icon-caret-down:before { - content: ""; -} - -.fa-caret-up:before { - content: ""; -} - -.fa-caret-left:before { - content: ""; -} - -.fa-caret-right:before { - content: ""; -} - -.fa-columns:before { - content: ""; -} - -.fa-unsorted:before, -.fa-sort:before { - content: ""; -} - -.fa-sort-down:before, -.fa-sort-desc:before { - content: ""; -} - -.fa-sort-up:before, -.fa-sort-asc:before { - content: ""; -} - -.fa-envelope:before { - content: ""; -} - -.fa-linkedin:before { - content: ""; -} - -.fa-rotate-left:before, -.fa-undo:before { - content: ""; -} - -.fa-legal:before, -.fa-gavel:before { - content: ""; -} - -.fa-dashboard:before, -.fa-tachometer:before { - content: ""; -} - -.fa-comment-o:before { - content: ""; -} - -.fa-comments-o:before { - content: ""; -} - -.fa-flash:before, -.fa-bolt:before { - content: ""; -} - -.fa-sitemap:before { - content: ""; -} - -.fa-umbrella:before { - content: ""; -} - -.fa-paste:before, -.fa-clipboard:before { - content: ""; -} - -.fa-lightbulb-o:before { - content: ""; -} - -.fa-exchange:before { - content: ""; -} - -.fa-cloud-download:before { - content: ""; -} - -.fa-cloud-upload:before { - content: ""; -} - -.fa-user-md:before { - content: ""; -} - -.fa-stethoscope:before { - content: ""; -} - -.fa-suitcase:before { - content: ""; -} - -.fa-bell-o:before { - content: ""; -} - -.fa-coffee:before { - content: ""; -} - -.fa-cutlery:before { - content: ""; -} - -.fa-file-text-o:before { - content: ""; -} - -.fa-building-o:before { - content: ""; -} - -.fa-hospital-o:before { - content: ""; -} - -.fa-ambulance:before { - content: ""; -} - -.fa-medkit:before { - content: ""; -} - -.fa-fighter-jet:before { - content: ""; -} - -.fa-beer:before { - content: ""; -} - -.fa-h-square:before { - content: ""; -} - -.fa-plus-square:before { - content: ""; -} - -.fa-angle-double-left:before { - content: ""; -} - -.fa-angle-double-right:before { - content: ""; -} - -.fa-angle-double-up:before { - content: ""; -} - -.fa-angle-double-down:before { - content: ""; -} - -.fa-angle-left:before { - content: ""; -} - -.fa-angle-right:before { - content: ""; -} - -.fa-angle-up:before { - content: ""; -} - -.fa-angle-down:before { - content: ""; -} - -.fa-desktop:before { - content: ""; -} - -.fa-laptop:before { - content: ""; -} - -.fa-tablet:before { - content: ""; -} - -.fa-mobile-phone:before, -.fa-mobile:before { - content: ""; -} - -.fa-circle-o:before { - content: ""; -} - -.fa-quote-left:before { - content: ""; -} - -.fa-quote-right:before { - content: ""; -} - -.fa-spinner:before { - content: ""; -} - -.fa-circle:before { - content: ""; -} - -.fa-mail-reply:before, -.fa-reply:before { - content: ""; -} - -.fa-github-alt:before { - content: ""; -} - -.fa-folder-o:before { - content: ""; -} - -.fa-folder-open-o:before { - content: ""; -} - -.fa-smile-o:before { - content: ""; -} - -.fa-frown-o:before { - content: ""; -} - -.fa-meh-o:before { - content: ""; -} - -.fa-gamepad:before { - content: ""; -} - -.fa-keyboard-o:before { - content: ""; -} - -.fa-flag-o:before { - content: ""; -} - -.fa-flag-checkered:before { - content: ""; -} - -.fa-terminal:before { - content: ""; -} - -.fa-code:before { - content: ""; -} - -.fa-mail-reply-all:before, -.fa-reply-all:before { - content: ""; -} - -.fa-star-half-empty:before, -.fa-star-half-full:before, -.fa-star-half-o:before { - content: ""; -} - -.fa-location-arrow:before { - content: ""; -} - -.fa-crop:before { - content: ""; -} - -.fa-code-fork:before { - content: ""; -} - -.fa-unlink:before, -.fa-chain-broken:before { - content: ""; -} - -.fa-question:before { - content: ""; -} - -.fa-info:before { - content: ""; -} - -.fa-exclamation:before { - content: ""; -} - -.fa-superscript:before { - content: ""; -} - -.fa-subscript:before { - content: ""; -} - -.fa-eraser:before { - content: ""; -} - -.fa-puzzle-piece:before { - content: ""; -} - -.fa-microphone:before { - content: ""; -} - -.fa-microphone-slash:before { - content: ""; -} - -.fa-shield:before { - content: ""; -} - -.fa-calendar-o:before { - content: ""; -} - -.fa-fire-extinguisher:before { - content: ""; -} - -.fa-rocket:before { - content: ""; -} - -.fa-maxcdn:before { - content: ""; -} - -.fa-chevron-circle-left:before { - content: ""; -} - -.fa-chevron-circle-right:before { - content: ""; -} - -.fa-chevron-circle-up:before { - content: ""; -} - -.fa-chevron-circle-down:before { - content: ""; -} - -.fa-html5:before { - content: ""; -} - -.fa-css3:before { - content: ""; -} - -.fa-anchor:before { - content: ""; -} - -.fa-unlock-alt:before { - content: ""; -} - -.fa-bullseye:before { - content: ""; -} - -.fa-ellipsis-h:before { - content: ""; -} - -.fa-ellipsis-v:before { - content: ""; -} - -.fa-rss-square:before { - content: ""; -} - -.fa-play-circle:before { - content: ""; -} - -.fa-ticket:before { - content: ""; -} - -.fa-minus-square:before { - content: ""; -} - -.fa-minus-square-o:before, .wy-menu-vertical li.on a span.toctree-expand:before, .wy-menu-vertical li.current > a span.toctree-expand:before { - content: ""; -} - -.fa-level-up:before { - content: ""; -} - -.fa-level-down:before { - content: ""; -} - -.fa-check-square:before { - content: ""; -} - -.fa-pencil-square:before { - content: ""; -} - -.fa-external-link-square:before { - content: ""; -} - -.fa-share-square:before { - content: ""; -} - -.fa-compass:before { - content: ""; -} - -.fa-toggle-down:before, -.fa-caret-square-o-down:before { - content: ""; -} - -.fa-toggle-up:before, -.fa-caret-square-o-up:before { - content: ""; -} - -.fa-toggle-right:before, -.fa-caret-square-o-right:before { - content: ""; -} - -.fa-euro:before, -.fa-eur:before { - content: ""; -} - -.fa-gbp:before { - content: ""; -} - -.fa-dollar:before, -.fa-usd:before { - content: ""; -} - -.fa-rupee:before, -.fa-inr:before { - content: ""; -} - -.fa-cny:before, -.fa-rmb:before, -.fa-yen:before, -.fa-jpy:before { - content: ""; -} - -.fa-ruble:before, -.fa-rouble:before, -.fa-rub:before { - content: ""; -} - -.fa-won:before, -.fa-krw:before { - content: ""; -} - -.fa-bitcoin:before, -.fa-btc:before { - content: ""; -} - -.fa-file:before { - content: ""; -} - -.fa-file-text:before { - content: ""; -} - -.fa-sort-alpha-asc:before { - content: ""; -} - -.fa-sort-alpha-desc:before { - content: ""; -} - -.fa-sort-amount-asc:before { - content: ""; -} - -.fa-sort-amount-desc:before { - content: ""; -} - -.fa-sort-numeric-asc:before { - content: ""; -} - -.fa-sort-numeric-desc:before { - content: ""; -} - -.fa-thumbs-up:before { - content: ""; -} - -.fa-thumbs-down:before { - content: ""; -} - -.fa-youtube-square:before { - content: ""; -} - -.fa-youtube:before { - content: ""; -} - -.fa-xing:before { - content: ""; -} - -.fa-xing-square:before { - content: ""; -} - -.fa-youtube-play:before { - content: ""; -} - -.fa-dropbox:before { - content: ""; -} - -.fa-stack-overflow:before { - content: ""; -} - -.fa-instagram:before { - content: ""; -} - -.fa-flickr:before { - content: ""; -} - -.fa-adn:before { - content: ""; -} - -.fa-bitbucket:before, .icon-bitbucket:before { - content: ""; -} - -.fa-bitbucket-square:before { - content: ""; -} - -.fa-tumblr:before { - content: ""; -} - -.fa-tumblr-square:before { - content: ""; -} - -.fa-long-arrow-down:before { - content: ""; -} - -.fa-long-arrow-up:before { - content: ""; -} - -.fa-long-arrow-left:before { - content: ""; -} - -.fa-long-arrow-right:before { - content: ""; -} - -.fa-apple:before { - content: ""; -} - -.fa-windows:before { - content: ""; -} - -.fa-android:before { - content: ""; -} - -.fa-linux:before { - content: ""; -} - -.fa-dribbble:before { - content: ""; -} - -.fa-skype:before { - content: ""; -} - -.fa-foursquare:before { - content: ""; -} - -.fa-trello:before { - content: ""; -} - -.fa-female:before { - content: ""; -} - -.fa-male:before { - content: ""; -} - -.fa-gittip:before, -.fa-gratipay:before { - content: ""; -} - -.fa-sun-o:before { - content: ""; -} - -.fa-moon-o:before { - content: ""; -} - -.fa-archive:before { - content: ""; -} - -.fa-bug:before { - content: ""; -} - -.fa-vk:before { - content: ""; -} - -.fa-weibo:before { - content: ""; -} - -.fa-renren:before { - content: ""; -} - -.fa-pagelines:before { - content: ""; -} - -.fa-stack-exchange:before { - content: ""; -} - -.fa-arrow-circle-o-right:before { - content: ""; -} - -.fa-arrow-circle-o-left:before { - content: ""; -} - -.fa-toggle-left:before, -.fa-caret-square-o-left:before { - content: ""; -} - -.fa-dot-circle-o:before { - content: ""; -} - -.fa-wheelchair:before { - content: ""; -} - -.fa-vimeo-square:before { - content: ""; -} - -.fa-turkish-lira:before, -.fa-try:before { - content: ""; -} - -.fa-plus-square-o:before, .wy-menu-vertical li span.toctree-expand:before { - content: ""; -} - -.fa-space-shuttle:before { - content: ""; -} - -.fa-slack:before { - content: ""; -} - -.fa-envelope-square:before { - content: ""; -} - -.fa-wordpress:before { - content: ""; -} - -.fa-openid:before { - content: ""; -} - -.fa-institution:before, -.fa-bank:before, -.fa-university:before { - content: ""; -} - -.fa-mortar-board:before, -.fa-graduation-cap:before { - content: ""; -} - -.fa-yahoo:before { - content: ""; -} - -.fa-google:before { - content: ""; -} - -.fa-reddit:before { - content: ""; -} - -.fa-reddit-square:before { - content: ""; -} - -.fa-stumbleupon-circle:before { - content: ""; -} - -.fa-stumbleupon:before { - content: ""; -} - -.fa-delicious:before { - content: ""; -} - -.fa-digg:before { - content: ""; -} - -.fa-pied-piper-pp:before { - content: ""; -} - -.fa-pied-piper-alt:before { - content: ""; -} - -.fa-drupal:before { - content: ""; -} - -.fa-joomla:before { - content: ""; -} - -.fa-language:before { - content: ""; -} - -.fa-fax:before { - content: ""; -} - -.fa-building:before { - content: ""; -} - -.fa-child:before { - content: ""; -} - -.fa-paw:before { - content: ""; -} - -.fa-spoon:before { - content: ""; -} - -.fa-cube:before { - content: ""; -} - -.fa-cubes:before { - content: ""; -} - -.fa-behance:before { - content: ""; -} - -.fa-behance-square:before { - content: ""; -} - -.fa-steam:before { - content: ""; -} - -.fa-steam-square:before { - content: ""; -} - -.fa-recycle:before { - content: ""; -} - -.fa-automobile:before, -.fa-car:before { - content: ""; -} - -.fa-cab:before, -.fa-taxi:before { - content: ""; -} - -.fa-tree:before { - content: ""; -} - -.fa-spotify:before { - content: ""; -} - -.fa-deviantart:before { - content: ""; -} - -.fa-soundcloud:before { - content: ""; -} - -.fa-database:before { - content: ""; -} - -.fa-file-pdf-o:before { - content: ""; -} - -.fa-file-word-o:before { - content: ""; -} - -.fa-file-excel-o:before { - content: ""; -} - -.fa-file-powerpoint-o:before { - content: ""; -} - -.fa-file-photo-o:before, -.fa-file-picture-o:before, -.fa-file-image-o:before { - content: ""; -} - -.fa-file-zip-o:before, -.fa-file-archive-o:before { - content: ""; -} - -.fa-file-sound-o:before, -.fa-file-audio-o:before { - content: ""; -} - -.fa-file-movie-o:before, -.fa-file-video-o:before { - content: ""; -} - -.fa-file-code-o:before { - content: ""; -} - -.fa-vine:before { - content: ""; -} - -.fa-codepen:before { - content: ""; -} - -.fa-jsfiddle:before { - content: ""; -} - -.fa-life-bouy:before, -.fa-life-buoy:before, -.fa-life-saver:before, -.fa-support:before, -.fa-life-ring:before { - content: ""; -} - -.fa-circle-o-notch:before { - content: ""; -} - -.fa-ra:before, -.fa-resistance:before, -.fa-rebel:before { - content: ""; -} - -.fa-ge:before, -.fa-empire:before { - content: ""; -} - -.fa-git-square:before { - content: ""; -} - -.fa-git:before { - content: ""; -} - -.fa-y-combinator-square:before, -.fa-yc-square:before, -.fa-hacker-news:before { - content: ""; -} - -.fa-tencent-weibo:before { - content: ""; -} - -.fa-qq:before { - content: ""; -} - -.fa-wechat:before, -.fa-weixin:before { - content: ""; -} - -.fa-send:before, -.fa-paper-plane:before { - content: ""; -} - -.fa-send-o:before, -.fa-paper-plane-o:before { - content: ""; -} - -.fa-history:before { - content: ""; -} - -.fa-circle-thin:before { - content: ""; -} - -.fa-header:before { - content: ""; -} - -.fa-paragraph:before { - content: ""; -} - -.fa-sliders:before { - content: ""; -} - -.fa-share-alt:before { - content: ""; -} - -.fa-share-alt-square:before { - content: ""; -} - -.fa-bomb:before { - content: ""; -} - -.fa-soccer-ball-o:before, -.fa-futbol-o:before { - content: ""; -} - -.fa-tty:before { - content: ""; -} - -.fa-binoculars:before { - content: ""; -} - -.fa-plug:before { - content: ""; -} - -.fa-slideshare:before { - content: ""; -} - -.fa-twitch:before { - content: ""; -} - -.fa-yelp:before { - content: ""; -} - -.fa-newspaper-o:before { - content: ""; -} - -.fa-wifi:before { - content: ""; -} - -.fa-calculator:before { - content: ""; -} - -.fa-paypal:before { - content: ""; -} - -.fa-google-wallet:before { - content: ""; -} - -.fa-cc-visa:before { - content: ""; -} - -.fa-cc-mastercard:before { - content: ""; -} - -.fa-cc-discover:before { - content: ""; -} - -.fa-cc-amex:before { - content: ""; -} - -.fa-cc-paypal:before { - content: ""; -} - -.fa-cc-stripe:before { - content: ""; -} - -.fa-bell-slash:before { - content: ""; -} - -.fa-bell-slash-o:before { - content: ""; -} - -.fa-trash:before { - content: ""; -} - -.fa-copyright:before { - content: ""; -} - -.fa-at:before { - content: ""; -} - -.fa-eyedropper:before { - content: ""; -} - -.fa-paint-brush:before { - content: ""; -} - -.fa-birthday-cake:before { - content: ""; -} - -.fa-area-chart:before { - content: ""; -} - -.fa-pie-chart:before { - content: ""; -} - -.fa-line-chart:before { - content: ""; -} - -.fa-lastfm:before { - content: ""; -} - -.fa-lastfm-square:before { - content: ""; -} - -.fa-toggle-off:before { - content: ""; -} - -.fa-toggle-on:before { - content: ""; -} - -.fa-bicycle:before { - content: ""; -} - -.fa-bus:before { - content: ""; -} - -.fa-ioxhost:before { - content: ""; -} - -.fa-angellist:before { - content: ""; -} - -.fa-cc:before { - content: ""; -} - -.fa-shekel:before, -.fa-sheqel:before, -.fa-ils:before { - content: ""; -} - -.fa-meanpath:before { - content: ""; -} - -.fa-buysellads:before { - content: ""; -} - -.fa-connectdevelop:before { - content: ""; -} - -.fa-dashcube:before { - content: ""; -} - -.fa-forumbee:before { - content: ""; -} - -.fa-leanpub:before { - content: ""; -} - -.fa-sellsy:before { - content: ""; -} - -.fa-shirtsinbulk:before { - content: ""; -} - -.fa-simplybuilt:before { - content: ""; -} - -.fa-skyatlas:before { - content: ""; -} - -.fa-cart-plus:before { - content: ""; -} - -.fa-cart-arrow-down:before { - content: ""; -} - -.fa-diamond:before { - content: ""; -} - -.fa-ship:before { - content: ""; -} - -.fa-user-secret:before { - content: ""; -} - -.fa-motorcycle:before { - content: ""; -} - -.fa-street-view:before { - content: ""; -} - -.fa-heartbeat:before { - content: ""; -} - -.fa-venus:before { - content: ""; -} - -.fa-mars:before { - content: ""; -} - -.fa-mercury:before { - content: ""; -} - -.fa-intersex:before, -.fa-transgender:before { - content: ""; -} - -.fa-transgender-alt:before { - content: ""; -} - -.fa-venus-double:before { - content: ""; -} - -.fa-mars-double:before { - content: ""; -} - -.fa-venus-mars:before { - content: ""; -} - -.fa-mars-stroke:before { - content: ""; -} - -.fa-mars-stroke-v:before { - content: ""; -} - -.fa-mars-stroke-h:before { - content: ""; -} - -.fa-neuter:before { - content: ""; -} - -.fa-genderless:before { - content: ""; -} - -.fa-facebook-official:before { - content: ""; -} - -.fa-pinterest-p:before { - content: ""; -} - -.fa-whatsapp:before { - content: ""; -} - -.fa-server:before { - content: ""; -} - -.fa-user-plus:before { - content: ""; -} - -.fa-user-times:before { - content: ""; -} - -.fa-hotel:before, -.fa-bed:before { - content: ""; -} - -.fa-viacoin:before { - content: ""; -} - -.fa-train:before { - content: ""; -} - -.fa-subway:before { - content: ""; -} - -.fa-medium:before { - content: ""; -} - -.fa-yc:before, -.fa-y-combinator:before { - content: ""; -} - -.fa-optin-monster:before { - content: ""; -} - -.fa-opencart:before { - content: ""; -} - -.fa-expeditedssl:before { - content: ""; -} - -.fa-battery-4:before, -.fa-battery:before, -.fa-battery-full:before { - content: ""; -} - -.fa-battery-3:before, -.fa-battery-three-quarters:before { - content: ""; -} - -.fa-battery-2:before, -.fa-battery-half:before { - content: ""; -} - -.fa-battery-1:before, -.fa-battery-quarter:before { - content: ""; -} - -.fa-battery-0:before, -.fa-battery-empty:before { - content: ""; -} - -.fa-mouse-pointer:before { - content: ""; -} - -.fa-i-cursor:before { - content: ""; -} - -.fa-object-group:before { - content: ""; -} - -.fa-object-ungroup:before { - content: ""; -} - -.fa-sticky-note:before { - content: ""; -} - -.fa-sticky-note-o:before { - content: ""; -} - -.fa-cc-jcb:before { - content: ""; -} - -.fa-cc-diners-club:before { - content: ""; -} - -.fa-clone:before { - content: ""; -} - -.fa-balance-scale:before { - content: ""; -} - -.fa-hourglass-o:before { - content: ""; -} - -.fa-hourglass-1:before, -.fa-hourglass-start:before { - content: ""; -} - -.fa-hourglass-2:before, -.fa-hourglass-half:before { - content: ""; -} - -.fa-hourglass-3:before, -.fa-hourglass-end:before { - content: ""; -} - -.fa-hourglass:before { - content: ""; -} - -.fa-hand-grab-o:before, -.fa-hand-rock-o:before { - content: ""; -} - -.fa-hand-stop-o:before, -.fa-hand-paper-o:before { - content: ""; -} - -.fa-hand-scissors-o:before { - content: ""; -} - -.fa-hand-lizard-o:before { - content: ""; -} - -.fa-hand-spock-o:before { - content: ""; -} - -.fa-hand-pointer-o:before { - content: ""; -} - -.fa-hand-peace-o:before { - content: ""; -} - -.fa-trademark:before { - content: ""; -} - -.fa-registered:before { - content: ""; -} - -.fa-creative-commons:before { - content: ""; -} - -.fa-gg:before { - content: ""; -} - -.fa-gg-circle:before { - content: ""; -} - -.fa-tripadvisor:before { - content: ""; -} - -.fa-odnoklassniki:before { - content: ""; -} - -.fa-odnoklassniki-square:before { - content: ""; -} - -.fa-get-pocket:before { - content: ""; -} - -.fa-wikipedia-w:before { - content: ""; -} - -.fa-safari:before { - content: ""; -} - -.fa-chrome:before { - content: ""; -} - -.fa-firefox:before { - content: ""; -} - -.fa-opera:before { - content: ""; -} - -.fa-internet-explorer:before { - content: ""; -} - -.fa-tv:before, -.fa-television:before { - content: ""; -} - -.fa-contao:before { - content: ""; -} - -.fa-500px:before { - content: ""; -} - -.fa-amazon:before { - content: ""; -} - -.fa-calendar-plus-o:before { - content: ""; -} - -.fa-calendar-minus-o:before { - content: ""; -} - -.fa-calendar-times-o:before { - content: ""; -} - -.fa-calendar-check-o:before { - content: ""; -} - -.fa-industry:before { - content: ""; -} - -.fa-map-pin:before { - content: ""; -} - -.fa-map-signs:before { - content: ""; -} - -.fa-map-o:before { - content: ""; -} - -.fa-map:before { - content: ""; -} - -.fa-commenting:before { - content: ""; -} - -.fa-commenting-o:before { - content: ""; -} - -.fa-houzz:before { - content: ""; -} - -.fa-vimeo:before { - content: ""; -} - -.fa-black-tie:before { - content: ""; -} - -.fa-fonticons:before { - content: ""; -} - -.fa-reddit-alien:before { - content: ""; -} - -.fa-edge:before { - content: ""; -} - -.fa-credit-card-alt:before { - content: ""; -} - -.fa-codiepie:before { - content: ""; -} - -.fa-modx:before { - content: ""; -} - -.fa-fort-awesome:before { - content: ""; -} - -.fa-usb:before { - content: ""; -} - -.fa-product-hunt:before { - content: ""; -} - -.fa-mixcloud:before { - content: ""; -} - -.fa-scribd:before { - content: ""; -} - -.fa-pause-circle:before { - content: ""; -} - -.fa-pause-circle-o:before { - content: ""; -} - -.fa-stop-circle:before { - content: ""; -} - -.fa-stop-circle-o:before { - content: ""; -} - -.fa-shopping-bag:before { - content: ""; -} - -.fa-shopping-basket:before { - content: ""; -} - -.fa-hashtag:before { - content: ""; -} - -.fa-bluetooth:before { - content: ""; -} - -.fa-bluetooth-b:before { - content: ""; -} - -.fa-percent:before { - content: ""; -} - -.fa-gitlab:before, .icon-gitlab:before { - content: ""; -} - -.fa-wpbeginner:before { - content: ""; -} - -.fa-wpforms:before { - content: ""; -} - -.fa-envira:before { - content: ""; -} - -.fa-universal-access:before { - content: ""; -} - -.fa-wheelchair-alt:before { - content: ""; -} - -.fa-question-circle-o:before { - content: ""; -} - -.fa-blind:before { - content: ""; -} - -.fa-audio-description:before { - content: ""; -} - -.fa-volume-control-phone:before { - content: ""; -} - -.fa-braille:before { - content: ""; -} - -.fa-assistive-listening-systems:before { - content: ""; -} - -.fa-asl-interpreting:before, -.fa-american-sign-language-interpreting:before { - content: ""; -} - -.fa-deafness:before, -.fa-hard-of-hearing:before, -.fa-deaf:before { - content: ""; -} - -.fa-glide:before { - content: ""; -} - -.fa-glide-g:before { - content: ""; -} - -.fa-signing:before, -.fa-sign-language:before { - content: ""; -} - -.fa-low-vision:before { - content: ""; -} - -.fa-viadeo:before { - content: ""; -} - -.fa-viadeo-square:before { - content: ""; -} - -.fa-snapchat:before { - content: ""; -} - -.fa-snapchat-ghost:before { - content: ""; -} - -.fa-snapchat-square:before { - content: ""; -} - -.fa-pied-piper:before { - content: ""; -} - -.fa-first-order:before { - content: ""; -} - -.fa-yoast:before { - content: ""; -} - -.fa-themeisle:before { - content: ""; -} - -.fa-google-plus-circle:before, -.fa-google-plus-official:before { - content: ""; -} - -.fa-fa:before, -.fa-font-awesome:before { - content: ""; -} - -.fa-handshake-o:before { - content: ""; -} - -.fa-envelope-open:before { - content: ""; -} - -.fa-envelope-open-o:before { - content: ""; -} - -.fa-linode:before { - content: ""; -} - -.fa-address-book:before { - content: ""; -} - -.fa-address-book-o:before { - content: ""; -} - -.fa-vcard:before, -.fa-address-card:before { - content: ""; -} - -.fa-vcard-o:before, -.fa-address-card-o:before { - content: ""; -} - -.fa-user-circle:before { - content: ""; -} - -.fa-user-circle-o:before { - content: ""; -} - -.fa-user-o:before { - content: ""; -} - -.fa-id-badge:before { - content: ""; -} - -.fa-drivers-license:before, -.fa-id-card:before { - content: ""; -} - -.fa-drivers-license-o:before, -.fa-id-card-o:before { - content: ""; -} - -.fa-quora:before { - content: ""; -} - -.fa-free-code-camp:before { - content: ""; -} - -.fa-telegram:before { - content: ""; -} - -.fa-thermometer-4:before, -.fa-thermometer:before, -.fa-thermometer-full:before { - content: ""; -} - -.fa-thermometer-3:before, -.fa-thermometer-three-quarters:before { - content: ""; -} - -.fa-thermometer-2:before, -.fa-thermometer-half:before { - content: ""; -} - -.fa-thermometer-1:before, -.fa-thermometer-quarter:before { - content: ""; -} - -.fa-thermometer-0:before, -.fa-thermometer-empty:before { - content: ""; -} - -.fa-shower:before { - content: ""; -} - -.fa-bathtub:before, -.fa-s15:before, -.fa-bath:before { - content: ""; -} - -.fa-podcast:before { - content: ""; -} - -.fa-window-maximize:before { - content: ""; -} - -.fa-window-minimize:before { - content: ""; -} - -.fa-window-restore:before { - content: ""; -} - -.fa-times-rectangle:before, -.fa-window-close:before { - content: ""; -} - -.fa-times-rectangle-o:before, -.fa-window-close-o:before { - content: ""; -} - -.fa-bandcamp:before { - content: ""; -} - -.fa-grav:before { - content: ""; -} - -.fa-etsy:before { - content: ""; -} - -.fa-imdb:before { - content: ""; -} - -.fa-ravelry:before { - content: ""; -} - -.fa-eercast:before { - content: ""; -} - -.fa-microchip:before { - content: ""; -} - -.fa-snowflake-o:before { - content: ""; -} - -.fa-superpowers:before { - content: ""; -} - -.fa-wpexplorer:before { - content: ""; -} - -.fa-meetup:before { - content: ""; -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} - -.fa, .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand, .rst-content .admonition-title, .rst-content h1 .headerlink, .rst-content h2 .headerlink, .rst-content h3 .headerlink, .rst-content h4 .headerlink, .rst-content h5 .headerlink, .rst-content h6 .headerlink, .rst-content dl dt .headerlink, .rst-content p.caption .headerlink, .rst-content table > caption .headerlink, .rst-content tt.download span:first-child, .rst-content code.download span:first-child, .icon, .wy-dropdown .caret, .wy-inline-validate.wy-inline-validate-success .wy-input-context, .wy-inline-validate.wy-inline-validate-danger .wy-input-context, .wy-inline-validate.wy-inline-validate-warning .wy-input-context, .wy-inline-validate.wy-inline-validate-info .wy-input-context { - font-family: inherit; -} -.fa:before, .wy-menu-vertical li span.toctree-expand:before, .wy-menu-vertical li.on a span.toctree-expand:before, .wy-menu-vertical li.current > a span.toctree-expand:before, .rst-content .admonition-title:before, .rst-content h1 .headerlink:before, .rst-content h2 .headerlink:before, .rst-content h3 .headerlink:before, .rst-content h4 .headerlink:before, .rst-content h5 .headerlink:before, .rst-content h6 .headerlink:before, .rst-content dl dt .headerlink:before, .rst-content p.caption .headerlink:before, .rst-content table > caption .headerlink:before, .rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before, .icon:before, .wy-dropdown .caret:before, .wy-inline-validate.wy-inline-validate-success .wy-input-context:before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before { - font-family: "FontAwesome"; - display: inline-block; - font-style: normal; - font-weight: normal; - line-height: 1; - text-decoration: inherit; -} - -a .fa, a .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li a span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand, a .rst-content .admonition-title, .rst-content a .admonition-title, a .rst-content h1 .headerlink, .rst-content h1 a .headerlink, a .rst-content h2 .headerlink, .rst-content h2 a .headerlink, a .rst-content h3 .headerlink, .rst-content h3 a .headerlink, a .rst-content h4 .headerlink, .rst-content h4 a .headerlink, a .rst-content h5 .headerlink, .rst-content h5 a .headerlink, a .rst-content h6 .headerlink, .rst-content h6 a .headerlink, a .rst-content dl dt .headerlink, .rst-content dl dt a .headerlink, a .rst-content p.caption .headerlink, .rst-content p.caption a .headerlink, a .rst-content table > caption .headerlink, .rst-content table > caption a .headerlink, a .rst-content tt.download span:first-child, .rst-content tt.download a span:first-child, a .rst-content code.download span:first-child, .rst-content code.download a span:first-child, a .icon { - display: inline-block; - text-decoration: inherit; -} - -.btn .fa, .btn .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .btn span.toctree-expand, .btn .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.on a .btn span.toctree-expand, .btn .wy-menu-vertical li.current > a span.toctree-expand, .wy-menu-vertical li.current > a .btn span.toctree-expand, .btn .rst-content .admonition-title, .rst-content .btn .admonition-title, .btn .rst-content h1 .headerlink, .rst-content h1 .btn .headerlink, .btn .rst-content h2 .headerlink, .rst-content h2 .btn .headerlink, .btn .rst-content h3 .headerlink, .rst-content h3 .btn .headerlink, .btn .rst-content h4 .headerlink, .rst-content h4 .btn .headerlink, .btn .rst-content h5 .headerlink, .rst-content h5 .btn .headerlink, .btn .rst-content h6 .headerlink, .rst-content h6 .btn .headerlink, .btn .rst-content dl dt .headerlink, .rst-content dl dt .btn .headerlink, .btn .rst-content p.caption .headerlink, .rst-content p.caption .btn .headerlink, .btn .rst-content table > caption .headerlink, .rst-content table > caption .btn .headerlink, .btn .rst-content tt.download span:first-child, .rst-content tt.download .btn span:first-child, .btn .rst-content code.download span:first-child, .rst-content code.download .btn span:first-child, .btn .icon, .nav .fa, .nav .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .nav span.toctree-expand, .nav .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.on a .nav span.toctree-expand, .nav .wy-menu-vertical li.current > a span.toctree-expand, .wy-menu-vertical li.current > a .nav span.toctree-expand, .nav .rst-content .admonition-title, .rst-content .nav .admonition-title, .nav .rst-content h1 .headerlink, .rst-content h1 .nav .headerlink, .nav .rst-content h2 .headerlink, .rst-content h2 .nav .headerlink, .nav .rst-content h3 .headerlink, .rst-content h3 .nav .headerlink, .nav .rst-content h4 .headerlink, .rst-content h4 .nav .headerlink, .nav .rst-content h5 .headerlink, .rst-content h5 .nav .headerlink, .nav .rst-content h6 .headerlink, .rst-content h6 .nav .headerlink, .nav .rst-content dl dt .headerlink, .rst-content dl dt .nav .headerlink, .nav .rst-content p.caption .headerlink, .rst-content p.caption .nav .headerlink, .nav .rst-content table > caption .headerlink, .rst-content table > caption .nav .headerlink, .nav .rst-content tt.download span:first-child, .rst-content tt.download .nav span:first-child, .nav .rst-content code.download span:first-child, .rst-content code.download .nav span:first-child, .nav .icon { - display: inline; -} -.btn .fa.fa-large, .btn .wy-menu-vertical li span.fa-large.toctree-expand, .wy-menu-vertical li .btn span.fa-large.toctree-expand, .btn .rst-content .fa-large.admonition-title, .rst-content .btn .fa-large.admonition-title, .btn .rst-content h1 .fa-large.headerlink, .rst-content h1 .btn .fa-large.headerlink, .btn .rst-content h2 .fa-large.headerlink, .rst-content h2 .btn .fa-large.headerlink, .btn .rst-content h3 .fa-large.headerlink, .rst-content h3 .btn .fa-large.headerlink, .btn .rst-content h4 .fa-large.headerlink, .rst-content h4 .btn .fa-large.headerlink, .btn .rst-content h5 .fa-large.headerlink, .rst-content h5 .btn .fa-large.headerlink, .btn .rst-content h6 .fa-large.headerlink, .rst-content h6 .btn .fa-large.headerlink, .btn .rst-content dl dt .fa-large.headerlink, .rst-content dl dt .btn .fa-large.headerlink, .btn .rst-content p.caption .fa-large.headerlink, .rst-content p.caption .btn .fa-large.headerlink, .btn .rst-content table > caption .fa-large.headerlink, .rst-content table > caption .btn .fa-large.headerlink, .btn .rst-content tt.download span.fa-large:first-child, .rst-content tt.download .btn span.fa-large:first-child, .btn .rst-content code.download span.fa-large:first-child, .rst-content code.download .btn span.fa-large:first-child, .btn .fa-large.icon, .nav .fa.fa-large, .nav .wy-menu-vertical li span.fa-large.toctree-expand, .wy-menu-vertical li .nav span.fa-large.toctree-expand, .nav .rst-content .fa-large.admonition-title, .rst-content .nav .fa-large.admonition-title, .nav .rst-content h1 .fa-large.headerlink, .rst-content h1 .nav .fa-large.headerlink, .nav .rst-content h2 .fa-large.headerlink, .rst-content h2 .nav .fa-large.headerlink, .nav .rst-content h3 .fa-large.headerlink, .rst-content h3 .nav .fa-large.headerlink, .nav .rst-content h4 .fa-large.headerlink, .rst-content h4 .nav .fa-large.headerlink, .nav .rst-content h5 .fa-large.headerlink, .rst-content h5 .nav .fa-large.headerlink, .nav .rst-content h6 .fa-large.headerlink, .rst-content h6 .nav .fa-large.headerlink, .nav .rst-content dl dt .fa-large.headerlink, .rst-content dl dt .nav .fa-large.headerlink, .nav .rst-content p.caption .fa-large.headerlink, .rst-content p.caption .nav .fa-large.headerlink, .nav .rst-content table > caption .fa-large.headerlink, .rst-content table > caption .nav .fa-large.headerlink, .nav .rst-content tt.download span.fa-large:first-child, .rst-content tt.download .nav span.fa-large:first-child, .nav .rst-content code.download span.fa-large:first-child, .rst-content code.download .nav span.fa-large:first-child, .nav .fa-large.icon { - line-height: 0.9em; -} -.btn .fa.fa-spin, .btn .wy-menu-vertical li span.fa-spin.toctree-expand, .wy-menu-vertical li .btn span.fa-spin.toctree-expand, .btn .rst-content .fa-spin.admonition-title, .rst-content .btn .fa-spin.admonition-title, .btn .rst-content h1 .fa-spin.headerlink, .rst-content h1 .btn .fa-spin.headerlink, .btn .rst-content h2 .fa-spin.headerlink, .rst-content h2 .btn .fa-spin.headerlink, .btn .rst-content h3 .fa-spin.headerlink, .rst-content h3 .btn .fa-spin.headerlink, .btn .rst-content h4 .fa-spin.headerlink, .rst-content h4 .btn .fa-spin.headerlink, .btn .rst-content h5 .fa-spin.headerlink, .rst-content h5 .btn .fa-spin.headerlink, .btn .rst-content h6 .fa-spin.headerlink, .rst-content h6 .btn .fa-spin.headerlink, .btn .rst-content dl dt .fa-spin.headerlink, .rst-content dl dt .btn .fa-spin.headerlink, .btn .rst-content p.caption .fa-spin.headerlink, .rst-content p.caption .btn .fa-spin.headerlink, .btn .rst-content table > caption .fa-spin.headerlink, .rst-content table > caption .btn .fa-spin.headerlink, .btn .rst-content tt.download span.fa-spin:first-child, .rst-content tt.download .btn span.fa-spin:first-child, .btn .rst-content code.download span.fa-spin:first-child, .rst-content code.download .btn span.fa-spin:first-child, .btn .fa-spin.icon, .nav .fa.fa-spin, .nav .wy-menu-vertical li span.fa-spin.toctree-expand, .wy-menu-vertical li .nav span.fa-spin.toctree-expand, .nav .rst-content .fa-spin.admonition-title, .rst-content .nav .fa-spin.admonition-title, .nav .rst-content h1 .fa-spin.headerlink, .rst-content h1 .nav .fa-spin.headerlink, .nav .rst-content h2 .fa-spin.headerlink, .rst-content h2 .nav .fa-spin.headerlink, .nav .rst-content h3 .fa-spin.headerlink, .rst-content h3 .nav .fa-spin.headerlink, .nav .rst-content h4 .fa-spin.headerlink, .rst-content h4 .nav .fa-spin.headerlink, .nav .rst-content h5 .fa-spin.headerlink, .rst-content h5 .nav .fa-spin.headerlink, .nav .rst-content h6 .fa-spin.headerlink, .rst-content h6 .nav .fa-spin.headerlink, .nav .rst-content dl dt .fa-spin.headerlink, .rst-content dl dt .nav .fa-spin.headerlink, .nav .rst-content p.caption .fa-spin.headerlink, .rst-content p.caption .nav .fa-spin.headerlink, .nav .rst-content table > caption .fa-spin.headerlink, .rst-content table > caption .nav .fa-spin.headerlink, .nav .rst-content tt.download span.fa-spin:first-child, .rst-content tt.download .nav span.fa-spin:first-child, .nav .rst-content code.download span.fa-spin:first-child, .rst-content code.download .nav span.fa-spin:first-child, .nav .fa-spin.icon { - display: inline-block; -} - -.btn.fa:before, .wy-menu-vertical li span.btn.toctree-expand:before, .rst-content .btn.admonition-title:before, .rst-content h1 .btn.headerlink:before, .rst-content h2 .btn.headerlink:before, .rst-content h3 .btn.headerlink:before, .rst-content h4 .btn.headerlink:before, .rst-content h5 .btn.headerlink:before, .rst-content h6 .btn.headerlink:before, .rst-content dl dt .btn.headerlink:before, .rst-content p.caption .btn.headerlink:before, .rst-content table > caption .btn.headerlink:before, .rst-content tt.download span.btn:first-child:before, .rst-content code.download span.btn:first-child:before, .btn.icon:before { - opacity: 0.5; - -webkit-transition: opacity 0.05s ease-in; - -moz-transition: opacity 0.05s ease-in; - transition: opacity 0.05s ease-in; -} - -.btn.fa:hover:before, .wy-menu-vertical li span.btn.toctree-expand:hover:before, .rst-content .btn.admonition-title:hover:before, .rst-content h1 .btn.headerlink:hover:before, .rst-content h2 .btn.headerlink:hover:before, .rst-content h3 .btn.headerlink:hover:before, .rst-content h4 .btn.headerlink:hover:before, .rst-content h5 .btn.headerlink:hover:before, .rst-content h6 .btn.headerlink:hover:before, .rst-content dl dt .btn.headerlink:hover:before, .rst-content p.caption .btn.headerlink:hover:before, .rst-content table > caption .btn.headerlink:hover:before, .rst-content tt.download span.btn:first-child:hover:before, .rst-content code.download span.btn:first-child:hover:before, .btn.icon:hover:before { - opacity: 1; -} - -.btn-mini .fa:before, .btn-mini .wy-menu-vertical li span.toctree-expand:before, .wy-menu-vertical li .btn-mini span.toctree-expand:before, .btn-mini .rst-content .admonition-title:before, .rst-content .btn-mini .admonition-title:before, .btn-mini .rst-content h1 .headerlink:before, .rst-content h1 .btn-mini .headerlink:before, .btn-mini .rst-content h2 .headerlink:before, .rst-content h2 .btn-mini .headerlink:before, .btn-mini .rst-content h3 .headerlink:before, .rst-content h3 .btn-mini .headerlink:before, .btn-mini .rst-content h4 .headerlink:before, .rst-content h4 .btn-mini .headerlink:before, .btn-mini .rst-content h5 .headerlink:before, .rst-content h5 .btn-mini .headerlink:before, .btn-mini .rst-content h6 .headerlink:before, .rst-content h6 .btn-mini .headerlink:before, .btn-mini .rst-content dl dt .headerlink:before, .rst-content dl dt .btn-mini .headerlink:before, .btn-mini .rst-content p.caption .headerlink:before, .rst-content p.caption .btn-mini .headerlink:before, .btn-mini .rst-content table > caption .headerlink:before, .rst-content table > caption .btn-mini .headerlink:before, .btn-mini .rst-content tt.download span:first-child:before, .rst-content tt.download .btn-mini span:first-child:before, .btn-mini .rst-content code.download span:first-child:before, .rst-content code.download .btn-mini span:first-child:before, .btn-mini .icon:before { - font-size: 14px; - vertical-align: -15%; -} - -.wy-alert, .rst-content .note, .rst-content .attention, .rst-content .caution, .rst-content .danger, .rst-content .error, .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .warning, .rst-content .seealso, .rst-content .admonition-todo, .rst-content .admonition { - padding: 12px; - line-height: 24px; - margin-bottom: 24px; - background: #e7f2fa; -} - -.wy-alert-title, .rst-content .admonition-title { - color: #fff; - font-weight: bold; - display: block; - color: #fff; - background: #6ab0de; - margin: -12px; - padding: 6px 12px; - margin-bottom: 12px; -} - -.wy-alert.wy-alert-danger, .rst-content .wy-alert-danger.note, .rst-content .wy-alert-danger.attention, .rst-content .wy-alert-danger.caution, .rst-content .danger, .rst-content .error, .rst-content .wy-alert-danger.hint, .rst-content .wy-alert-danger.important, .rst-content .wy-alert-danger.tip, .rst-content .wy-alert-danger.warning, .rst-content .wy-alert-danger.seealso, .rst-content .wy-alert-danger.admonition-todo, .rst-content .wy-alert-danger.admonition { - background: #fdf3f2; -} -.wy-alert.wy-alert-danger .wy-alert-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .danger .wy-alert-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .danger .admonition-title, .rst-content .error .admonition-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition .admonition-title { - background: #f29f97; -} - -.wy-alert.wy-alert-warning, .rst-content .wy-alert-warning.note, .rst-content .attention, .rst-content .caution, .rst-content .wy-alert-warning.danger, .rst-content .wy-alert-warning.error, .rst-content .wy-alert-warning.hint, .rst-content .wy-alert-warning.important, .rst-content .wy-alert-warning.tip, .rst-content .warning, .rst-content .wy-alert-warning.seealso, .rst-content .admonition-todo, .rst-content .wy-alert-warning.admonition { - background: #ffedcc; -} -.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { - background: #f0b37e; -} - -.wy-alert.wy-alert-info, .rst-content .note, .rst-content .wy-alert-info.attention, .rst-content .wy-alert-info.caution, .rst-content .wy-alert-info.danger, .rst-content .wy-alert-info.error, .rst-content .wy-alert-info.hint, .rst-content .wy-alert-info.important, .rst-content .wy-alert-info.tip, .rst-content .wy-alert-info.warning, .rst-content .seealso, .rst-content .wy-alert-info.admonition-todo, .rst-content .wy-alert-info.admonition { - background: #e7f2fa; -} -.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { - background: #6ab0de; -} - -.wy-alert.wy-alert-success, .rst-content .wy-alert-success.note, .rst-content .wy-alert-success.attention, .rst-content .wy-alert-success.caution, .rst-content .wy-alert-success.danger, .rst-content .wy-alert-success.error, .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .wy-alert-success.warning, .rst-content .wy-alert-success.seealso, .rst-content .wy-alert-success.admonition-todo, .rst-content .wy-alert-success.admonition { - background: #dbfaf4; -} -.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { - background: #1abc9c; -} - -.wy-alert.wy-alert-neutral, .rst-content .wy-alert-neutral.note, .rst-content .wy-alert-neutral.attention, .rst-content .wy-alert-neutral.caution, .rst-content .wy-alert-neutral.danger, .rst-content .wy-alert-neutral.error, .rst-content .wy-alert-neutral.hint, .rst-content .wy-alert-neutral.important, .rst-content .wy-alert-neutral.tip, .rst-content .wy-alert-neutral.warning, .rst-content .wy-alert-neutral.seealso, .rst-content .wy-alert-neutral.admonition-todo, .rst-content .wy-alert-neutral.admonition { - background: #f3f6f6; -} -.wy-alert.wy-alert-neutral .wy-alert-title, .rst-content .wy-alert-neutral.note .wy-alert-title, .rst-content .wy-alert-neutral.attention .wy-alert-title, .rst-content .wy-alert-neutral.caution .wy-alert-title, .rst-content .wy-alert-neutral.danger .wy-alert-title, .rst-content .wy-alert-neutral.error .wy-alert-title, .rst-content .wy-alert-neutral.hint .wy-alert-title, .rst-content .wy-alert-neutral.important .wy-alert-title, .rst-content .wy-alert-neutral.tip .wy-alert-title, .rst-content .wy-alert-neutral.warning .wy-alert-title, .rst-content .wy-alert-neutral.seealso .wy-alert-title, .rst-content .wy-alert-neutral.admonition-todo .wy-alert-title, .rst-content .wy-alert-neutral.admonition .wy-alert-title, .wy-alert.wy-alert-neutral .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-neutral .admonition-title, .rst-content .wy-alert-neutral.note .admonition-title, .rst-content .wy-alert-neutral.attention .admonition-title, .rst-content .wy-alert-neutral.caution .admonition-title, .rst-content .wy-alert-neutral.danger .admonition-title, .rst-content .wy-alert-neutral.error .admonition-title, .rst-content .wy-alert-neutral.hint .admonition-title, .rst-content .wy-alert-neutral.important .admonition-title, .rst-content .wy-alert-neutral.tip .admonition-title, .rst-content .wy-alert-neutral.warning .admonition-title, .rst-content .wy-alert-neutral.seealso .admonition-title, .rst-content .wy-alert-neutral.admonition-todo .admonition-title, .rst-content .wy-alert-neutral.admonition .admonition-title { - color: #404040; - background: #e1e4e5; -} -.wy-alert.wy-alert-neutral a, .rst-content .wy-alert-neutral.note a, .rst-content .wy-alert-neutral.attention a, .rst-content .wy-alert-neutral.caution a, .rst-content .wy-alert-neutral.danger a, .rst-content .wy-alert-neutral.error a, .rst-content .wy-alert-neutral.hint a, .rst-content .wy-alert-neutral.important a, .rst-content .wy-alert-neutral.tip a, .rst-content .wy-alert-neutral.warning a, .rst-content .wy-alert-neutral.seealso a, .rst-content .wy-alert-neutral.admonition-todo a, .rst-content .wy-alert-neutral.admonition a { - color: #60c557; -} - -.wy-alert p:last-child, .rst-content .note p:last-child, .rst-content .attention p:last-child, .rst-content .caution p:last-child, .rst-content .danger p:last-child, .rst-content .error p:last-child, .rst-content .hint p:last-child, .rst-content .important p:last-child, .rst-content .tip p:last-child, .rst-content .warning p:last-child, .rst-content .seealso p:last-child, .rst-content .admonition-todo p:last-child, .rst-content .admonition p:last-child { - margin-bottom: 0; -} - -.wy-tray-container { - position: fixed; - bottom: 0px; - left: 0; - z-index: 600; -} -.wy-tray-container li { - display: block; - width: 300px; - background: transparent; - color: #fff; - text-align: center; - box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.1); - padding: 0 24px; - min-width: 20%; - opacity: 0; - height: 0; - line-height: 56px; - overflow: hidden; - -webkit-transition: all 0.3s ease-in; - -moz-transition: all 0.3s ease-in; - transition: all 0.3s ease-in; -} -.wy-tray-container li.wy-tray-item-success { - background: #84d27d; -} -.wy-tray-container li.wy-tray-item-info { - background: #2980B9; -} -.wy-tray-container li.wy-tray-item-warning { - background: #E67E22; -} -.wy-tray-container li.wy-tray-item-danger { - background: #E74C3C; -} -.wy-tray-container li.on { - opacity: 1; - height: 56px; -} - -@media screen and (max-width: 768px) { - .wy-tray-container { - bottom: auto; - top: 0; - width: 100%; - } - .wy-tray-container li { - width: 100%; - } -} -button { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; - cursor: pointer; - line-height: normal; - -webkit-appearance: button; - *overflow: visible; -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; -} - -button[disabled] { - cursor: default; -} - -.btn { - /* Structure */ - display: inline-block; - border-radius: 2px; - line-height: normal; - white-space: nowrap; - text-align: center; - cursor: pointer; - font-size: 100%; - padding: 6px 12px 8px 12px; - color: #fff; - border: 1px solid rgba(0, 0, 0, 0.1); - background-color: #27AE60; - text-decoration: none; - font-weight: normal; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - box-shadow: 0px 1px 2px -1px rgba(255, 255, 255, 0.5) inset, 0px -2px 0px 0px rgba(0, 0, 0, 0.1) inset; - outline-none: false; - vertical-align: middle; - *display: inline; - zoom: 1; - -webkit-user-drag: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - transition: all 0.1s linear; -} - -.btn-hover { - background: #72cb6a; - color: #fff; -} - -.btn:hover { - background: #2cc36b; - color: #fff; -} -.btn:focus { - background: #2cc36b; - outline: 0; -} -.btn:active { - box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.05) inset, 0px 2px 0px 0px rgba(0, 0, 0, 0.1) inset; - padding: 8px 12px 6px 12px; -} -.btn:visited { - color: #fff; -} -.btn:disabled { - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - opacity: 0.4; - cursor: not-allowed; - box-shadow: none; -} - -.btn-disabled { - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - opacity: 0.4; - cursor: not-allowed; - box-shadow: none; -} -.btn-disabled:hover, .btn-disabled:focus, .btn-disabled:active { - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - opacity: 0.4; - cursor: not-allowed; - box-shadow: none; -} - -.btn::-moz-focus-inner { - padding: 0; - border: 0; -} - -.btn-small { - font-size: 80%; -} - -.btn-info { - background-color: #2980B9 !important; -} -.btn-info:hover { - background-color: #2e8ece !important; -} - -.btn-neutral { - background-color: #f3f6f6 !important; - color: #404040 !important; -} -.btn-neutral:hover { - background-color: #e5ebeb !important; - color: #404040; -} -.btn-neutral:visited { - color: #404040 !important; -} - -.btn-success { - background-color: #84d27d !important; -} -.btn-success:hover { - background-color: #72cb6a !important; -} - -.btn-danger { - background-color: #E74C3C !important; -} -.btn-danger:hover { - background-color: #ea6153 !important; -} - -.btn-warning { - background-color: #E67E22 !important; -} -.btn-warning:hover { - background-color: #e98b39 !important; -} - -.btn-invert { - background-color: #222; -} -.btn-invert:hover { - background-color: #2f2f2f !important; -} - -.btn-link { - background-color: transparent !important; - color: #60c557; - box-shadow: none; - border-color: transparent !important; -} -.btn-link:hover { - background-color: transparent !important; - color: #84d27d !important; - box-shadow: none; -} -.btn-link:active { - background-color: transparent !important; - color: #84d27d !important; - box-shadow: none; -} -.btn-link:visited { - color: #36872f; -} - -.wy-btn-group .btn, .wy-control .btn { - vertical-align: middle; -} - -.wy-btn-group { - margin-bottom: 24px; - *zoom: 1; -} -.wy-btn-group:before, .wy-btn-group:after { - display: table; - content: ""; -} -.wy-btn-group:after { - clear: both; -} - -.wy-dropdown { - position: relative; - display: inline-block; -} - -.wy-dropdown-active .wy-dropdown-menu { - display: block; -} - -.wy-dropdown-menu { - position: absolute; - left: 0; - display: none; - float: left; - top: 100%; - min-width: 100%; - background: #fcfcfc; - z-index: 100; - border: solid 1px #cfd7dd; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1); - padding: 12px; -} -.wy-dropdown-menu > dd > a { - display: block; - clear: both; - color: #404040; - white-space: nowrap; - font-size: 90%; - padding: 0 12px; - cursor: pointer; -} -.wy-dropdown-menu > dd > a:hover { - background: #60c557; - color: #fff; -} -.wy-dropdown-menu > dd.divider { - border-top: solid 1px #cfd7dd; - margin: 6px 0; -} -.wy-dropdown-menu > dd.search { - padding-bottom: 12px; -} -.wy-dropdown-menu > dd.search input[type="search"] { - width: 100%; -} -.wy-dropdown-menu > dd.call-to-action { - background: #e3e3e3; - text-transform: uppercase; - font-weight: 500; - font-size: 80%; -} -.wy-dropdown-menu > dd.call-to-action:hover { - background: #e3e3e3; -} -.wy-dropdown-menu > dd.call-to-action .btn { - color: #fff; -} - -.wy-dropdown.wy-dropdown-up .wy-dropdown-menu { - bottom: 100%; - top: auto; - left: auto; - right: 0; -} - -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu { - background: #fcfcfc; - margin-top: 2px; -} -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a { - padding: 6px 12px; -} -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover { - background: #60c557; - color: #fff; -} - -.wy-dropdown.wy-dropdown-left .wy-dropdown-menu { - right: 0; - left: auto; - text-align: right; -} - -.wy-dropdown-arrow:before { - content: " "; - border-bottom: 5px solid whitesmoke; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - position: absolute; - display: block; - top: -4px; - left: 50%; - margin-left: -3px; -} -.wy-dropdown-arrow.wy-dropdown-arrow-left:before { - left: 11px; -} - -.wy-form-stacked select { - display: block; -} - -.wy-form-aligned input, .wy-form-aligned textarea, .wy-form-aligned select, .wy-form-aligned .wy-help-inline, .wy-form-aligned label { - display: inline-block; - *display: inline; - *zoom: 1; - vertical-align: middle; -} - -.wy-form-aligned .wy-control-group > label { - display: inline-block; - vertical-align: middle; - width: 10em; - margin: 6px 12px 0 0; - float: left; -} -.wy-form-aligned .wy-control { - float: left; -} -.wy-form-aligned .wy-control label { - display: block; -} -.wy-form-aligned .wy-control select { - margin-top: 6px; -} - -fieldset { - border: 0; - margin: 0; - padding: 0; -} - -legend { - display: block; - width: 100%; - border: 0; - padding: 0; - white-space: normal; - margin-bottom: 24px; - font-size: 150%; - *margin-left: -7px; -} - -label { - display: block; - margin: 0 0 0.3125em 0; - color: #333; - font-size: 90%; -} - -input, select, textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; -} - -.wy-control-group { - margin-bottom: 24px; - *zoom: 1; - max-width: 68em; - margin-left: auto; - margin-right: auto; - *zoom: 1; -} -.wy-control-group:before, .wy-control-group:after { - display: table; - content: ""; -} -.wy-control-group:after { - clear: both; -} -.wy-control-group:before, .wy-control-group:after { - display: table; - content: ""; -} -.wy-control-group:after { - clear: both; -} - -.wy-control-group.wy-control-group-required > label:after { - content: " *"; - color: #E74C3C; -} - -.wy-control-group .wy-form-full, .wy-control-group .wy-form-halves, .wy-control-group .wy-form-thirds { - padding-bottom: 12px; -} -.wy-control-group .wy-form-full select, .wy-control-group .wy-form-halves select, .wy-control-group .wy-form-thirds select { - width: 100%; -} -.wy-control-group .wy-form-full input[type="text"], .wy-control-group .wy-form-full input[type="password"], .wy-control-group .wy-form-full input[type="email"], .wy-control-group .wy-form-full input[type="url"], .wy-control-group .wy-form-full input[type="date"], .wy-control-group .wy-form-full input[type="month"], .wy-control-group .wy-form-full input[type="time"], .wy-control-group .wy-form-full input[type="datetime"], .wy-control-group .wy-form-full input[type="datetime-local"], .wy-control-group .wy-form-full input[type="week"], .wy-control-group .wy-form-full input[type="number"], .wy-control-group .wy-form-full input[type="search"], .wy-control-group .wy-form-full input[type="tel"], .wy-control-group .wy-form-full input[type="color"], .wy-control-group .wy-form-halves input[type="text"], .wy-control-group .wy-form-halves input[type="password"], .wy-control-group .wy-form-halves input[type="email"], .wy-control-group .wy-form-halves input[type="url"], .wy-control-group .wy-form-halves input[type="date"], .wy-control-group .wy-form-halves input[type="month"], .wy-control-group .wy-form-halves input[type="time"], .wy-control-group .wy-form-halves input[type="datetime"], .wy-control-group .wy-form-halves input[type="datetime-local"], .wy-control-group .wy-form-halves input[type="week"], .wy-control-group .wy-form-halves input[type="number"], .wy-control-group .wy-form-halves input[type="search"], .wy-control-group .wy-form-halves input[type="tel"], .wy-control-group .wy-form-halves input[type="color"], .wy-control-group .wy-form-thirds input[type="text"], .wy-control-group .wy-form-thirds input[type="password"], .wy-control-group .wy-form-thirds input[type="email"], .wy-control-group .wy-form-thirds input[type="url"], .wy-control-group .wy-form-thirds input[type="date"], .wy-control-group .wy-form-thirds input[type="month"], .wy-control-group .wy-form-thirds input[type="time"], .wy-control-group .wy-form-thirds input[type="datetime"], .wy-control-group .wy-form-thirds input[type="datetime-local"], .wy-control-group .wy-form-thirds input[type="week"], .wy-control-group .wy-form-thirds input[type="number"], .wy-control-group .wy-form-thirds input[type="search"], .wy-control-group .wy-form-thirds input[type="tel"], .wy-control-group .wy-form-thirds input[type="color"] { - width: 100%; -} - -.wy-control-group .wy-form-full { - float: left; - display: block; - margin-right: 2.3576515979%; - width: 100%; - margin-right: 0; -} -.wy-control-group .wy-form-full:last-child { - margin-right: 0; -} - -.wy-control-group .wy-form-halves { - float: left; - display: block; - margin-right: 2.3576515979%; - width: 48.821174201%; -} -.wy-control-group .wy-form-halves:last-child { - margin-right: 0; -} -.wy-control-group .wy-form-halves:nth-of-type(2n) { - margin-right: 0; -} -.wy-control-group .wy-form-halves:nth-of-type(2n+1) { - clear: left; -} - -.wy-control-group .wy-form-thirds { - float: left; - display: block; - margin-right: 2.3576515979%; - width: 31.7615656014%; -} -.wy-control-group .wy-form-thirds:last-child { - margin-right: 0; -} -.wy-control-group .wy-form-thirds:nth-of-type(3n) { - margin-right: 0; -} -.wy-control-group .wy-form-thirds:nth-of-type(3n+1) { - clear: left; -} - -.wy-control-group.wy-control-group-no-input .wy-control { - margin: 6px 0 0 0; - font-size: 90%; -} - -.wy-control-no-input { - display: inline-block; - margin: 6px 0 0 0; - font-size: 90%; -} - -.wy-control-group.fluid-input input[type="text"], .wy-control-group.fluid-input input[type="password"], .wy-control-group.fluid-input input[type="email"], .wy-control-group.fluid-input input[type="url"], .wy-control-group.fluid-input input[type="date"], .wy-control-group.fluid-input input[type="month"], .wy-control-group.fluid-input input[type="time"], .wy-control-group.fluid-input input[type="datetime"], .wy-control-group.fluid-input input[type="datetime-local"], .wy-control-group.fluid-input input[type="week"], .wy-control-group.fluid-input input[type="number"], .wy-control-group.fluid-input input[type="search"], .wy-control-group.fluid-input input[type="tel"], .wy-control-group.fluid-input input[type="color"] { - width: 100%; -} - -.wy-form-message-inline { - display: inline-block; - padding-left: 0.3em; - color: #666; - vertical-align: middle; - font-size: 90%; -} - -.wy-form-message { - display: block; - color: #999; - font-size: 70%; - margin-top: 0.3125em; - font-style: italic; -} -.wy-form-message p { - font-size: inherit; - font-style: italic; - margin-bottom: 6px; -} -.wy-form-message p:last-child { - margin-bottom: 0; -} - -input { - line-height: normal; -} - -input[type="button"], input[type="reset"], input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - *overflow: visible; -} -input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"] { - -webkit-appearance: none; - padding: 6px; - display: inline-block; - border: 1px solid #ccc; - font-size: 80%; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - box-shadow: inset 0 1px 3px #ddd; - border-radius: 0; - -webkit-transition: border 0.3s linear; - -moz-transition: border 0.3s linear; - transition: border 0.3s linear; -} -input[type="datetime-local"] { - padding: 0.34375em 0.625em; -} -input[disabled] { - cursor: default; -} -input[type="checkbox"], input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; - margin-right: 0.3125em; - *height: 13px; - *width: 13px; -} -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus { - outline: 0; - outline: thin dotted \9; - border-color: #333; -} -input.no-focus:focus { - border-color: #ccc !important; -} -input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { - outline: thin dotted #333; - outline: 1px auto #129FEA; -} -input[type="text"][disabled], input[type="password"][disabled], input[type="email"][disabled], input[type="url"][disabled], input[type="date"][disabled], input[type="month"][disabled], input[type="time"][disabled], input[type="datetime"][disabled], input[type="datetime-local"][disabled], input[type="week"][disabled], input[type="number"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="color"][disabled] { - cursor: not-allowed; - background-color: #fafafa; -} - -input:focus:invalid, textarea:focus:invalid, select:focus:invalid { - color: #E74C3C; - border: 1px solid #E74C3C; -} - -input:focus:invalid:focus, textarea:focus:invalid:focus, select:focus:invalid:focus { - border-color: #E74C3C; -} - -input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus, input[type="checkbox"]:focus:invalid:focus { - outline-color: #E74C3C; -} - -input.wy-input-large { - padding: 12px; - font-size: 100%; -} - -textarea { - overflow: auto; - vertical-align: top; - width: 100%; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; -} - -select, textarea { - padding: 0.5em 0.625em; - display: inline-block; - border: 1px solid #ccc; - font-size: 80%; - box-shadow: inset 0 1px 3px #ddd; - -webkit-transition: border 0.3s linear; - -moz-transition: border 0.3s linear; - transition: border 0.3s linear; -} - -select { - border: 1px solid #ccc; - background-color: #fff; -} -select[multiple] { - height: auto; -} - -select:focus, textarea:focus { - outline: 0; -} - -select[disabled], textarea[disabled], input[readonly], select[readonly], textarea[readonly] { - cursor: not-allowed; - background-color: #fafafa; -} - -input[type="radio"][disabled], input[type="checkbox"][disabled] { - cursor: not-allowed; -} - -.wy-checkbox, .wy-radio { - margin: 6px 0; - color: #404040; - display: block; -} -.wy-checkbox input, .wy-radio input { - vertical-align: baseline; -} - -.wy-form-message-inline { - display: inline-block; - *display: inline; - *zoom: 1; - vertical-align: middle; -} - -.wy-input-prefix, .wy-input-suffix { - white-space: nowrap; - padding: 6px; -} -.wy-input-prefix .wy-input-context, .wy-input-suffix .wy-input-context { - line-height: 27px; - padding: 0 8px; - display: inline-block; - font-size: 80%; - background-color: #f3f6f6; - border: solid 1px #ccc; - color: #999; -} - -.wy-input-suffix .wy-input-context { - border-left: 0; -} - -.wy-input-prefix .wy-input-context { - border-right: 0; -} - -.wy-switch { - position: relative; - display: block; - height: 24px; - margin-top: 12px; - cursor: pointer; -} -.wy-switch:before { - position: absolute; - content: ""; - display: block; - left: 0; - top: 0; - width: 36px; - height: 12px; - border-radius: 4px; - background: #ccc; - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} -.wy-switch:after { - position: absolute; - content: ""; - display: block; - width: 18px; - height: 18px; - border-radius: 4px; - background: #999; - left: -3px; - top: -3px; - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} -.wy-switch span { - position: absolute; - left: 48px; - display: block; - font-size: 12px; - color: #ccc; - line-height: 1; -} - -.wy-switch.active:before { - background: #60c557; -} -.wy-switch.active:after { - left: 24px; - background: #84d27d; -} - -.wy-switch.disabled { - cursor: not-allowed; - opacity: 0.8; -} - -.wy-control-group.wy-control-group-error .wy-form-message, .wy-control-group.wy-control-group-error > label { - color: #E74C3C; -} -.wy-control-group.wy-control-group-error input[type="text"], .wy-control-group.wy-control-group-error input[type="password"], .wy-control-group.wy-control-group-error input[type="email"], .wy-control-group.wy-control-group-error input[type="url"], .wy-control-group.wy-control-group-error input[type="date"], .wy-control-group.wy-control-group-error input[type="month"], .wy-control-group.wy-control-group-error input[type="time"], .wy-control-group.wy-control-group-error input[type="datetime"], .wy-control-group.wy-control-group-error input[type="datetime-local"], .wy-control-group.wy-control-group-error input[type="week"], .wy-control-group.wy-control-group-error input[type="number"], .wy-control-group.wy-control-group-error input[type="search"], .wy-control-group.wy-control-group-error input[type="tel"], .wy-control-group.wy-control-group-error input[type="color"] { - border: solid 1px #E74C3C; -} -.wy-control-group.wy-control-group-error textarea { - border: solid 1px #E74C3C; -} - -.wy-inline-validate { - white-space: nowrap; -} -.wy-inline-validate .wy-input-context { - padding: 0.5em 0.625em; - display: inline-block; - font-size: 80%; -} - -.wy-inline-validate.wy-inline-validate-success .wy-input-context { - color: #84d27d; -} - -.wy-inline-validate.wy-inline-validate-danger .wy-input-context { - color: #E74C3C; -} - -.wy-inline-validate.wy-inline-validate-warning .wy-input-context { - color: #E67E22; -} - -.wy-inline-validate.wy-inline-validate-info .wy-input-context { - color: #2980B9; -} - -.rotate-90 { - -webkit-transform: rotate(90deg); - -moz-transform: rotate(90deg); - -ms-transform: rotate(90deg); - -o-transform: rotate(90deg); - transform: rotate(90deg); -} - -.rotate-180 { - -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); - -ms-transform: rotate(180deg); - -o-transform: rotate(180deg); - transform: rotate(180deg); -} - -.rotate-270 { - -webkit-transform: rotate(270deg); - -moz-transform: rotate(270deg); - -ms-transform: rotate(270deg); - -o-transform: rotate(270deg); - transform: rotate(270deg); -} - -.mirror { - -webkit-transform: scaleX(-1); - -moz-transform: scaleX(-1); - -ms-transform: scaleX(-1); - -o-transform: scaleX(-1); - transform: scaleX(-1); -} -.mirror.rotate-90 { - -webkit-transform: scaleX(-1) rotate(90deg); - -moz-transform: scaleX(-1) rotate(90deg); - -ms-transform: scaleX(-1) rotate(90deg); - -o-transform: scaleX(-1) rotate(90deg); - transform: scaleX(-1) rotate(90deg); -} -.mirror.rotate-180 { - -webkit-transform: scaleX(-1) rotate(180deg); - -moz-transform: scaleX(-1) rotate(180deg); - -ms-transform: scaleX(-1) rotate(180deg); - -o-transform: scaleX(-1) rotate(180deg); - transform: scaleX(-1) rotate(180deg); -} -.mirror.rotate-270 { - -webkit-transform: scaleX(-1) rotate(270deg); - -moz-transform: scaleX(-1) rotate(270deg); - -ms-transform: scaleX(-1) rotate(270deg); - -o-transform: scaleX(-1) rotate(270deg); - transform: scaleX(-1) rotate(270deg); -} - -@media only screen and (max-width: 480px) { - .wy-form button[type="submit"] { - margin: 0.7em 0 0; - } - .wy-form input[type="text"], .wy-form input[type="password"], .wy-form input[type="email"], .wy-form input[type="url"], .wy-form input[type="date"], .wy-form input[type="month"], .wy-form input[type="time"], .wy-form input[type="datetime"], .wy-form input[type="datetime-local"], .wy-form input[type="week"], .wy-form input[type="number"], .wy-form input[type="search"], .wy-form input[type="tel"], .wy-form input[type="color"] { - margin-bottom: 0.3em; - display: block; - } - .wy-form label { - margin-bottom: 0.3em; - display: block; - } - - .wy-form input[type="password"], .wy-form input[type="email"], .wy-form input[type="url"], .wy-form input[type="date"], .wy-form input[type="month"], .wy-form input[type="time"], .wy-form input[type="datetime"], .wy-form input[type="datetime-local"], .wy-form input[type="week"], .wy-form input[type="number"], .wy-form input[type="search"], .wy-form input[type="tel"], .wy-form input[type="color"] { - margin-bottom: 0; - } - - .wy-form-aligned .wy-control-group label { - margin-bottom: 0.3em; - text-align: left; - display: block; - width: 100%; - } - .wy-form-aligned .wy-control { - margin: 1.5em 0 0 0; - } - - .wy-form .wy-help-inline, .wy-form-message-inline, .wy-form-message { - display: block; - font-size: 80%; - padding: 6px 0; - } -} -@media screen and (max-width: 768px) { - .tablet-hide { - display: none; - } -} - -@media screen and (max-width: 480px) { - .mobile-hide { - display: none; - } -} - -.float-left { - float: left; -} - -.float-right { - float: right; -} - -.full-width { - width: 100%; -} - -.wy-table, .rst-content table.docutils, .rst-content table.field-list { - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; - margin-bottom: 24px; -} -.wy-table caption, .rst-content table.docutils caption, .rst-content table.field-list caption { - color: #000; - font: italic 85%/1 arial, sans-serif; - padding: 1em 0; - text-align: center; -} -.wy-table td, .rst-content table.docutils td, .rst-content table.field-list td, .wy-table th, .rst-content table.docutils th, .rst-content table.field-list th { - font-size: 90%; - margin: 0; - overflow: visible; - padding: 8px 16px; -} -.wy-table td:first-child, .rst-content table.docutils td:first-child, .rst-content table.field-list td:first-child, .wy-table th:first-child, .rst-content table.docutils th:first-child, .rst-content table.field-list th:first-child { - border-left-width: 0; -} -.wy-table thead, .rst-content table.docutils thead, .rst-content table.field-list thead { - color: #000; - text-align: left; - vertical-align: bottom; - white-space: nowrap; -} -.wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th { - font-weight: bold; - border-bottom: solid 2px #e1e4e5; -} -.wy-table td, .rst-content table.docutils td, .rst-content table.field-list td { - background-color: transparent; - vertical-align: middle; -} - -.wy-table td p, .rst-content table.docutils td p, .rst-content table.field-list td p { - line-height: 18px; -} -.wy-table td p:last-child, .rst-content table.docutils td p:last-child, .rst-content table.field-list td p:last-child { - margin-bottom: 0; -} - -.wy-table .wy-table-cell-min, .rst-content table.docutils .wy-table-cell-min, .rst-content table.field-list .wy-table-cell-min { - width: 1%; - padding-right: 0; -} -.wy-table .wy-table-cell-min input[type=checkbox], .rst-content table.docutils .wy-table-cell-min input[type=checkbox], .rst-content table.field-list .wy-table-cell-min input[type=checkbox], .wy-table .wy-table-cell-min input[type=checkbox], .rst-content table.docutils .wy-table-cell-min input[type=checkbox], .rst-content table.field-list .wy-table-cell-min input[type=checkbox] { - margin: 0; -} - -.wy-table-secondary { - color: gray; - font-size: 90%; -} - -.wy-table-tertiary { - color: gray; - font-size: 80%; -} - -.wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { - background-color: #f3f6f6; -} - -.wy-table-backed { - background-color: #f3f6f6; -} - -/* BORDERED TABLES */ -.wy-table-bordered-all, .rst-content table.docutils { - border: 1px solid #e1e4e5; -} -.wy-table-bordered-all td, .rst-content table.docutils td { - border-bottom: 1px solid #e1e4e5; - border-left: 1px solid #e1e4e5; -} -.wy-table-bordered-all tbody > tr:last-child td, .rst-content table.docutils tbody > tr:last-child td { - border-bottom-width: 0; -} - -.wy-table-bordered { - border: 1px solid #e1e4e5; -} - -.wy-table-bordered-rows td { - border-bottom: 1px solid #e1e4e5; -} -.wy-table-bordered-rows tbody > tr:last-child td { - border-bottom-width: 0; -} - -.wy-table-horizontal tbody > tr:last-child td { - border-bottom-width: 0; -} -.wy-table-horizontal td, .wy-table-horizontal th { - border-width: 0 0 1px 0; - border-bottom: 1px solid #e1e4e5; -} -.wy-table-horizontal tbody > tr:last-child td { - border-bottom-width: 0; -} - -/* RESPONSIVE TABLES */ -.wy-table-responsive { - margin-bottom: 24px; - max-width: 100%; - overflow: auto; -} -.wy-table-responsive table { - margin-bottom: 0 !important; -} -.wy-table-responsive table td, .wy-table-responsive table th { - white-space: nowrap; -} - -a { - color: #60c557; - text-decoration: none; - cursor: pointer; -} -a:hover { - color: #84d27d; -} -a:visited { - color: #36872f; -} - -html { - height: 100%; - overflow-x: hidden; -} - -body { - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - font-weight: normal; - color: #404040; - min-height: 100%; - overflow-x: hidden; - background: #edf0f2; -} - -.wy-text-left { - text-align: left; -} - -.wy-text-center { - text-align: center; -} - -.wy-text-right { - text-align: right; -} - -.wy-text-large { - font-size: 120%; -} - -.wy-text-normal { - font-size: 100%; -} - -.wy-text-small, small { - font-size: 80%; -} - -.wy-text-strike { - text-decoration: line-through; -} - -.wy-text-warning { - color: #E67E22 !important; -} - -a.wy-text-warning:hover { - color: #eb9950 !important; -} - -.wy-text-info { - color: #2980B9 !important; -} - -a.wy-text-info:hover { - color: #409ad5 !important; -} - -.wy-text-success { - color: #84d27d !important; -} - -a.wy-text-success:hover { - color: #a8dfa3 !important; -} - -.wy-text-danger { - color: #E74C3C !important; -} - -a.wy-text-danger:hover { - color: #ed7669 !important; -} - -.wy-text-neutral { - color: #404040 !important; -} - -a.wy-text-neutral:hover { - color: #595959 !important; -} - -h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend { - margin-top: 0; - font-weight: 700; - font-family: "Roboto Slab", "ff-tisa-web-pro", "Georgia", Arial, sans-serif; -} - -p { - line-height: 24px; - margin: 0; - font-size: 16px; - margin-bottom: 24px; -} - -h1 { - font-size: 175%; -} - -h2, .rst-content .toctree-wrapper p.caption { - font-size: 150%; -} - -h3 { - font-size: 125%; -} - -h4 { - font-size: 115%; -} - -h5 { - font-size: 110%; -} - -h6 { - font-size: 100%; -} - -hr { - display: block; - height: 1px; - border: 0; - border-top: 1px solid #e1e4e5; - margin: 24px 0; - padding: 0; -} - -code, .rst-content tt, .rst-content code { - white-space: nowrap; - max-width: 100%; - background: #fff; - border: solid 1px #e1e4e5; - font-size: 75%; - padding: 0 5px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; - color: #E74C3C; - overflow-x: auto; -} -code.code-large, .rst-content tt.code-large { - font-size: 90%; -} - -.wy-plain-list-disc, .rst-content .section ul, .rst-content .toctree-wrapper ul, article ul { - list-style: disc; - line-height: 24px; - margin-bottom: 24px; -} -.wy-plain-list-disc li, .rst-content .section ul li, .rst-content .toctree-wrapper ul li, article ul li { - list-style: disc; - margin-left: 24px; -} -.wy-plain-list-disc li p:last-child, .rst-content .section ul li p:last-child, .rst-content .toctree-wrapper ul li p:last-child, article ul li p:last-child { - margin-bottom: 0; -} -.wy-plain-list-disc li ul, .rst-content .section ul li ul, .rst-content .toctree-wrapper ul li ul, article ul li ul { - margin-bottom: 0; -} -.wy-plain-list-disc li li, .rst-content .section ul li li, .rst-content .toctree-wrapper ul li li, article ul li li { - list-style: circle; -} -.wy-plain-list-disc li li li, .rst-content .section ul li li li, .rst-content .toctree-wrapper ul li li li, article ul li li li { - list-style: square; -} -.wy-plain-list-disc li ol li, .rst-content .section ul li ol li, .rst-content .toctree-wrapper ul li ol li, article ul li ol li { - list-style: decimal; -} - -.wy-plain-list-decimal, .rst-content .section ol, .rst-content ol.arabic, article ol { - list-style: decimal; - line-height: 24px; - margin-bottom: 24px; -} -.wy-plain-list-decimal li, .rst-content .section ol li, .rst-content ol.arabic li, article ol li { - list-style: decimal; - margin-left: 24px; -} -.wy-plain-list-decimal li p:last-child, .rst-content .section ol li p:last-child, .rst-content ol.arabic li p:last-child, article ol li p:last-child { - margin-bottom: 0; -} -.wy-plain-list-decimal li ul, .rst-content .section ol li ul, .rst-content ol.arabic li ul, article ol li ul { - margin-bottom: 0; -} -.wy-plain-list-decimal li ul li, .rst-content .section ol li ul li, .rst-content ol.arabic li ul li, article ol li ul li { - list-style: disc; -} - -.wy-breadcrumbs { - *zoom: 1; -} -.wy-breadcrumbs:before, .wy-breadcrumbs:after { - display: table; - content: ""; -} -.wy-breadcrumbs:after { - clear: both; -} - -.wy-breadcrumbs li { - display: inline-block; -} -.wy-breadcrumbs li.wy-breadcrumbs-aside { - float: right; -} -.wy-breadcrumbs li a { - display: inline-block; - padding: 5px; -} -.wy-breadcrumbs li a:first-child { - padding-left: 0; -} -.wy-breadcrumbs li code, .wy-breadcrumbs li .rst-content tt, .rst-content .wy-breadcrumbs li tt { - padding: 5px; - border: none; - background: none; -} -.wy-breadcrumbs li code.literal, .wy-breadcrumbs li .rst-content tt.literal, .rst-content .wy-breadcrumbs li tt.literal { - color: #404040; -} - -.wy-breadcrumbs-extra { - margin-bottom: 0; - color: #b3b3b3; - font-size: 80%; - display: inline-block; -} - -@media screen and (max-width: 480px) { - .wy-breadcrumbs-extra { - display: none; - } - - .wy-breadcrumbs li.wy-breadcrumbs-aside { - display: none; - } -} -@media print { - .wy-breadcrumbs li.wy-breadcrumbs-aside { - display: none; - } -} -.wy-affix { - position: fixed; - top: 1.618em; -} - -.wy-menu a:hover { - text-decoration: none; -} - -.wy-menu-horiz { - *zoom: 1; -} -.wy-menu-horiz:before, .wy-menu-horiz:after { - display: table; - content: ""; -} -.wy-menu-horiz:after { - clear: both; -} -.wy-menu-horiz ul, .wy-menu-horiz li { - display: inline-block; -} -.wy-menu-horiz li:hover { - background: rgba(255, 255, 255, 0.1); -} -.wy-menu-horiz li.divide-left { - border-left: solid 1px #404040; -} -.wy-menu-horiz li.divide-right { - border-right: solid 1px #404040; -} -.wy-menu-horiz a { - height: 32px; - display: inline-block; - line-height: 32px; - padding: 0 16px; -} - -.wy-menu-vertical { - width: 300px; -} -.wy-menu-vertical header, .wy-menu-vertical p.caption { - height: 32px; - display: inline-block; - line-height: 32px; - padding: 0 1.618em; - margin-bottom: 0; - display: block; - font-weight: bold; - text-transform: uppercase; - font-size: 80%; - color: #6f6f6f; - white-space: nowrap; -} -.wy-menu-vertical ul { - margin-bottom: 0; -} -.wy-menu-vertical li.divide-top { - border-top: solid 1px #404040; -} -.wy-menu-vertical li.divide-bottom { - border-bottom: solid 1px #404040; -} -.wy-menu-vertical li.current { - background: #e3e3e3; -} -.wy-menu-vertical li.current a { - color: gray; - border-right: solid 1px #c9c9c9; - padding: 0.4045em 2.427em; -} -.wy-menu-vertical li.current a:hover { - background: #d6d6d6; -} -.wy-menu-vertical li code, .wy-menu-vertical li .rst-content tt, .rst-content .wy-menu-vertical li tt { - border: none; - background: inherit; - color: inherit; - padding-left: 0; - padding-right: 0; -} -.wy-menu-vertical li span.toctree-expand { - display: block; - float: left; - margin-left: -1.2em; - font-size: 0.8em; - line-height: 1.6em; - color: #4d4d4d; -} -.wy-menu-vertical li.on a, .wy-menu-vertical li.current > a { - color: #404040; - padding: 0.4045em 1.618em; - font-weight: bold; - position: relative; - background: #fcfcfc; - border: none; - padding-left: 1.618em -4px; -} -.wy-menu-vertical li.on a:hover, .wy-menu-vertical li.current > a:hover { - background: #fcfcfc; -} -.wy-menu-vertical li.on a:hover span.toctree-expand, .wy-menu-vertical li.current > a:hover span.toctree-expand { - color: gray; -} -.wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand { - display: block; - font-size: 0.8em; - line-height: 1.6em; - color: #333333; -} -.wy-menu-vertical li.toctree-l1.current > a { - border-bottom: solid 1px #c9c9c9; - border-top: solid 1px #c9c9c9; -} -.wy-menu-vertical li.toctree-l1.current li.toctree-l2 > ul, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > ul { - display: none; -} -.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current > ul, .wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > ul { - display: block; -} -.wy-menu-vertical li.toctree-l2.current > a { - background: #c9c9c9; - padding: 0.4045em 2.427em; -} -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a { - display: block; - background: #c9c9c9; - padding: 0.4045em 4.045em; -} -.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand { - color: gray; -} -.wy-menu-vertical li.toctree-l2 span.toctree-expand { - color: #a3a3a3; -} -.wy-menu-vertical li.toctree-l3 { - font-size: 0.9em; -} -.wy-menu-vertical li.toctree-l3.current > a { - background: #bdbdbd; - padding: 0.4045em 4.045em; -} -.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a { - display: block; - background: #bdbdbd; - padding: 0.4045em 5.663em; -} -.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand { - color: gray; -} -.wy-menu-vertical li.toctree-l3 span.toctree-expand { - color: #969696; -} -.wy-menu-vertical li.toctree-l4 { - font-size: 0.9em; -} -.wy-menu-vertical li.current ul { - display: block; -} -.wy-menu-vertical li ul { - margin-bottom: 0; - display: none; -} -.wy-menu-vertical .local-toc li ul { - display: block; -} -.wy-menu-vertical li ul li a { - margin-bottom: 0; - color: #b3b3b3; - font-weight: normal; -} -.wy-menu-vertical a { - display: inline-block; - line-height: 18px; - padding: 0.4045em 1.618em; - display: block; - position: relative; - font-size: 90%; - color: #b3b3b3; -} -.wy-menu-vertical a:hover { - background-color: #4e4a4a; - cursor: pointer; -} -.wy-menu-vertical a:hover span.toctree-expand { - color: #b3b3b3; -} -.wy-menu-vertical a:active { - background-color: #2980B9; - cursor: pointer; - color: #fff; -} -.wy-menu-vertical a:active span.toctree-expand { - color: #fff; -} - -.wy-side-nav-search { - display: block; - width: 300px; - padding: 0.809em; - margin-bottom: 0.809em; - z-index: 200; - background-color: #484848; - text-align: center; - padding: 0.809em; - display: block; - color: #fcfcfc; - margin-bottom: 0.809em; -} -.wy-side-nav-search input[type=text] { - width: 100%; - border-radius: 50px; - padding: 6px 12px; - border-color: #4ebe44; -} -.wy-side-nav-search img { - display: block; - margin: auto auto 0.809em auto; - height: 45px; - width: 45px; - background-color: #2980B9; - padding: 5px; - border-radius: 100%; -} -.wy-side-nav-search > a, .wy-side-nav-search .wy-dropdown > a { - color: #fcfcfc; - font-size: 100%; - font-weight: bold; - display: inline-block; - padding: 4px 6px; - margin-bottom: 0.809em; -} -.wy-side-nav-search > a:hover, .wy-side-nav-search .wy-dropdown > a:hover { - background: rgba(255, 255, 255, 0.1); -} -.wy-side-nav-search > a img.logo, .wy-side-nav-search .wy-dropdown > a img.logo { - display: block; - margin: 0 auto; - height: auto; - width: auto; - border-radius: 0; - max-width: 100%; - background: rgba(0, 0, 0, 0); -} -.wy-side-nav-search > a.icon img.logo, .wy-side-nav-search .wy-dropdown > a.icon img.logo { - margin-top: 0.85em; -} -.wy-side-nav-search > div.version { - margin-top: -0.4045em; - margin-bottom: 0.809em; - font-weight: normal; - color: rgba(255, 255, 255, 0.3); -} - -.wy-nav .wy-menu-vertical header { - color: #60c557; -} -.wy-nav .wy-menu-vertical a { - color: #b3b3b3; -} -.wy-nav .wy-menu-vertical a:hover { - background-color: #60c557; - color: #fff; -} - -[data-menu-wrap] { - -webkit-transition: all 0.2s ease-in; - -moz-transition: all 0.2s ease-in; - transition: all 0.2s ease-in; - position: absolute; - opacity: 1; - width: 100%; - opacity: 0; -} -[data-menu-wrap].move-center { - left: 0; - right: auto; - opacity: 1; -} -[data-menu-wrap].move-left { - right: auto; - left: -100%; - opacity: 0; -} -[data-menu-wrap].move-right { - right: -100%; - left: auto; - opacity: 0; -} - -.wy-body-for-nav { - background: #fcfcfc; -} - -.wy-grid-for-nav { - position: absolute; - width: 100%; - height: 100%; -} - -.wy-nav-side { - position: fixed; - top: 0; - bottom: 0; - left: 0; - padding-bottom: 2em; - width: 300px; - overflow-x: hidden; - overflow-y: hidden; - min-height: 100%; - background: #343131; - z-index: 200; -} - -.wy-side-scroll { - width: 320px; - position: relative; - overflow-x: hidden; - overflow-y: scroll; - height: 100%; -} - -.wy-nav-top { - display: none; - background: #60c557; - color: #fff; - padding: 0.4045em 0.809em; - position: relative; - line-height: 50px; - text-align: center; - font-size: 100%; - *zoom: 1; -} -.wy-nav-top:before, .wy-nav-top:after { - display: table; - content: ""; -} -.wy-nav-top:after { - clear: both; -} -.wy-nav-top a { - color: #fff; - font-weight: bold; -} -.wy-nav-top img { - margin-right: 12px; - height: 45px; - width: 45px; - background-color: #2980B9; - padding: 5px; - border-radius: 100%; -} -.wy-nav-top i { - font-size: 30px; - float: left; - cursor: pointer; - padding-top: inherit; -} - -.wy-nav-content-wrap { - margin-left: 300px; - background: #fcfcfc; - min-height: 100%; -} - -.wy-nav-content { - padding: 1.618em 3.236em; - height: 100%; - max-width: 800px; - margin: auto; -} - -.wy-body-mask { - position: fixed; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.2); - display: none; - z-index: 499; -} -.wy-body-mask.on { - display: block; -} - -footer { - color: gray; -} -footer p { - margin-bottom: 12px; -} -footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { - padding: 0px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; - font-size: 1em; - background: none; - border: none; - color: gray; -} - -.rst-footer-buttons { - *zoom: 1; -} -.rst-footer-buttons:before, .rst-footer-buttons:after { - width: 100%; -} -.rst-footer-buttons:before, .rst-footer-buttons:after { - display: table; - content: ""; -} -.rst-footer-buttons:after { - clear: both; -} - -.rst-breadcrumbs-buttons { - margin-top: 12px; - *zoom: 1; -} -.rst-breadcrumbs-buttons:before, .rst-breadcrumbs-buttons:after { - display: table; - content: ""; -} -.rst-breadcrumbs-buttons:after { - clear: both; -} - -#search-results .search li { - margin-bottom: 24px; - border-bottom: solid 1px #e1e4e5; - padding-bottom: 24px; -} -#search-results .search li:first-child { - border-top: solid 1px #e1e4e5; - padding-top: 24px; -} -#search-results .search li a { - font-size: 120%; - margin-bottom: 12px; - display: inline-block; -} -#search-results .context { - color: gray; - font-size: 90%; -} - -@media screen and (max-width: 768px) { - .wy-body-for-nav { - background: #fcfcfc; - } - - .wy-nav-top { - display: block; - } - - .wy-nav-side { - left: -300px; - } - .wy-nav-side.shift { - width: 85%; - left: 0; - } - - .wy-side-scroll { - width: auto; - } - - .wy-side-nav-search { - width: auto; - } - - .wy-menu.wy-menu-vertical { - width: auto; - } - - .wy-nav-content-wrap { - margin-left: 0; - } - .wy-nav-content-wrap .wy-nav-content { - padding: 1.618em; - } - .wy-nav-content-wrap.shift { - position: fixed; - min-width: 100%; - left: 85%; - top: 0; - height: 100%; - overflow: hidden; - } -} -@media screen and (min-width: 1100px) { - .wy-nav-content-wrap { - background: rgba(0, 0, 0, 0.05); - } - - .wy-nav-content { - margin: 0; - background: #fcfcfc; - } -} -@media print { - .rst-versions, footer, .wy-nav-side { - display: none; - } - - .wy-nav-content-wrap { - margin-left: 0; - } -} -.rst-versions { - position: fixed; - bottom: 0; - left: 0; - overflow-y: scroll; - width: 300px; - color: #fcfcfc; - background: #1f1d1d; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - z-index: 400; -} -.rst-versions a { - color: #60c557; - text-decoration: none; -} -.rst-versions .rst-badge-small { - display: none; -} -.rst-versions .rst-current-version { - padding: 12px; - background-color: #272525; - display: block; - text-align: right; - font-size: 90%; - cursor: pointer; - color: #84d27d; - *zoom: 1; -} -.rst-versions .rst-current-version:before, .rst-versions .rst-current-version:after { - display: table; - content: ""; -} -.rst-versions .rst-current-version:after { - clear: both; -} -.rst-versions .rst-current-version .fa, .rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand, .rst-versions .rst-current-version .rst-content .admonition-title, .rst-content .rst-versions .rst-current-version .admonition-title, .rst-versions .rst-current-version .rst-content h1 .headerlink, .rst-content h1 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h2 .headerlink, .rst-content h2 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h3 .headerlink, .rst-content h3 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h4 .headerlink, .rst-content h4 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h5 .headerlink, .rst-content h5 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h6 .headerlink, .rst-content h6 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content dl dt .headerlink, .rst-content dl dt .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content p.caption .headerlink, .rst-content p.caption .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content table > caption .headerlink, .rst-content table > caption .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content tt.download span:first-child, .rst-content tt.download .rst-versions .rst-current-version span:first-child, .rst-versions .rst-current-version .rst-content code.download span:first-child, .rst-content code.download .rst-versions .rst-current-version span:first-child, .rst-versions .rst-current-version .icon { - color: #fcfcfc; -} -.rst-versions .rst-current-version .fa-book, .rst-versions .rst-current-version .icon-book { - float: left; -} -.rst-versions .rst-current-version .icon-book { - float: left; -} -.rst-versions .rst-current-version.rst-out-of-date { - background-color: #E74C3C; - color: #fff; -} -.rst-versions .rst-current-version.rst-active-old-version { - background-color: #F1C40F; - color: #000; -} -.rst-versions.shift-up { - max-height: 100%; -} -.rst-versions.shift-up .rst-other-versions { - display: block; -} -.rst-versions .rst-other-versions { - font-size: 90%; - padding: 12px; - color: gray; - display: none; -} -.rst-versions .rst-other-versions hr { - display: block; - height: 1px; - border: 0; - margin: 20px 0; - padding: 0; - border-top: solid 1px #413d3d; -} -.rst-versions .rst-other-versions dd { - display: inline-block; - margin: 0; -} -.rst-versions .rst-other-versions dd a { - display: inline-block; - padding: 6px; - color: #fcfcfc; -} -.rst-versions.rst-badge { - width: auto; - bottom: 20px; - right: 20px; - left: auto; - border: none; - max-width: 300px; -} -.rst-versions.rst-badge .icon-book { - float: none; -} -.rst-versions.rst-badge .fa-book, .rst-versions.rst-badge .icon-book { - float: none; -} -.rst-versions.rst-badge.shift-up .rst-current-version { - text-align: right; -} -.rst-versions.rst-badge.shift-up .rst-current-version .fa-book, .rst-versions.rst-badge.shift-up .rst-current-version .icon-book { - float: left; -} -.rst-versions.rst-badge.shift-up .rst-current-version .icon-book { - float: left; -} -.rst-versions.rst-badge .rst-current-version { - width: auto; - height: 30px; - line-height: 30px; - padding: 0 6px; - display: block; - text-align: center; -} - -@media screen and (max-width: 768px) { - .rst-versions { - width: 85%; - display: none; - } - .rst-versions.shift { - display: block; - } -} -.rst-content img { - max-width: 100%; - height: auto; -} -.rst-content div.figure { - margin-bottom: 24px; -} -.rst-content div.figure p.caption { - font-style: italic; -} -.rst-content div.figure p:last-child.caption { - margin-bottom: 0px; -} -.rst-content div.figure.align-center { - text-align: center; -} -.rst-content .section > img, .rst-content .section > a > img { - margin-bottom: 24px; -} -.rst-content abbr[title] { - text-decoration: none; -} -.rst-content.style-external-links a.reference.external:after { - font-family: FontAwesome; - content: ""; - color: #b3b3b3; - vertical-align: super; - font-size: 60%; - margin: 0 0.2em; -} -.rst-content blockquote { - margin-left: 24px; - line-height: 24px; - margin-bottom: 24px; -} -.rst-content pre.literal-block, .rst-content div[class^='highlight'] { - border: 1px solid #e1e4e5; - padding: 0px; - overflow-x: auto; - margin: 1px 0 24px 0; -} -.rst-content pre.literal-block div[class^='highlight'], .rst-content div[class^='highlight'] div[class^='highlight'] { - border: none; - margin: 0; -} -.rst-content div[class^='highlight'] td.code { - width: 100%; -} -.rst-content .linenodiv pre { - border-right: solid 1px #e6e9ea; - margin: 0; - padding: 12px 12px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; -} -.rst-content div[class^='highlight'] pre { - white-space: pre; - margin: 0; - padding: 12px 12px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; - display: block; - overflow: auto; -} -.rst-content pre.literal-block, .rst-content div[class^='highlight'] pre, .rst-content .linenodiv pre { - font-size: 12px; - line-height: normal; -} -@media print { - .rst-content .codeblock, .rst-content div[class^='highlight'], .rst-content div[class^='highlight'] pre { - white-space: pre-wrap; - } -} -.rst-content .note .last, .rst-content .attention .last, .rst-content .caution .last, .rst-content .danger .last, .rst-content .error .last, .rst-content .hint .last, .rst-content .important .last, .rst-content .tip .last, .rst-content .warning .last, .rst-content .seealso .last, .rst-content .admonition-todo .last, .rst-content .admonition .last { - margin-bottom: 0; -} -.rst-content .admonition-title:before { - margin-right: 4px; -} -.rst-content .admonition table { - border-color: rgba(0, 0, 0, 0.1); -} -.rst-content .admonition table td, .rst-content .admonition table th { - background: transparent !important; - border-color: rgba(0, 0, 0, 0.1) !important; -} -.rst-content .section ol.loweralpha, .rst-content .section ol.loweralpha li { - list-style: lower-alpha; -} -.rst-content .section ol.upperalpha, .rst-content .section ol.upperalpha li { - list-style: upper-alpha; -} -.rst-content .section ol p, .rst-content .section ul p { - margin-bottom: 12px; -} -.rst-content .line-block { - margin-left: 0px; - margin-bottom: 24px; -} -.rst-content .line-block .line-block { - margin-left: 24px; - margin-bottom: 0px; -} -.rst-content .topic-title { - font-weight: bold; - margin-bottom: 12px; -} -.rst-content .toc-backref { - color: #404040; -} -.rst-content .align-right { - float: right; - margin: 0px 0px 24px 24px; -} -.rst-content .align-left { - float: left; - margin: 0px 24px 24px 0px; -} -.rst-content .align-center { - margin: auto; - display: block; -} -.rst-content h1 .headerlink, .rst-content h2 .headerlink, .rst-content .toctree-wrapper p.caption .headerlink, .rst-content h3 .headerlink, .rst-content h4 .headerlink, .rst-content h5 .headerlink, .rst-content h6 .headerlink, .rst-content dl dt .headerlink, .rst-content p.caption .headerlink, .rst-content table > caption .headerlink { - visibility: hidden; - font-size: 14px; -} -.rst-content h1 .headerlink:after, .rst-content h2 .headerlink:after, .rst-content .toctree-wrapper p.caption .headerlink:after, .rst-content h3 .headerlink:after, .rst-content h4 .headerlink:after, .rst-content h5 .headerlink:after, .rst-content h6 .headerlink:after, .rst-content dl dt .headerlink:after, .rst-content p.caption .headerlink:after, .rst-content table > caption .headerlink:after { - content: ""; - font-family: FontAwesome; -} -.rst-content h1:hover .headerlink:after, .rst-content h2:hover .headerlink:after, .rst-content .toctree-wrapper p.caption:hover .headerlink:after, .rst-content h3:hover .headerlink:after, .rst-content h4:hover .headerlink:after, .rst-content h5:hover .headerlink:after, .rst-content h6:hover .headerlink:after, .rst-content dl dt:hover .headerlink:after, .rst-content p.caption:hover .headerlink:after, .rst-content table > caption:hover .headerlink:after { - visibility: visible; -} -.rst-content table > caption .headerlink:after { - font-size: 12px; -} -.rst-content .centered { - text-align: center; -} -.rst-content .sidebar { - float: right; - width: 40%; - display: block; - margin: 0 0 24px 24px; - padding: 24px; - background: #f3f6f6; - border: solid 1px #e1e4e5; -} -.rst-content .sidebar p, .rst-content .sidebar ul, .rst-content .sidebar dl { - font-size: 90%; -} -.rst-content .sidebar .last { - margin-bottom: 0; -} -.rst-content .sidebar .sidebar-title { - display: block; - font-family: "Roboto Slab", "ff-tisa-web-pro", "Georgia", Arial, sans-serif; - font-weight: bold; - background: #e1e4e5; - padding: 6px 12px; - margin: -24px; - margin-bottom: 24px; - font-size: 100%; -} -.rst-content .highlighted { - background: #F1C40F; - display: inline-block; - font-weight: bold; - padding: 0 6px; -} -.rst-content .footnote-reference, .rst-content .citation-reference { - vertical-align: baseline; - position: relative; - top: -0.4em; - line-height: 0; - font-size: 90%; -} -.rst-content table.docutils.citation, .rst-content table.docutils.footnote { - background: none; - border: none; - color: gray; -} -.rst-content table.docutils.citation td, .rst-content table.docutils.citation tr, .rst-content table.docutils.footnote td, .rst-content table.docutils.footnote tr { - border: none; - background-color: transparent !important; - white-space: normal; -} -.rst-content table.docutils.citation td.label, .rst-content table.docutils.footnote td.label { - padding-left: 0; - padding-right: 0; - vertical-align: top; -} -.rst-content table.docutils.citation tt, .rst-content table.docutils.citation code, .rst-content table.docutils.footnote tt, .rst-content table.docutils.footnote code { - color: #555; -} -.rst-content .wy-table-responsive.citation, .rst-content .wy-table-responsive.footnote { - margin-bottom: 0; -} -.rst-content .wy-table-responsive.citation + :not(.citation), -.rst-content .wy-table-responsive.footnote + :not(.footnote) { - margin-top: 24px; -} -.rst-content .wy-table-responsive.citation:last-child, .rst-content .wy-table-responsive.footnote:last-child { - margin-bottom: 24px; -} -.rst-content table.field-list { - border: none; -} -.rst-content table.field-list td { - border: none; -} -.rst-content table.field-list td > strong { - display: inline-block; -} -.rst-content table.field-list .field-name { - padding-right: 10px; - text-align: left; - white-space: nowrap; -} -.rst-content table.field-list .field-body { - text-align: left; -} -.rst-content tt, .rst-content tt, .rst-content code { - color: #000; - padding: 2px 5px; -} -.rst-content tt big, .rst-content tt em, .rst-content tt big, .rst-content code big, .rst-content tt em, .rst-content code em { - font-size: 100% !important; - line-height: normal; -} -.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { - color: #404040; -} -.rst-content tt.xref, a .rst-content tt, .rst-content tt.xref, .rst-content code.xref, a .rst-content tt, a .rst-content code { - font-weight: bold; - color: #36872f; -} -.rst-content a tt, .rst-content a tt, .rst-content a code { - color: #60c557; -} -.rst-content dl { - margin-bottom: 24px; -} -.rst-content dl dt { - font-weight: bold; -} -.rst-content dl p, .rst-content dl table, .rst-content dl ul, .rst-content dl ol { - margin-bottom: 12px !important; -} -.rst-content dl dd { - margin: 0 0 12px 24px; -} -.rst-content dl:not(.docutils) { - margin-bottom: 24px; -} -.rst-content dl:not(.docutils) dt { - display: table; - margin: 6px 0; - font-size: 90%; - line-height: normal; - background: #c8c8c8; - color: #484848; - border-top: solid 3px #7b7b7b; - padding: 6px; - position: relative; -} -.rst-content dl:not(.docutils) dt:before { - color: #7b7b7b; -} -.rst-content dl:not(.docutils) dt .headerlink { - color: #404040; - font-size: 100% !important; -} -.rst-content dl:not(.docutils) dl dt { - margin-bottom: 6px; - border: none; - border-left: solid 3px #cccccc; - background: #f0f0f0; - color: #555; -} -.rst-content dl:not(.docutils) dl dt .headerlink { - color: #404040; - font-size: 100% !important; -} -.rst-content dl:not(.docutils) dt:first-child { - margin-top: 0; -} -.rst-content dl:not(.docutils) tt, .rst-content dl:not(.docutils) tt, .rst-content dl:not(.docutils) code { - font-weight: bold; -} -.rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) tt.descclassname, .rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) code.descname, .rst-content dl:not(.docutils) tt.descclassname, .rst-content dl:not(.docutils) code.descclassname { - background-color: transparent; - border: none; - padding: 0; - font-size: 100% !important; -} -.rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) code.descname { - font-weight: bold; -} -.rst-content dl:not(.docutils) .optional { - display: inline-block; - padding: 0 4px; - color: #000; - font-weight: bold; -} -.rst-content dl:not(.docutils) .property { - display: inline-block; - padding-right: 8px; -} -.rst-content .viewcode-link, .rst-content .viewcode-back { - display: inline-block; - color: #404040; - font-size: 80%; - padding-left: 24px; -} -.rst-content .viewcode-back { - display: block; - float: right; -} -.rst-content p.rubric { - margin-bottom: 12px; - font-weight: bold; -} -.rst-content tt.download, .rst-content code.download { - background: inherit; - padding: inherit; - font-weight: normal; - font-family: inherit; - font-size: inherit; - color: inherit; - border: inherit; - white-space: inherit; -} -.rst-content tt.download span:first-child, .rst-content code.download span:first-child { - -webkit-font-smoothing: subpixel-antialiased; -} -.rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before { - margin-right: 4px; -} -.rst-content .guilabel { - border: 1px solid #888888; - background: #c8c8c8; - font-size: 80%; - font-weight: 700; - border-radius: 4px; - padding: 2.4px 6px; - margin: auto 2px; -} -.rst-content .versionmodified { - font-style: italic; -} - -@media screen and (max-width: 480px) { - .rst-content .sidebar { - width: 100%; - } -} -span[id*='MathJax-Span'] { - color: #404040; -} - -.math { - text-align: center; -} - -@font-face { - font-family: "Inconsolata"; - font-style: normal; - font-weight: 400; - src: local("Inconsolata"), local("Inconsolata-Regular"), url(../fonts/Inconsolata-Regular.ttf) format("truetype"); -} -@font-face { - font-family: "Inconsolata"; - font-style: normal; - font-weight: 700; - src: local("Inconsolata Bold"), local("Inconsolata-Bold"), url(../fonts/Inconsolata-Bold.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: normal; - font-weight: 400; - src: local("Lato Regular"), local("Lato-Regular"), url(../fonts/Lato-Regular.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: normal; - font-weight: 700; - src: local("Lato Bold"), local("Lato-Bold"), url(../fonts/Lato-Bold.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: italic; - font-weight: 400; - src: local("Lato Italic"), local("Lato-Italic"), url(../fonts/Lato-Italic.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: italic; - font-weight: 700; - src: local("Lato Bold Italic"), local("Lato-BoldItalic"), url(../fonts/Lato-BoldItalic.ttf) format("truetype"); -} -@font-face { - font-family: "Roboto Slab"; - font-style: normal; - font-weight: 400; - src: local("Roboto Slab Regular"), local("RobotoSlab-Regular"), url(../fonts/RobotoSlab-Regular.ttf) format("truetype"); -} -@font-face { - font-family: "Roboto Slab"; - font-style: normal; - font-weight: 700; - src: local("Roboto Slab Bold"), local("RobotoSlab-Bold"), url(../fonts/RobotoSlab-Bold.ttf) format("truetype"); -} - -/*# sourceMappingURL=theme.css.map */ diff --git a/docs/_static/css/theme.css.map b/docs/_static/css/theme.css.map deleted file mode 100644 index f0d1df4d..00000000 --- a/docs/_static/css/theme.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": "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", -"sources": ["../../../bower_components/neat/app/assets/stylesheets/grid/_grid.scss","../../../bower_components/bourbon/dist/addons/_prefixer.scss","../../../bower_components/wyrm/sass/wyrm_core/_reset.sass","../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/font-awesome/scss/font-awesome.scss","../../../bower_components/font-awesome/scss/_path.scss","../../../bower_components/font-awesome/scss/_core.scss","../../../bower_components/font-awesome/scss/_larger.scss","../../../bower_components/font-awesome/scss/_fixed-width.scss","../../../bower_components/font-awesome/scss/_list.scss","../../../bower_components/font-awesome/scss/_variables.scss","../../../bower_components/font-awesome/scss/_bordered-pulled.scss","../../../bower_components/font-awesome/scss/_animated.scss","../../../bower_components/font-awesome/scss/_rotated-flipped.scss","../../../bower_components/font-awesome/scss/_mixins.scss","../../../bower_components/font-awesome/scss/_stacked.scss","../../../bower_components/font-awesome/scss/_icons.scss","../../../bower_components/font-awesome/scss/_screen-reader.scss","../../../bower_components/wyrm/sass/wyrm_core/_font_icon_defaults.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../bower_components/wyrm/sass/wyrm_core/_alert.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss","../../../bower_components/wyrm/sass/wyrm_core/_button.sass","../../../bower_components/wyrm/sass/wyrm_core/_dropdown.sass","../../../bower_components/wyrm/sass/wyrm_core/_form.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_outer-container.scss","../../../bower_components/neat/app/assets/stylesheets/settings/_grid.scss","../../../bower_components/neat/app/assets/stylesheets/grid/_span-columns.scss","../../../bower_components/wyrm/sass/wyrm_core/_neat_extra.sass","../../../bower_components/wyrm/sass/wyrm_core/_generic.sass","../../../bower_components/wyrm/sass/wyrm_core/_table.sass","../../../bower_components/wyrm/sass/wyrm_core/_type.sass","../../../sass/_theme_breadcrumbs.sass","../../../sass/_theme_layout.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_private.scss","../../../sass/_theme_badge.sass","../../../sass/_theme_rst.sass","../../../sass/_theme_mathjax.sass","../../../sass/_theme_font_local.sass"], -"names": [], -"file": "theme.css" -} diff --git a/docs/_static/doctools.js b/docs/_static/doctools.js deleted file mode 100644 index 7d88f807..00000000 --- a/docs/_static/doctools.js +++ /dev/null @@ -1,316 +0,0 @@ -/* - * doctools.js - * ~~~~~~~~~~~ - * - * Sphinx JavaScript utilities for all documentation. - * - * :copyright: Copyright 2007-2020 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/** - * select a different prefix for underscore - */ -$u = _.noConflict(); - -/** - * make the code below compatible with browsers without - * an installed firebug like debugger -if (!window.console || !console.firebug) { - var names = ["log", "debug", "info", "warn", "error", "assert", "dir", - "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", - "profile", "profileEnd"]; - window.console = {}; - for (var i = 0; i < names.length; ++i) - window.console[names[i]] = function() {}; -} - */ - -/** - * small helper function to urldecode strings - */ -jQuery.urldecode = function(x) { - return decodeURIComponent(x).replace(/\+/g, ' '); -}; - -/** - * small helper function to urlencode strings - */ -jQuery.urlencode = encodeURIComponent; - -/** - * This function returns the parsed url parameters of the - * current request. Multiple values per key are supported, - * it will always return arrays of strings for the value parts. - */ -jQuery.getQueryParameters = function(s) { - if (typeof s === 'undefined') - s = document.location.search; - var parts = s.substr(s.indexOf('?') + 1).split('&'); - var result = {}; - for (var i = 0; i < parts.length; i++) { - var tmp = parts[i].split('=', 2); - var key = jQuery.urldecode(tmp[0]); - var value = jQuery.urldecode(tmp[1]); - if (key in result) - result[key].push(value); - else - result[key] = [value]; - } - return result; -}; - -/** - * highlight a given string on a jquery object by wrapping it in - * span elements with the given class name. - */ -jQuery.fn.highlightText = function(text, className) { - function highlight(node, addItems) { - if (node.nodeType === 3) { - var val = node.nodeValue; - var pos = val.toLowerCase().indexOf(text); - if (pos >= 0 && - !jQuery(node.parentNode).hasClass(className) && - !jQuery(node.parentNode).hasClass("nohighlight")) { - var span; - var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); - if (isInSVG) { - span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); - } else { - span = document.createElement("span"); - span.className = className; - } - span.appendChild(document.createTextNode(val.substr(pos, text.length))); - node.parentNode.insertBefore(span, node.parentNode.insertBefore( - document.createTextNode(val.substr(pos + text.length)), - node.nextSibling)); - node.nodeValue = val.substr(0, pos); - if (isInSVG) { - var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); - var bbox = node.parentElement.getBBox(); - rect.x.baseVal.value = bbox.x; - rect.y.baseVal.value = bbox.y; - rect.width.baseVal.value = bbox.width; - rect.height.baseVal.value = bbox.height; - rect.setAttribute('class', className); - addItems.push({ - "parent": node.parentNode, - "target": rect}); - } - } - } - else if (!jQuery(node).is("button, select, textarea")) { - jQuery.each(node.childNodes, function() { - highlight(this, addItems); - }); - } - } - var addItems = []; - var result = this.each(function() { - highlight(this, addItems); - }); - for (var i = 0; i < addItems.length; ++i) { - jQuery(addItems[i].parent).before(addItems[i].target); - } - return result; -}; - -/* - * backward compatibility for jQuery.browser - * This will be supported until firefox bug is fixed. - */ -if (!jQuery.browser) { - jQuery.uaMatch = function(ua) { - ua = ua.toLowerCase(); - - var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || - /(webkit)[ \/]([\w.]+)/.exec(ua) || - /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || - /(msie) ([\w.]+)/.exec(ua) || - ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || - []; - - return { - browser: match[ 1 ] || "", - version: match[ 2 ] || "0" - }; - }; - jQuery.browser = {}; - jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; -} - -/** - * Small JavaScript module for the documentation. - */ -var Documentation = { - - init : function() { - this.fixFirefoxAnchorBug(); - this.highlightSearchWords(); - this.initIndexTable(); - if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { - this.initOnKeyListeners(); - } - }, - - /** - * i18n support - */ - TRANSLATIONS : {}, - PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, - LOCALE : 'unknown', - - // gettext and ngettext don't access this so that the functions - // can safely bound to a different name (_ = Documentation.gettext) - gettext : function(string) { - var translated = Documentation.TRANSLATIONS[string]; - if (typeof translated === 'undefined') - return string; - return (typeof translated === 'string') ? translated : translated[0]; - }, - - ngettext : function(singular, plural, n) { - var translated = Documentation.TRANSLATIONS[singular]; - if (typeof translated === 'undefined') - return (n == 1) ? singular : plural; - return translated[Documentation.PLURALEXPR(n)]; - }, - - addTranslations : function(catalog) { - for (var key in catalog.messages) - this.TRANSLATIONS[key] = catalog.messages[key]; - this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); - this.LOCALE = catalog.locale; - }, - - /** - * add context elements like header anchor links - */ - addContextElements : function() { - $('div[id] > :header:first').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this headline')). - appendTo(this); - }); - $('dt[id]').each(function() { - $('\u00B6'). - attr('href', '#' + this.id). - attr('title', _('Permalink to this definition')). - appendTo(this); - }); - }, - - /** - * workaround a firefox stupidity - * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 - */ - fixFirefoxAnchorBug : function() { - if (document.location.hash && $.browser.mozilla) - window.setTimeout(function() { - document.location.href += ''; - }, 10); - }, - - /** - * highlight the search words provided in the url in the text - */ - highlightSearchWords : function() { - var params = $.getQueryParameters(); - var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; - if (terms.length) { - var body = $('div.body'); - if (!body.length) { - body = $('body'); - } - window.setTimeout(function() { - $.each(terms, function() { - body.highlightText(this.toLowerCase(), 'highlighted'); - }); - }, 10); - $('') - .appendTo($('#searchbox')); - } - }, - - /** - * init the domain index toggle buttons - */ - initIndexTable : function() { - var togglers = $('img.toggler').click(function() { - var src = $(this).attr('src'); - var idnum = $(this).attr('id').substr(7); - $('tr.cg-' + idnum).toggle(); - if (src.substr(-9) === 'minus.png') - $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); - else - $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); - }).css('display', ''); - if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { - togglers.click(); - } - }, - - /** - * helper function to hide the search marks again - */ - hideSearchWords : function() { - $('#searchbox .highlight-link').fadeOut(300); - $('span.highlighted').removeClass('highlighted'); - }, - - /** - * make the url absolute - */ - makeURL : function(relativeURL) { - return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; - }, - - /** - * get the current relative url - */ - getCurrentURL : function() { - var path = document.location.pathname; - var parts = path.split(/\//); - $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { - if (this === '..') - parts.pop(); - }); - var url = parts.join('/'); - return path.substring(url.lastIndexOf('/') + 1, path.length - 1); - }, - - initOnKeyListeners: function() { - $(document).keydown(function(event) { - var activeElementType = document.activeElement.tagName; - // don't navigate when in search box, textarea, dropdown or button - if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' - && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey - && !event.shiftKey) { - switch (event.keyCode) { - case 37: // left - var prevHref = $('link[rel="prev"]').prop('href'); - if (prevHref) { - window.location.href = prevHref; - return false; - } - case 39: // right - var nextHref = $('link[rel="next"]').prop('href'); - if (nextHref) { - window.location.href = nextHref; - return false; - } - } - } - }); - } -}; - -// quick alias for translations -_ = Documentation.gettext; - -$(document).ready(function() { - Documentation.init(); -}); diff --git a/docs/_static/documentation_options.js b/docs/_static/documentation_options.js deleted file mode 100644 index 120e3eec..00000000 --- a/docs/_static/documentation_options.js +++ /dev/null @@ -1,12 +0,0 @@ -var DOCUMENTATION_OPTIONS = { - URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '1.2.1', - LANGUAGE: 'None', - COLLAPSE_INDEX: false, - BUILDER: 'html', - FILE_SUFFIX: '.html', - LINK_SUFFIX: '.html', - HAS_SOURCE: true, - SOURCELINK_SUFFIX: '.txt', - NAVIGATION_WITH_KEYS: false -}; \ No newline at end of file diff --git a/docs/_static/file.png b/docs/_static/file.png deleted file mode 100644 index a858a410..00000000 Binary files a/docs/_static/file.png and /dev/null differ diff --git a/docs/_static/fonts/FontAwesome.otf b/docs/_static/fonts/FontAwesome.otf deleted file mode 100644 index 401ec0f3..00000000 Binary files a/docs/_static/fonts/FontAwesome.otf and /dev/null differ diff --git a/docs/_static/fonts/Inconsolata-Bold.ttf b/docs/_static/fonts/Inconsolata-Bold.ttf deleted file mode 100644 index 9addc892..00000000 Binary files a/docs/_static/fonts/Inconsolata-Bold.ttf and /dev/null differ diff --git a/docs/_static/fonts/Inconsolata-Regular.ttf b/docs/_static/fonts/Inconsolata-Regular.ttf deleted file mode 100644 index 592ccd20..00000000 Binary files a/docs/_static/fonts/Inconsolata-Regular.ttf and /dev/null differ diff --git a/docs/_static/fonts/Lato-Bold.ttf b/docs/_static/fonts/Lato-Bold.ttf deleted file mode 100644 index 1d23c706..00000000 Binary files a/docs/_static/fonts/Lato-Bold.ttf and /dev/null differ diff --git a/docs/_static/fonts/Lato-BoldItalic.ttf b/docs/_static/fonts/Lato-BoldItalic.ttf deleted file mode 100644 index a3b8e332..00000000 Binary files a/docs/_static/fonts/Lato-BoldItalic.ttf and /dev/null differ diff --git a/docs/_static/fonts/Lato-Italic.ttf b/docs/_static/fonts/Lato-Italic.ttf deleted file mode 100644 index 70a870f4..00000000 Binary files a/docs/_static/fonts/Lato-Italic.ttf and /dev/null differ diff --git a/docs/_static/fonts/Lato-Regular.ttf b/docs/_static/fonts/Lato-Regular.ttf deleted file mode 100644 index 0f3d0f83..00000000 Binary files a/docs/_static/fonts/Lato-Regular.ttf and /dev/null differ diff --git a/docs/_static/fonts/RobotoSlab-Bold.ttf b/docs/_static/fonts/RobotoSlab-Bold.ttf deleted file mode 100644 index df5d1df2..00000000 Binary files a/docs/_static/fonts/RobotoSlab-Bold.ttf and /dev/null differ diff --git a/docs/_static/fonts/RobotoSlab-Regular.ttf b/docs/_static/fonts/RobotoSlab-Regular.ttf deleted file mode 100644 index eb52a790..00000000 Binary files a/docs/_static/fonts/RobotoSlab-Regular.ttf and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.eot b/docs/_static/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca9..00000000 Binary files a/docs/_static/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.svg b/docs/_static/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e..00000000 --- a/docs/_static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/_static/fonts/fontawesome-webfont.ttf b/docs/_static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2f..00000000 Binary files a/docs/_static/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.woff b/docs/_static/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4..00000000 Binary files a/docs/_static/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/docs/_static/fonts/fontawesome-webfont.woff2 b/docs/_static/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc60..00000000 Binary files a/docs/_static/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/docs/_static/jquery-3.2.1.js b/docs/_static/jquery-3.2.1.js deleted file mode 100644 index d2d8ca47..00000000 --- a/docs/_static/jquery-3.2.1.js +++ /dev/null @@ -1,10253 +0,0 @@ -/*! - * jQuery JavaScript Library v3.2.1 - * https://jquery.com/ - * - * Includes Sizzle.js - * https://sizzlejs.com/ - * - * Copyright JS Foundation and other contributors - * Released under the MIT license - * https://jquery.org/license - * - * Date: 2017-03-20T18:59Z - */ -( function( global, factory ) { - - "use strict"; - - if ( typeof module === "object" && typeof module.exports === "object" ) { - - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 -// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode -// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common -// enough that all such attempts are guarded in a try block. -"use strict"; - -var arr = []; - -var document = window.document; - -var getProto = Object.getPrototypeOf; - -var slice = arr.slice; - -var concat = arr.concat; - -var push = arr.push; - -var indexOf = arr.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var fnToString = hasOwn.toString; - -var ObjectFunctionString = fnToString.call( Object ); - -var support = {}; - - - - function DOMEval( code, doc ) { - doc = doc || document; - - var script = doc.createElement( "script" ); - - script.text = code; - doc.head.appendChild( script ).parentNode.removeChild( script ); - } -/* global Symbol */ -// Defining this global in .eslintrc.json would create a danger of using the global -// unguarded in another place, it seems safer to define global only for this module - - - -var - version = "3.2.1", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android <=4.0 only - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([a-z])/g, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - - // Return all the elements in a clean array - if ( num == null ) { - return slice.call( this ); - } - - // Return just the one element from the set - return num < 0 ? this[ num + this.length ] : this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: arr.sort, - splice: arr.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var options, name, src, copy, copyIsArray, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // Skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // Extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = Array.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && Array.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isWindow: function( obj ) { - return obj != null && obj === obj.window; - }, - - isNumeric: function( obj ) { - - // As of jQuery 3.0, isNumeric is limited to - // strings and numbers (primitives or objects) - // that can be coerced to finite numbers (gh-2662) - var type = jQuery.type( obj ); - return ( type === "number" || type === "string" ) && - - // parseFloat NaNs numeric-cast false positives ("") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - !isNaN( obj - parseFloat( obj ) ); - }, - - isPlainObject: function( obj ) { - var proto, Ctor; - - // Detect obvious negatives - // Use toString instead of jQuery.type to catch host objects - if ( !obj || toString.call( obj ) !== "[object Object]" ) { - return false; - } - - proto = getProto( obj ); - - // Objects with no prototype (e.g., `Object.create( null )`) are plain - if ( !proto ) { - return true; - } - - // Objects with prototype are plain iff they were constructed by a global Object function - Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; - return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; - }, - - isEmptyObject: function( obj ) { - - /* eslint-disable no-unused-vars */ - // See https://github.com/eslint/eslint/issues/6125 - var name; - - for ( name in obj ) { - return false; - } - return true; - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - - // Support: Android <=2.3 only (functionish RegExp) - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Evaluates a script in a global context - globalEval: function( code ) { - DOMEval( code ); - }, - - // Convert dashed to camelCase; used by the css and data modules - // Support: IE <=9 - 11, Edge 12 - 13 - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android <=4.0 only - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - return arr == null ? -1 : indexOf.call( arr, elem, i ); - }, - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - for ( ; j < len; j++ ) { - first[ i++ ] = second[ j ]; - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var tmp, args, proxy; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: Date.now, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; -} - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: real iOS 8.2 only (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.3.3 - * https://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-08-08 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // https://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - - // CSS escapes - // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // CSS string/identifier serialization - // https://drafts.csswg.org/cssom/#common-serializing-idioms - rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, - fcssescape = function( ch, asCodePoint ) { - if ( asCodePoint ) { - - // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER - if ( ch === "\0" ) { - return "\uFFFD"; - } - - // Control characters and (dependent upon position) numbers get escaped as code points - return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; - } - - // Other potentially-special ASCII characters get backslash-escaped - return "\\" + ch; - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }, - - disabledAncestor = addCombinator( - function( elem ) { - return elem.disabled === true && ("form" in elem || "label" in elem); - }, - { dir: "parentNode", next: "legend" } - ); - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rcssescape, fcssescape ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - while ( i-- ) { - groups[i] = "#" + nid + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created element and returns a boolean result - */ -function assert( fn ) { - var el = document.createElement("fieldset"); - - try { - return !!fn( el ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( el.parentNode ) { - el.parentNode.removeChild( el ); - } - // release memory in IE - el = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - a.sourceIndex - b.sourceIndex; - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for :enabled/:disabled - * @param {Boolean} disabled true for :disabled; false for :enabled - */ -function createDisabledPseudo( disabled ) { - - // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable - return function( elem ) { - - // Only certain elements can match :enabled or :disabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled - // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled - if ( "form" in elem ) { - - // Check for inherited disabledness on relevant non-disabled elements: - // * listed form-associated elements in a disabled fieldset - // https://html.spec.whatwg.org/multipage/forms.html#category-listed - // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled - // * option elements in a disabled optgroup - // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled - // All such elements have a "form" property. - if ( elem.parentNode && elem.disabled === false ) { - - // Option elements defer to a parent optgroup if present - if ( "label" in elem ) { - if ( "label" in elem.parentNode ) { - return elem.parentNode.disabled === disabled; - } else { - return elem.disabled === disabled; - } - } - - // Support: IE 6 - 11 - // Use the isDisabled shortcut property to check for disabled fieldset ancestors - return elem.isDisabled === disabled || - - // Where there is no isDisabled, check manually - /* jshint -W018 */ - elem.isDisabled !== !disabled && - disabledAncestor( elem ) === disabled; - } - - return elem.disabled === disabled; - - // Try to winnow out elements that can't be disabled before trusting the disabled property. - // Some victims get caught in our net (label, legend, menu, track), but it shouldn't - // even exist on them, let alone have a boolean value. - } else if ( "label" in elem ) { - return elem.disabled === disabled; - } - - // Remaining elements are neither :enabled nor :disabled - return false; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, subWindow, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( preferredDoc !== document && - (subWindow = document.defaultView) && subWindow.top !== subWindow ) { - - // Support: IE 11, Edge - if ( subWindow.addEventListener ) { - subWindow.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( subWindow.attachEvent ) { - subWindow.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( el ) { - el.className = "i"; - return !el.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( el ) { - el.appendChild( document.createComment("") ); - return !el.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programmatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( el ) { - docElem.appendChild( el ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID filter and find - if ( support.getById ) { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var elem = context.getElementById( id ); - return elem ? [ elem ] : []; - } - }; - } else { - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - - // Support: IE 6 - 7 only - // getElementById is not reliable as a find shortcut - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var node, i, elems, - elem = context.getElementById( id ); - - if ( elem ) { - - // Verify the id attribute - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - - // Fall back on getElementsByName - elems = context.getElementsByName( id ); - i = 0; - while ( (elem = elems[i++]) ) { - node = elem.getAttributeNode("id"); - if ( node && node.value === id ) { - return [ elem ]; - } - } - } - - return []; - } - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See https://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( el ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // https://bugs.jquery.com/ticket/12359 - docElem.appendChild( el ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( el.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !el.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !el.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibling-combinator selector` fails - if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( el ) { - el.innerHTML = "" + - ""; - - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - el.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( el.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( el.querySelectorAll(":enabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Support: IE9-11+ - // IE's :disabled selector does not pick up the children of disabled fieldsets - docElem.appendChild( el ).disabled = true; - if ( el.querySelectorAll(":disabled").length !== 2 ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - el.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( el ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( el, "*" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( el, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.escape = function( sel ) { - return (sel + "").replace( rcssescape, fcssescape ); -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": createDisabledPseudo( false ), - "disabled": createDisabledPseudo( true ), - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - skip = combinator.next, - key = skip || dir, - checkNonElements = base && key === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - return false; - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( skip && skip === elem.nodeName.toLowerCase() ) { - elem = elem[ dir ] || elem; - } else if ( (oldCache = uniqueCache[ key ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ key ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - return false; - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( el ) { - // Should return 1, but returns 4 (following) - return el.compareDocumentPosition( document.createElement("fieldset") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( el ) { - el.innerHTML = ""; - return el.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( el ) { - el.innerHTML = ""; - el.firstChild.setAttribute( "value", "" ); - return el.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( el ) { - return el.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; - -// Deprecated -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; -jQuery.escapeSelector = Sizzle.escape; - - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - - - -function nodeName( elem, name ) { - - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - -}; -var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - return !!qualifier.call( elem, i, elem ) !== not; - } ); - } - - // Single element - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - } - - // Arraylike of elements (jQuery, arguments, Array) - if ( typeof qualifier !== "string" ) { - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not; - } ); - } - - // Simple selector that can be filtered directly, removing non-Elements - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - // Complex selector, compare the two sets, removing non-Elements - qualifier = jQuery.filter( qualifier, elements ); - return jQuery.grep( elements, function( elem ) { - return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1; - } ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - if ( elems.length === 1 && elem.nodeType === 1 ) { - return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; - } - - return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, ret, - len = this.length, - self = this; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - ret = this.pushStack( [] ); - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - return len > 1 ? jQuery.uniqueSort( ret ) : ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - // Shortcut simple #id case for speed - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // Method init() accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector[ 0 ] === "<" && - selector[ selector.length - 1 ] === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // Option to run scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - if ( elem ) { - - // Inject the element directly into the jQuery object - this[ 0 ] = elem; - this.length = 1; - } - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return root.ready !== undefined ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // Methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var targets = jQuery( target, this ), - l = targets.length; - - return this.filter( function() { - var i = 0; - for ( ; i < l; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - targets = typeof selectors !== "string" && jQuery( selectors ); - - // Positional selectors never match, since there's no _selection_ context - if ( !rneedsContext.test( selectors ) ) { - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( targets ? - targets.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within the set - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // Index in selector - if ( typeof elem === "string" ) { - return indexOf.call( jQuery( elem ), this[ 0 ] ); - } - - // Locate the position of the desired element - return indexOf.call( this, - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem - ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - if ( nodeName( elem, "iframe" ) ) { - return elem.contentDocument; - } - - // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only - // Treat the template element as a regular one in browsers that - // don't support it. - if ( nodeName( elem, "template" ) ) { - elem = elem.content || elem; - } - - return jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var matched = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - matched = jQuery.filter( selector, matched ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - jQuery.uniqueSort( matched ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - matched.reverse(); - } - } - - return this.pushStack( matched ); - }; -} ); -var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = locked || options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = queue = []; - if ( !memory && !firing ) { - list = memory = ""; - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -function Identity( v ) { - return v; -} -function Thrower( ex ) { - throw ex; -} - -function adoptValue( value, resolve, reject, noValue ) { - var method; - - try { - - // Check for promise aspect first to privilege synchronous behavior - if ( value && jQuery.isFunction( ( method = value.promise ) ) ) { - method.call( value ).done( resolve ).fail( reject ); - - // Other thenables - } else if ( value && jQuery.isFunction( ( method = value.then ) ) ) { - method.call( value, resolve, reject ); - - // Other non-thenables - } else { - - // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: - // * false: [ value ].slice( 0 ) => resolve( value ) - // * true: [ value ].slice( 1 ) => resolve() - resolve.apply( undefined, [ value ].slice( noValue ) ); - } - - // For Promises/A+, convert exceptions into rejections - // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in - // Deferred#then to conditionally suppress rejection. - } catch ( value ) { - - // Support: Android 4.0 only - // Strict mode functions invoked without .call/.apply get global-object context - reject.apply( undefined, [ value ] ); - } -} - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, callbacks, - // ... .then handlers, argument index, [final state] - [ "notify", "progress", jQuery.Callbacks( "memory" ), - jQuery.Callbacks( "memory" ), 2 ], - [ "resolve", "done", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 0, "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), - jQuery.Callbacks( "once memory" ), 1, "rejected" ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - "catch": function( fn ) { - return promise.then( null, fn ); - }, - - // Keep pipe for back-compat - pipe: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - - // Map tuples (progress, done, fail) to arguments (done, fail, progress) - var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; - - // deferred.progress(function() { bind to newDefer or newDefer.notify }) - // deferred.done(function() { bind to newDefer or newDefer.resolve }) - // deferred.fail(function() { bind to newDefer or newDefer.reject }) - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - then: function( onFulfilled, onRejected, onProgress ) { - var maxDepth = 0; - function resolve( depth, deferred, handler, special ) { - return function() { - var that = this, - args = arguments, - mightThrow = function() { - var returned, then; - - // Support: Promises/A+ section 2.3.3.3.3 - // https://promisesaplus.com/#point-59 - // Ignore double-resolution attempts - if ( depth < maxDepth ) { - return; - } - - returned = handler.apply( that, args ); - - // Support: Promises/A+ section 2.3.1 - // https://promisesaplus.com/#point-48 - if ( returned === deferred.promise() ) { - throw new TypeError( "Thenable self-resolution" ); - } - - // Support: Promises/A+ sections 2.3.3.1, 3.5 - // https://promisesaplus.com/#point-54 - // https://promisesaplus.com/#point-75 - // Retrieve `then` only once - then = returned && - - // Support: Promises/A+ section 2.3.4 - // https://promisesaplus.com/#point-64 - // Only check objects and functions for thenability - ( typeof returned === "object" || - typeof returned === "function" ) && - returned.then; - - // Handle a returned thenable - if ( jQuery.isFunction( then ) ) { - - // Special processors (notify) just wait for resolution - if ( special ) { - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ) - ); - - // Normal processors (resolve) also hook into progress - } else { - - // ...and disregard older resolution values - maxDepth++; - - then.call( - returned, - resolve( maxDepth, deferred, Identity, special ), - resolve( maxDepth, deferred, Thrower, special ), - resolve( maxDepth, deferred, Identity, - deferred.notifyWith ) - ); - } - - // Handle all other returned values - } else { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Identity ) { - that = undefined; - args = [ returned ]; - } - - // Process the value(s) - // Default process is resolve - ( special || deferred.resolveWith )( that, args ); - } - }, - - // Only normal processors (resolve) catch and reject exceptions - process = special ? - mightThrow : - function() { - try { - mightThrow(); - } catch ( e ) { - - if ( jQuery.Deferred.exceptionHook ) { - jQuery.Deferred.exceptionHook( e, - process.stackTrace ); - } - - // Support: Promises/A+ section 2.3.3.3.4.1 - // https://promisesaplus.com/#point-61 - // Ignore post-resolution exceptions - if ( depth + 1 >= maxDepth ) { - - // Only substitute handlers pass on context - // and multiple values (non-spec behavior) - if ( handler !== Thrower ) { - that = undefined; - args = [ e ]; - } - - deferred.rejectWith( that, args ); - } - } - }; - - // Support: Promises/A+ section 2.3.3.3.1 - // https://promisesaplus.com/#point-57 - // Re-resolve promises immediately to dodge false rejection from - // subsequent errors - if ( depth ) { - process(); - } else { - - // Call an optional hook to record the stack, in case of exception - // since it's otherwise lost when execution goes async - if ( jQuery.Deferred.getStackHook ) { - process.stackTrace = jQuery.Deferred.getStackHook(); - } - window.setTimeout( process ); - } - }; - } - - return jQuery.Deferred( function( newDefer ) { - - // progress_handlers.add( ... ) - tuples[ 0 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onProgress ) ? - onProgress : - Identity, - newDefer.notifyWith - ) - ); - - // fulfilled_handlers.add( ... ) - tuples[ 1 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onFulfilled ) ? - onFulfilled : - Identity - ) - ); - - // rejected_handlers.add( ... ) - tuples[ 2 ][ 3 ].add( - resolve( - 0, - newDefer, - jQuery.isFunction( onRejected ) ? - onRejected : - Thrower - ) - ); - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 5 ]; - - // promise.progress = list.add - // promise.done = list.add - // promise.fail = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( - function() { - - // state = "resolved" (i.e., fulfilled) - // state = "rejected" - state = stateString; - }, - - // rejected_callbacks.disable - // fulfilled_callbacks.disable - tuples[ 3 - i ][ 2 ].disable, - - // progress_callbacks.lock - tuples[ 0 ][ 2 ].lock - ); - } - - // progress_handlers.fire - // fulfilled_handlers.fire - // rejected_handlers.fire - list.add( tuple[ 3 ].fire ); - - // deferred.notify = function() { deferred.notifyWith(...) } - // deferred.resolve = function() { deferred.resolveWith(...) } - // deferred.reject = function() { deferred.rejectWith(...) } - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); - return this; - }; - - // deferred.notifyWith = list.fireWith - // deferred.resolveWith = list.fireWith - // deferred.rejectWith = list.fireWith - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( singleValue ) { - var - - // count of uncompleted subordinates - remaining = arguments.length, - - // count of unprocessed arguments - i = remaining, - - // subordinate fulfillment data - resolveContexts = Array( i ), - resolveValues = slice.call( arguments ), - - // the master Deferred - master = jQuery.Deferred(), - - // subordinate callback factory - updateFunc = function( i ) { - return function( value ) { - resolveContexts[ i ] = this; - resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( !( --remaining ) ) { - master.resolveWith( resolveContexts, resolveValues ); - } - }; - }; - - // Single- and empty arguments are adopted like Promise.resolve - if ( remaining <= 1 ) { - adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, - !remaining ); - - // Use .then() to unwrap secondary thenables (cf. gh-3000) - if ( master.state() === "pending" || - jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { - - return master.then(); - } - } - - // Multiple arguments are aggregated like Promise.all array elements - while ( i-- ) { - adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); - } - - return master.promise(); - } -} ); - - -// These usually indicate a programmer mistake during development, -// warn about them ASAP rather than swallowing them by default. -var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; - -jQuery.Deferred.exceptionHook = function( error, stack ) { - - // Support: IE 8 - 9 only - // Console exists when dev tools are open, which can happen at any time - if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { - window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); - } -}; - - - - -jQuery.readyException = function( error ) { - window.setTimeout( function() { - throw error; - } ); -}; - - - - -// The deferred used on DOM ready -var readyList = jQuery.Deferred(); - -jQuery.fn.ready = function( fn ) { - - readyList - .then( fn ) - - // Wrap jQuery.readyException in a function so that the lookup - // happens at the time of error handling instead of callback - // registration. - .catch( function( error ) { - jQuery.readyException( error ); - } ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - } -} ); - -jQuery.ready.then = readyList.then; - -// The ready event handler and self cleanup method -function completed() { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - jQuery.ready(); -} - -// Catch cases where $(document).ready() is called -// after the browser event has already occurred. -// Support: IE <=9 - 10 only -// Older IE sometimes signals "interactive" too soon -if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - -} else { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); -} - - - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - len = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < len; i++ ) { - fn( - elems[ i ], key, raw ? - value : - value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - if ( chainable ) { - return elems; - } - - // Gets - if ( bulk ) { - return fn.call( elems ); - } - - return len ? fn( elems[ 0 ], key ) : emptyGet; -}; -var acceptData = function( owner ) { - - // Accepts only: - // - Node - // - Node.ELEMENT_NODE - // - Node.DOCUMENT_NODE - // - Object - // - Any - return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); -}; - - - - -function Data() { - this.expando = jQuery.expando + Data.uid++; -} - -Data.uid = 1; - -Data.prototype = { - - cache: function( owner ) { - - // Check if the owner object already has a cache - var value = owner[ this.expando ]; - - // If not, create one - if ( !value ) { - value = {}; - - // We can accept data for non-element nodes in modern browsers, - // but we should not, see #8335. - // Always return an empty object. - if ( acceptData( owner ) ) { - - // If it is a node unlikely to be stringify-ed or looped over - // use plain assignment - if ( owner.nodeType ) { - owner[ this.expando ] = value; - - // Otherwise secure it in a non-enumerable property - // configurable must be true to allow the property to be - // deleted when data is removed - } else { - Object.defineProperty( owner, this.expando, { - value: value, - configurable: true - } ); - } - } - } - - return value; - }, - set: function( owner, data, value ) { - var prop, - cache = this.cache( owner ); - - // Handle: [ owner, key, value ] args - // Always use camelCase key (gh-2257) - if ( typeof data === "string" ) { - cache[ jQuery.camelCase( data ) ] = value; - - // Handle: [ owner, { properties } ] args - } else { - - // Copy the properties one-by-one to the cache object - for ( prop in data ) { - cache[ jQuery.camelCase( prop ) ] = data[ prop ]; - } - } - return cache; - }, - get: function( owner, key ) { - return key === undefined ? - this.cache( owner ) : - - // Always use camelCase key (gh-2257) - owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ]; - }, - access: function( owner, key, value ) { - - // In cases where either: - // - // 1. No key was specified - // 2. A string key was specified, but no value provided - // - // Take the "read" path and allow the get method to determine - // which value to return, respectively either: - // - // 1. The entire cache object - // 2. The data stored at the key - // - if ( key === undefined || - ( ( key && typeof key === "string" ) && value === undefined ) ) { - - return this.get( owner, key ); - } - - // When the key is not a string, or both a key and value - // are specified, set or extend (existing objects) with either: - // - // 1. An object of properties - // 2. A key and value - // - this.set( owner, key, value ); - - // Since the "set" path can have two possible entry points - // return the expected data based on which path was taken[*] - return value !== undefined ? value : key; - }, - remove: function( owner, key ) { - var i, - cache = owner[ this.expando ]; - - if ( cache === undefined ) { - return; - } - - if ( key !== undefined ) { - - // Support array or space separated string of keys - if ( Array.isArray( key ) ) { - - // If key is an array of keys... - // We always set camelCase keys, so remove that. - key = key.map( jQuery.camelCase ); - } else { - key = jQuery.camelCase( key ); - - // If a key with the spaces exists, use it. - // Otherwise, create an array by matching non-whitespace - key = key in cache ? - [ key ] : - ( key.match( rnothtmlwhite ) || [] ); - } - - i = key.length; - - while ( i-- ) { - delete cache[ key[ i ] ]; - } - } - - // Remove the expando if there's no more data - if ( key === undefined || jQuery.isEmptyObject( cache ) ) { - - // Support: Chrome <=35 - 45 - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) - if ( owner.nodeType ) { - owner[ this.expando ] = undefined; - } else { - delete owner[ this.expando ]; - } - } - }, - hasData: function( owner ) { - var cache = owner[ this.expando ]; - return cache !== undefined && !jQuery.isEmptyObject( cache ); - } -}; -var dataPriv = new Data(); - -var dataUser = new Data(); - - - -// Implementation Summary -// -// 1. Enforce API surface and semantic compatibility with 1.9.x branch -// 2. Improve the module's maintainability by reducing the storage -// paths to a single mechanism. -// 3. Use the same single mechanism to support "private" and "user" data. -// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) -// 5. Avoid exposing implementation details on user objects (eg. expando properties) -// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /[A-Z]/g; - -function getData( data ) { - if ( data === "true" ) { - return true; - } - - if ( data === "false" ) { - return false; - } - - if ( data === "null" ) { - return null; - } - - // Only convert to a number if it doesn't change the string - if ( data === +data + "" ) { - return +data; - } - - if ( rbrace.test( data ) ) { - return JSON.parse( data ); - } - - return data; -} - -function dataAttr( elem, key, data ) { - var name; - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = getData( data ); - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - dataUser.set( elem, key, data ); - } else { - data = undefined; - } - } - return data; -} - -jQuery.extend( { - hasData: function( elem ) { - return dataUser.hasData( elem ) || dataPriv.hasData( elem ); - }, - - data: function( elem, name, data ) { - return dataUser.access( elem, name, data ); - }, - - removeData: function( elem, name ) { - dataUser.remove( elem, name ); - }, - - // TODO: Now that all calls to _data and _removeData have been replaced - // with direct calls to dataPriv methods, these can be deprecated. - _data: function( elem, name, data ) { - return dataPriv.access( elem, name, data ); - }, - - _removeData: function( elem, name ) { - dataPriv.remove( elem, name ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = dataUser.get( elem ); - - if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE 11 only - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - dataPriv.set( elem, "hasDataAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - dataUser.set( this, key ); - } ); - } - - return access( this, function( value ) { - var data; - - // The calling jQuery object (element matches) is not empty - // (and therefore has an element appears at this[ 0 ]) and the - // `value` parameter was not undefined. An empty jQuery object - // will result in `undefined` for elem = this[ 0 ] which will - // throw an exception if an attempt to read a data cache is made. - if ( elem && value === undefined ) { - - // Attempt to get data from the cache - // The key will always be camelCased in Data - data = dataUser.get( elem, key ); - if ( data !== undefined ) { - return data; - } - - // Attempt to "discover" the data in - // HTML5 custom data-* attrs - data = dataAttr( elem, key ); - if ( data !== undefined ) { - return data; - } - - // We tried really hard, but the data doesn't exist. - return; - } - - // Set the data... - this.each( function() { - - // We always store the camelCased key - dataUser.set( this, key, value ); - } ); - }, null, value, arguments.length > 1, null, true ); - }, - - removeData: function( key ) { - return this.each( function() { - dataUser.remove( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = dataPriv.get( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || Array.isArray( data ) ) { - queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // Clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // Not public - generate a queueHooks object, or return the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - dataPriv.remove( elem, [ type + "queue", key ] ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // Ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHiddenWithinTree = function( elem, el ) { - - // isHiddenWithinTree might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - - // Inline style trumps all - return elem.style.display === "none" || - elem.style.display === "" && - - // Otherwise, check computed style - // Support: Firefox <=43 - 45 - // Disconnected elements can have computed display: none, so first confirm that elem is - // in the document. - jQuery.contains( elem.ownerDocument, elem ) && - - jQuery.css( elem, "display" ) === "none"; - }; - -var swap = function( elem, options, callback, args ) { - var ret, name, - old = {}; - - // Remember the old values, and insert the new ones - for ( name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - ret = callback.apply( elem, args || [] ); - - // Revert the old values - for ( name in options ) { - elem.style[ name ] = old[ name ]; - } - - return ret; -}; - - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, - maxIterations = 20, - currentValue = tween ? - function() { - return tween.cur(); - } : - function() { - return jQuery.css( elem, prop, "" ); - }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -var defaultDisplayMap = {}; - -function getDefaultDisplay( elem ) { - var temp, - doc = elem.ownerDocument, - nodeName = elem.nodeName, - display = defaultDisplayMap[ nodeName ]; - - if ( display ) { - return display; - } - - temp = doc.body.appendChild( doc.createElement( nodeName ) ); - display = jQuery.css( temp, "display" ); - - temp.parentNode.removeChild( temp ); - - if ( display === "none" ) { - display = "block"; - } - defaultDisplayMap[ nodeName ] = display; - - return display; -} - -function showHide( elements, show ) { - var display, elem, - values = [], - index = 0, - length = elements.length; - - // Determine new display value for elements that need to change - for ( ; index < length; index++ ) { - elem = elements[ index ]; - if ( !elem.style ) { - continue; - } - - display = elem.style.display; - if ( show ) { - - // Since we force visibility upon cascade-hidden elements, an immediate (and slow) - // check is required in this first loop unless we have a nonempty display value (either - // inline or about-to-be-restored) - if ( display === "none" ) { - values[ index ] = dataPriv.get( elem, "display" ) || null; - if ( !values[ index ] ) { - elem.style.display = ""; - } - } - if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { - values[ index ] = getDefaultDisplay( elem ); - } - } else { - if ( display !== "none" ) { - values[ index ] = "none"; - - // Remember what we're overwriting - dataPriv.set( elem, "display", display ); - } - } - } - - // Set the display of the elements in a second loop to avoid constant reflow - for ( index = 0; index < length; index++ ) { - if ( values[ index ] != null ) { - elements[ index ].style.display = values[ index ]; - } - } - - return elements; -} - -jQuery.fn.extend( { - show: function() { - return showHide( this, true ); - }, - hide: function() { - return showHide( this ); - }, - toggle: function( state ) { - if ( typeof state === "boolean" ) { - return state ? this.show() : this.hide(); - } - - return this.each( function() { - if ( isHiddenWithinTree( this ) ) { - jQuery( this ).show(); - } else { - jQuery( this ).hide(); - } - } ); - } -} ); -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i ); - -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); - - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - - // Support: IE <=9 only - option: [ 1, "" ], - - // XHTML parsers do not magically insert elements in the - // same way that tag soup parsers do. So we cannot shorten - // this by omitting or other required elements. - thead: [ 1, "", "
" ], - col: [ 2, "", "
" ], - tr: [ 2, "", "
" ], - td: [ 3, "", "
" ], - - _default: [ 0, "", "" ] -}; - -// Support: IE <=9 only -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - - // Support: IE <=9 - 11 only - // Use typeof to avoid zero-argument method invocation on host objects (#15151) - var ret; - - if ( typeof context.getElementsByTagName !== "undefined" ) { - ret = context.getElementsByTagName( tag || "*" ); - - } else if ( typeof context.querySelectorAll !== "undefined" ) { - ret = context.querySelectorAll( tag || "*" ); - - } else { - ret = []; - } - - if ( tag === undefined || tag && nodeName( context, tag ) ) { - return jQuery.merge( [ context ], ret ); - } - - return ret; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - dataPriv.set( - elems[ i ], - "globalEval", - !refElements || dataPriv.get( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/; - -function buildFragment( elems, context, scripts, selection, ignored ) { - var elem, tmp, tag, wrap, contains, j, - fragment = context.createDocumentFragment(), - nodes = [], - i = 0, - l = elems.length; - - for ( ; i < l; i++ ) { - elem = elems[ i ]; - - if ( elem || elem === 0 ) { - - // Add nodes directly - if ( jQuery.type( elem ) === "object" ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); - - // Convert non-html into a text node - } else if ( !rhtml.test( elem ) ) { - nodes.push( context.createTextNode( elem ) ); - - // Convert html into DOM nodes - } else { - tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); - - // Deserialize a standard representation - tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); - wrap = wrapMap[ tag ] || wrapMap._default; - tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; - - // Descend through wrappers to the right content - j = wrap[ 0 ]; - while ( j-- ) { - tmp = tmp.lastChild; - } - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( nodes, tmp.childNodes ); - - // Remember the top-level container - tmp = fragment.firstChild; - - // Ensure the created nodes are orphaned (#12392) - tmp.textContent = ""; - } - } - } - - // Remove wrapper from fragment - fragment.textContent = ""; - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( fragment.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - return fragment; -} - - -( function() { - var fragment = document.createDocumentFragment(), - div = fragment.appendChild( document.createElement( "div" ) ), - input = document.createElement( "input" ); - - // Support: Android 4.0 - 4.3 only - // Check state lost if the name is set (#11217) - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Android <=4.1 only - // Older WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE <=11 only - // Make sure textarea (and checkbox) defaultValue is properly cloned - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; -} )(); -var documentElement = document.documentElement; - - - -var - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE <=9 only -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - - var handleObjIn, eventHandle, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.get( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Ensure that invalid selectors throw exceptions at attach time - // Evaluate against documentElement in case elem is a non-element node (e.g., document) - if ( selector ) { - jQuery.find.matchesSelector( documentElement, selector ); - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? - jQuery.event.dispatch.apply( elem, arguments ) : undefined; - }; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - - var j, origCount, tmp, - events, t, handleObj, - special, handlers, type, namespaces, origType, - elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove data and the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - dataPriv.remove( elem, "handle events" ); - } - }, - - dispatch: function( nativeEvent ) { - - // Make a writable jQuery.Event from the native event object - var event = jQuery.event.fix( nativeEvent ); - - var i, j, ret, matched, handleObj, handlerQueue, - args = new Array( arguments.length ), - handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - - for ( i = 1; i < arguments.length; i++ ) { - args[ i ] = arguments[ i ]; - } - - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, handleObj, sel, matchedHandlers, matchedSelectors, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Find delegate handlers - if ( delegateCount && - - // Support: IE <=9 - // Black-hole SVG instance trees (trac-13180) - cur.nodeType && - - // Support: Firefox <=42 - // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) - // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click - // Support: IE 11 only - // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) - !( event.type === "click" && event.button >= 1 ) ) { - - for ( ; cur !== this; cur = cur.parentNode || this ) { - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { - matchedHandlers = []; - matchedSelectors = {}; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matchedSelectors[ sel ] === undefined ) { - matchedSelectors[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matchedSelectors[ sel ] ) { - matchedHandlers.push( handleObj ); - } - } - if ( matchedHandlers.length ) { - handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - cur = this; - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - addProp: function( name, hook ) { - Object.defineProperty( jQuery.Event.prototype, name, { - enumerable: true, - configurable: true, - - get: jQuery.isFunction( hook ) ? - function() { - if ( this.originalEvent ) { - return hook( this.originalEvent ); - } - } : - function() { - if ( this.originalEvent ) { - return this.originalEvent[ name ]; - } - }, - - set: function( value ) { - Object.defineProperty( this, name, { - enumerable: true, - configurable: true, - writable: true, - value: value - } ); - } - } ); - }, - - fix: function( originalEvent ) { - return originalEvent[ jQuery.expando ] ? - originalEvent : - new jQuery.Event( originalEvent ); - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - this.focus(); - return false; - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - } -}; - -jQuery.removeEvent = function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } -}; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: Android <=2.3 only - src.returnValue === false ? - returnTrue : - returnFalse; - - // Create target properties - // Support: Safari <=6 - 7 only - // Target should not be a text node (#504, #13143) - this.target = ( src.target && src.target.nodeType === 3 ) ? - src.target.parentNode : - src.target; - - this.currentTarget = src.currentTarget; - this.relatedTarget = src.relatedTarget; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - isSimulated: false, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - - if ( e && !this.isSimulated ) { - e.preventDefault(); - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopPropagation(); - } - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && !this.isSimulated ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Includes all common event props including KeyEvent and MouseEvent specific props -jQuery.each( { - altKey: true, - bubbles: true, - cancelable: true, - changedTouches: true, - ctrlKey: true, - detail: true, - eventPhase: true, - metaKey: true, - pageX: true, - pageY: true, - shiftKey: true, - view: true, - "char": true, - charCode: true, - key: true, - keyCode: true, - button: true, - buttons: true, - clientX: true, - clientY: true, - offsetX: true, - offsetY: true, - pointerId: true, - pointerType: true, - screenX: true, - screenY: true, - targetTouches: true, - toElement: true, - touches: true, - - which: function( event ) { - var button = event.button; - - // Add which for key events - if ( event.which == null && rkeyEvent.test( event.type ) ) { - return event.charCode != null ? event.charCode : event.keyCode; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { - if ( button & 1 ) { - return 1; - } - - if ( button & 2 ) { - return 3; - } - - if ( button & 4 ) { - return 2; - } - - return 0; - } - - return event.which; - } -}, jQuery.event.addProp ); - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - } -} ); - - -var - - /* eslint-disable max-len */ - - // See https://github.com/eslint/eslint/issues/3229 - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi, - - /* eslint-enable */ - - // Support: IE <=10 - 11, Edge 12 - 13 - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g; - -// Prefer a tbody over its parent table for containing new rows -function manipulationTarget( elem, content ) { - if ( nodeName( elem, "table" ) && - nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { - - return jQuery( ">tbody", elem )[ 0 ] || elem; - } - - return elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute( "type" ); - } - - return elem; -} - -function cloneCopyEvent( src, dest ) { - var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events; - - if ( dest.nodeType !== 1 ) { - return; - } - - // 1. Copy private data: events, handlers, etc. - if ( dataPriv.hasData( src ) ) { - pdataOld = dataPriv.access( src ); - pdataCur = dataPriv.set( dest, pdataOld ); - events = pdataOld.events; - - if ( events ) { - delete pdataCur.handle; - pdataCur.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - } - - // 2. Copy user data - if ( dataUser.hasData( src ) ) { - udataOld = dataUser.access( src ); - udataCur = jQuery.extend( {}, udataOld ); - - dataUser.set( dest, udataCur ); - } -} - -// Fix IE bugs, see support tests -function fixInput( src, dest ) { - var nodeName = dest.nodeName.toLowerCase(); - - // Fails to persist the checked state of a cloned checkbox or radio button. - if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - dest.checked = src.checked; - - // Fails to return the selected option to the default selected state when cloning options - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var fragment, first, scripts, hasScripts, node, doc, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android <=4.0 only, PhantomJS 1 only - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !dataPriv.access( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - DOMEval( node.textContent.replace( rcleanScript, "" ), doc ); - } - } - } - } - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - nodes = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = nodes[ i ] ) != null; i++ ) { - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var i, l, srcElements, destElements, - clone = elem.cloneNode( true ), - inPage = jQuery.contains( elem.ownerDocument, elem ); - - // Fix IE cloning issues - if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && - !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - fixInput( srcElements[ i ], destElements[ i ] ); - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0, l = srcElements.length; i < l; i++ ) { - cloneCopyEvent( srcElements[ i ], destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - // Return the cloned set - return clone; - }, - - cleanData: function( elems ) { - var data, elem, type, - special = jQuery.event.special, - i = 0; - - for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { - if ( acceptData( elem ) ) { - if ( ( data = elem[ dataPriv.expando ] ) ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataPriv.expando ] = undefined; - } - if ( elem[ dataUser.expando ] ) { - - // Support: Chrome <=35 - 45+ - // Assign undefined instead of using delete, see Data#remove - elem[ dataUser.expando ] = undefined; - } - } - } - } -} ); - -jQuery.fn.extend( { - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().each( function() { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - this.textContent = value; - } - } ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - if ( elem.nodeType === 1 ) { - - // Prevent memory leaks - jQuery.cleanData( getAll( elem, false ) ); - - // Remove any remaining nodes - elem.textContent = ""; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined && elem.nodeType === 1 ) { - return elem.innerHTML; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - elem = this[ i ] || {}; - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1, - i = 0; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Support: Android <=4.0 only, PhantomJS 1 only - // .get() because push.apply(_, arraylike) throws on ancient WebKit - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); -var rmargin = ( /^margin/ ); - -var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); - -var getStyles = function( elem ) { - - // Support: IE <=11 only, Firefox <=30 (#15098, #14150) - // IE throws on elements created in popups - // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" - var view = elem.ownerDocument.defaultView; - - if ( !view || !view.opener ) { - view = window; - } - - return view.getComputedStyle( elem ); - }; - - - -( function() { - - // Executing both pixelPosition & boxSizingReliable tests require only one layout - // so they're executed at the same time to save the second computation. - function computeStyleTests() { - - // This is a singleton, we need to execute it only once - if ( !div ) { - return; - } - - div.style.cssText = - "box-sizing:border-box;" + - "position:relative;display:block;" + - "margin:auto;border:1px;padding:1px;" + - "top:1%;width:50%"; - div.innerHTML = ""; - documentElement.appendChild( container ); - - var divStyle = window.getComputedStyle( div ); - pixelPositionVal = divStyle.top !== "1%"; - - // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 - reliableMarginLeftVal = divStyle.marginLeft === "2px"; - boxSizingReliableVal = divStyle.width === "4px"; - - // Support: Android 4.0 - 4.3 only - // Some styles come back with percentage values, even though they shouldn't - div.style.marginRight = "50%"; - pixelMarginRightVal = divStyle.marginRight === "4px"; - - documentElement.removeChild( container ); - - // Nullify the div so it wouldn't be stored in the memory and - // it will also be a sign that checks already performed - div = null; - } - - var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal, - container = document.createElement( "div" ), - div = document.createElement( "div" ); - - // Finish early in limited (non-browser) environments - if ( !div.style ) { - return; - } - - // Support: IE <=9 - 11 only - // Style of cloned element affects source element cloned (#8908) - div.style.backgroundClip = "content-box"; - div.cloneNode( true ).style.backgroundClip = ""; - support.clearCloneStyle = div.style.backgroundClip === "content-box"; - - container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" + - "padding:0;margin-top:1px;position:absolute"; - container.appendChild( div ); - - jQuery.extend( support, { - pixelPosition: function() { - computeStyleTests(); - return pixelPositionVal; - }, - boxSizingReliable: function() { - computeStyleTests(); - return boxSizingReliableVal; - }, - pixelMarginRight: function() { - computeStyleTests(); - return pixelMarginRightVal; - }, - reliableMarginLeft: function() { - computeStyleTests(); - return reliableMarginLeftVal; - } - } ); -} )(); - - -function curCSS( elem, name, computed ) { - var width, minWidth, maxWidth, ret, - - // Support: Firefox 51+ - // Retrieving style before computed somehow - // fixes an issue with getting wrong values - // on detached elements - style = elem.style; - - computed = computed || getStyles( elem ); - - // getPropertyValue is needed for: - // .css('filter') (IE 9 only, #12537) - // .css('--customProperty) (#3144) - if ( computed ) { - ret = computed.getPropertyValue( name ) || computed[ name ]; - - if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) { - ret = jQuery.style( elem, name ); - } - - // A tribute to the "awesome hack by Dean Edwards" - // Android Browser returns percentage for some values, - // but width seems to be reliably pixels. - // This is against the CSSOM draft spec: - // https://drafts.csswg.org/cssom/#resolved-values - if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) { - - // Remember the original values - width = style.width; - minWidth = style.minWidth; - maxWidth = style.maxWidth; - - // Put in the new values to get a computed value out - style.minWidth = style.maxWidth = style.width = ret; - ret = computed.width; - - // Revert the changed values - style.width = width; - style.minWidth = minWidth; - style.maxWidth = maxWidth; - } - } - - return ret !== undefined ? - - // Support: IE <=9 - 11 only - // IE returns zIndex value as an integer. - ret + "" : - ret; -} - - -function addGetHookIf( conditionFn, hookFn ) { - - // Define the hook, we'll check on the first run if it's really needed. - return { - get: function() { - if ( conditionFn() ) { - - // Hook not needed (or it's not possible to use it due - // to missing dependency), remove it. - delete this.get; - return; - } - - // Hook needed; redefine it so that the support test is not executed again. - return ( this.get = hookFn ).apply( this, arguments ); - } - }; -} - - -var - - // Swappable if display is none or starts with table - // except "table", "table-cell", or "table-caption" - // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display - rdisplayswap = /^(none|table(?!-c[ea]).+)/, - rcustomProp = /^--/, - cssShow = { position: "absolute", visibility: "hidden", display: "block" }, - cssNormalTransform = { - letterSpacing: "0", - fontWeight: "400" - }, - - cssPrefixes = [ "Webkit", "Moz", "ms" ], - emptyStyle = document.createElement( "div" ).style; - -// Return a css property mapped to a potentially vendor prefixed property -function vendorPropName( name ) { - - // Shortcut for names that are not vendor prefixed - if ( name in emptyStyle ) { - return name; - } - - // Check for vendor prefixed names - var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), - i = cssPrefixes.length; - - while ( i-- ) { - name = cssPrefixes[ i ] + capName; - if ( name in emptyStyle ) { - return name; - } - } -} - -// Return a property mapped along what jQuery.cssProps suggests or to -// a vendor prefixed property. -function finalPropName( name ) { - var ret = jQuery.cssProps[ name ]; - if ( !ret ) { - ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name; - } - return ret; -} - -function setPositiveNumber( elem, value, subtract ) { - - // Any relative (+/-) values have already been - // normalized at this point - var matches = rcssNum.exec( value ); - return matches ? - - // Guard against undefined "subtract", e.g., when used as in cssHooks - Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : - value; -} - -function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) { - var i, - val = 0; - - // If we already have the right measurement, avoid augmentation - if ( extra === ( isBorderBox ? "border" : "content" ) ) { - i = 4; - - // Otherwise initialize for horizontal or vertical properties - } else { - i = name === "width" ? 1 : 0; - } - - for ( ; i < 4; i += 2 ) { - - // Both box models exclude margin, so add it if we want it - if ( extra === "margin" ) { - val += jQuery.css( elem, extra + cssExpand[ i ], true, styles ); - } - - if ( isBorderBox ) { - - // border-box includes padding, so remove it if we want content - if ( extra === "content" ) { - val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - } - - // At this point, extra isn't border nor margin, so remove border - if ( extra !== "margin" ) { - val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } else { - - // At this point, extra isn't content, so add padding - val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); - - // At this point, extra isn't content nor padding, so add border - if ( extra !== "padding" ) { - val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); - } - } - } - - return val; -} - -function getWidthOrHeight( elem, name, extra ) { - - // Start with computed style - var valueIsBorderBox, - styles = getStyles( elem ), - val = curCSS( elem, name, styles ), - isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; - - // Computed unit is not pixels. Stop here and return. - if ( rnumnonpx.test( val ) ) { - return val; - } - - // Check for style in case a browser which returns unreliable values - // for getComputedStyle silently falls back to the reliable elem.style - valueIsBorderBox = isBorderBox && - ( support.boxSizingReliable() || val === elem.style[ name ] ); - - // Fall back to offsetWidth/Height when value is "auto" - // This happens for inline elements with no explicit setting (gh-3571) - if ( val === "auto" ) { - val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ]; - } - - // Normalize "", auto, and prepare for extra - val = parseFloat( val ) || 0; - - // Use the active box-sizing model to add/subtract irrelevant styles - return ( val + - augmentWidthOrHeight( - elem, - name, - extra || ( isBorderBox ? "border" : "content" ), - valueIsBorderBox, - styles - ) - ) + "px"; -} - -jQuery.extend( { - - // Add in style property hooks for overriding the default - // behavior of getting and setting a style property - cssHooks: { - opacity: { - get: function( elem, computed ) { - if ( computed ) { - - // We should always get a number back from opacity - var ret = curCSS( elem, "opacity" ); - return ret === "" ? "1" : ret; - } - } - } - }, - - // Don't automatically add "px" to these possibly-unitless properties - cssNumber: { - "animationIterationCount": true, - "columnCount": true, - "fillOpacity": true, - "flexGrow": true, - "flexShrink": true, - "fontWeight": true, - "lineHeight": true, - "opacity": true, - "order": true, - "orphans": true, - "widows": true, - "zIndex": true, - "zoom": true - }, - - // Add in properties whose names you wish to fix before - // setting or getting the value - cssProps: { - "float": "cssFloat" - }, - - // Get and set the style property on a DOM Node - style: function( elem, name, value, extra ) { - - // Don't set styles on text and comment nodes - if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { - return; - } - - // Make sure that we're working with the right name - var ret, type, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ), - style = elem.style; - - // Make sure that we're working with the right name. We don't - // want to query the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Gets hook for the prefixed version, then unprefixed version - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // Check if we're setting a value - if ( value !== undefined ) { - type = typeof value; - - // Convert "+=" or "-=" to relative numbers (#7345) - if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { - value = adjustCSS( elem, name, ret ); - - // Fixes bug #9237 - type = "number"; - } - - // Make sure that null and NaN values aren't set (#7116) - if ( value == null || value !== value ) { - return; - } - - // If a number was passed in, add the unit (except for certain CSS properties) - if ( type === "number" ) { - value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); - } - - // background-* props affect original clone's values - if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { - style[ name ] = "inherit"; - } - - // If a hook was provided, use that value, otherwise just set the specified value - if ( !hooks || !( "set" in hooks ) || - ( value = hooks.set( elem, value, extra ) ) !== undefined ) { - - if ( isCustomProp ) { - style.setProperty( name, value ); - } else { - style[ name ] = value; - } - } - - } else { - - // If a hook was provided get the non-computed value from there - if ( hooks && "get" in hooks && - ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { - - return ret; - } - - // Otherwise just get the value from the style object - return style[ name ]; - } - }, - - css: function( elem, name, extra, styles ) { - var val, num, hooks, - origName = jQuery.camelCase( name ), - isCustomProp = rcustomProp.test( name ); - - // Make sure that we're working with the right name. We don't - // want to modify the value if it is a CSS custom property - // since they are user-defined. - if ( !isCustomProp ) { - name = finalPropName( origName ); - } - - // Try prefixed name followed by the unprefixed name - hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; - - // If a hook was provided get the computed value from there - if ( hooks && "get" in hooks ) { - val = hooks.get( elem, true, extra ); - } - - // Otherwise, if a way to get the computed value exists, use that - if ( val === undefined ) { - val = curCSS( elem, name, styles ); - } - - // Convert "normal" to computed value - if ( val === "normal" && name in cssNormalTransform ) { - val = cssNormalTransform[ name ]; - } - - // Make numeric if forced or a qualifier was provided and val looks numeric - if ( extra === "" || extra ) { - num = parseFloat( val ); - return extra === true || isFinite( num ) ? num || 0 : val; - } - - return val; - } -} ); - -jQuery.each( [ "height", "width" ], function( i, name ) { - jQuery.cssHooks[ name ] = { - get: function( elem, computed, extra ) { - if ( computed ) { - - // Certain elements can have dimension info if we invisibly show them - // but it must have a current display style that would benefit - return rdisplayswap.test( jQuery.css( elem, "display" ) ) && - - // Support: Safari 8+ - // Table columns in Safari have non-zero offsetWidth & zero - // getBoundingClientRect().width unless display is changed. - // Support: IE <=11 only - // Running getBoundingClientRect on a disconnected node - // in IE throws an error. - ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? - swap( elem, cssShow, function() { - return getWidthOrHeight( elem, name, extra ); - } ) : - getWidthOrHeight( elem, name, extra ); - } - }, - - set: function( elem, value, extra ) { - var matches, - styles = extra && getStyles( elem ), - subtract = extra && augmentWidthOrHeight( - elem, - name, - extra, - jQuery.css( elem, "boxSizing", false, styles ) === "border-box", - styles - ); - - // Convert to pixels if value adjustment is needed - if ( subtract && ( matches = rcssNum.exec( value ) ) && - ( matches[ 3 ] || "px" ) !== "px" ) { - - elem.style[ name ] = value; - value = jQuery.css( elem, name ); - } - - return setPositiveNumber( elem, value, subtract ); - } - }; -} ); - -jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, - function( elem, computed ) { - if ( computed ) { - return ( parseFloat( curCSS( elem, "marginLeft" ) ) || - elem.getBoundingClientRect().left - - swap( elem, { marginLeft: 0 }, function() { - return elem.getBoundingClientRect().left; - } ) - ) + "px"; - } - } -); - -// These hooks are used by animate to expand properties -jQuery.each( { - margin: "", - padding: "", - border: "Width" -}, function( prefix, suffix ) { - jQuery.cssHooks[ prefix + suffix ] = { - expand: function( value ) { - var i = 0, - expanded = {}, - - // Assumes a single number if not a string - parts = typeof value === "string" ? value.split( " " ) : [ value ]; - - for ( ; i < 4; i++ ) { - expanded[ prefix + cssExpand[ i ] + suffix ] = - parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; - } - - return expanded; - } - }; - - if ( !rmargin.test( prefix ) ) { - jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; - } -} ); - -jQuery.fn.extend( { - css: function( name, value ) { - return access( this, function( elem, name, value ) { - var styles, len, - map = {}, - i = 0; - - if ( Array.isArray( name ) ) { - styles = getStyles( elem ); - len = name.length; - - for ( ; i < len; i++ ) { - map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); - } - - return map; - } - - return value !== undefined ? - jQuery.style( elem, name, value ) : - jQuery.css( elem, name ); - }, name, value, arguments.length > 1 ); - } -} ); - - -function Tween( elem, options, prop, end, easing ) { - return new Tween.prototype.init( elem, options, prop, end, easing ); -} -jQuery.Tween = Tween; - -Tween.prototype = { - constructor: Tween, - init: function( elem, options, prop, end, easing, unit ) { - this.elem = elem; - this.prop = prop; - this.easing = easing || jQuery.easing._default; - this.options = options; - this.start = this.now = this.cur(); - this.end = end; - this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); - }, - cur: function() { - var hooks = Tween.propHooks[ this.prop ]; - - return hooks && hooks.get ? - hooks.get( this ) : - Tween.propHooks._default.get( this ); - }, - run: function( percent ) { - var eased, - hooks = Tween.propHooks[ this.prop ]; - - if ( this.options.duration ) { - this.pos = eased = jQuery.easing[ this.easing ]( - percent, this.options.duration * percent, 0, 1, this.options.duration - ); - } else { - this.pos = eased = percent; - } - this.now = ( this.end - this.start ) * eased + this.start; - - if ( this.options.step ) { - this.options.step.call( this.elem, this.now, this ); - } - - if ( hooks && hooks.set ) { - hooks.set( this ); - } else { - Tween.propHooks._default.set( this ); - } - return this; - } -}; - -Tween.prototype.init.prototype = Tween.prototype; - -Tween.propHooks = { - _default: { - get: function( tween ) { - var result; - - // Use a property on the element directly when it is not a DOM element, - // or when there is no matching style property that exists. - if ( tween.elem.nodeType !== 1 || - tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { - return tween.elem[ tween.prop ]; - } - - // Passing an empty string as a 3rd parameter to .css will automatically - // attempt a parseFloat and fallback to a string if the parse fails. - // Simple values such as "10px" are parsed to Float; - // complex values such as "rotate(1rad)" are returned as-is. - result = jQuery.css( tween.elem, tween.prop, "" ); - - // Empty strings, null, undefined and "auto" are converted to 0. - return !result || result === "auto" ? 0 : result; - }, - set: function( tween ) { - - // Use step hook for back compat. - // Use cssHook if its there. - // Use .style if available and use plain properties where available. - if ( jQuery.fx.step[ tween.prop ] ) { - jQuery.fx.step[ tween.prop ]( tween ); - } else if ( tween.elem.nodeType === 1 && - ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || - jQuery.cssHooks[ tween.prop ] ) ) { - jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); - } else { - tween.elem[ tween.prop ] = tween.now; - } - } - } -}; - -// Support: IE <=9 only -// Panic based approach to setting things on disconnected nodes -Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { - set: function( tween ) { - if ( tween.elem.nodeType && tween.elem.parentNode ) { - tween.elem[ tween.prop ] = tween.now; - } - } -}; - -jQuery.easing = { - linear: function( p ) { - return p; - }, - swing: function( p ) { - return 0.5 - Math.cos( p * Math.PI ) / 2; - }, - _default: "swing" -}; - -jQuery.fx = Tween.prototype.init; - -// Back compat <1.8 extension point -jQuery.fx.step = {}; - - - - -var - fxNow, inProgress, - rfxtypes = /^(?:toggle|show|hide)$/, - rrun = /queueHooks$/; - -function schedule() { - if ( inProgress ) { - if ( document.hidden === false && window.requestAnimationFrame ) { - window.requestAnimationFrame( schedule ); - } else { - window.setTimeout( schedule, jQuery.fx.interval ); - } - - jQuery.fx.tick(); - } -} - -// Animations created synchronously will run synchronously -function createFxNow() { - window.setTimeout( function() { - fxNow = undefined; - } ); - return ( fxNow = jQuery.now() ); -} - -// Generate parameters to create a standard animation -function genFx( type, includeWidth ) { - var which, - i = 0, - attrs = { height: type }; - - // If we include width, step value is 1 to do all cssExpand values, - // otherwise step value is 2 to skip over Left and Right - includeWidth = includeWidth ? 1 : 0; - for ( ; i < 4; i += 2 - includeWidth ) { - which = cssExpand[ i ]; - attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; - } - - if ( includeWidth ) { - attrs.opacity = attrs.width = type; - } - - return attrs; -} - -function createTween( value, prop, animation ) { - var tween, - collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), - index = 0, - length = collection.length; - for ( ; index < length; index++ ) { - if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { - - // We're done with this property - return tween; - } - } -} - -function defaultPrefilter( elem, props, opts ) { - var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, - isBox = "width" in props || "height" in props, - anim = this, - orig = {}, - style = elem.style, - hidden = elem.nodeType && isHiddenWithinTree( elem ), - dataShow = dataPriv.get( elem, "fxshow" ); - - // Queue-skipping animations hijack the fx hooks - if ( !opts.queue ) { - hooks = jQuery._queueHooks( elem, "fx" ); - if ( hooks.unqueued == null ) { - hooks.unqueued = 0; - oldfire = hooks.empty.fire; - hooks.empty.fire = function() { - if ( !hooks.unqueued ) { - oldfire(); - } - }; - } - hooks.unqueued++; - - anim.always( function() { - - // Ensure the complete handler is called before this completes - anim.always( function() { - hooks.unqueued--; - if ( !jQuery.queue( elem, "fx" ).length ) { - hooks.empty.fire(); - } - } ); - } ); - } - - // Detect show/hide animations - for ( prop in props ) { - value = props[ prop ]; - if ( rfxtypes.test( value ) ) { - delete props[ prop ]; - toggle = toggle || value === "toggle"; - if ( value === ( hidden ? "hide" : "show" ) ) { - - // Pretend to be hidden if this is a "show" and - // there is still data from a stopped show/hide - if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { - hidden = true; - - // Ignore all other no-op show/hide data - } else { - continue; - } - } - orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); - } - } - - // Bail out if this is a no-op like .hide().hide() - propTween = !jQuery.isEmptyObject( props ); - if ( !propTween && jQuery.isEmptyObject( orig ) ) { - return; - } - - // Restrict "overflow" and "display" styles during box animations - if ( isBox && elem.nodeType === 1 ) { - - // Support: IE <=9 - 11, Edge 12 - 13 - // Record all 3 overflow attributes because IE does not infer the shorthand - // from identically-valued overflowX and overflowY - opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; - - // Identify a display type, preferring old show/hide data over the CSS cascade - restoreDisplay = dataShow && dataShow.display; - if ( restoreDisplay == null ) { - restoreDisplay = dataPriv.get( elem, "display" ); - } - display = jQuery.css( elem, "display" ); - if ( display === "none" ) { - if ( restoreDisplay ) { - display = restoreDisplay; - } else { - - // Get nonempty value(s) by temporarily forcing visibility - showHide( [ elem ], true ); - restoreDisplay = elem.style.display || restoreDisplay; - display = jQuery.css( elem, "display" ); - showHide( [ elem ] ); - } - } - - // Animate inline elements as inline-block - if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { - if ( jQuery.css( elem, "float" ) === "none" ) { - - // Restore the original display value at the end of pure show/hide animations - if ( !propTween ) { - anim.done( function() { - style.display = restoreDisplay; - } ); - if ( restoreDisplay == null ) { - display = style.display; - restoreDisplay = display === "none" ? "" : display; - } - } - style.display = "inline-block"; - } - } - } - - if ( opts.overflow ) { - style.overflow = "hidden"; - anim.always( function() { - style.overflow = opts.overflow[ 0 ]; - style.overflowX = opts.overflow[ 1 ]; - style.overflowY = opts.overflow[ 2 ]; - } ); - } - - // Implement show/hide animations - propTween = false; - for ( prop in orig ) { - - // General show/hide setup for this element animation - if ( !propTween ) { - if ( dataShow ) { - if ( "hidden" in dataShow ) { - hidden = dataShow.hidden; - } - } else { - dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); - } - - // Store hidden/visible for toggle so `.stop().toggle()` "reverses" - if ( toggle ) { - dataShow.hidden = !hidden; - } - - // Show elements before animating them - if ( hidden ) { - showHide( [ elem ], true ); - } - - /* eslint-disable no-loop-func */ - - anim.done( function() { - - /* eslint-enable no-loop-func */ - - // The final step of a "hide" animation is actually hiding the element - if ( !hidden ) { - showHide( [ elem ] ); - } - dataPriv.remove( elem, "fxshow" ); - for ( prop in orig ) { - jQuery.style( elem, prop, orig[ prop ] ); - } - } ); - } - - // Per-property setup - propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); - if ( !( prop in dataShow ) ) { - dataShow[ prop ] = propTween.start; - if ( hidden ) { - propTween.end = propTween.start; - propTween.start = 0; - } - } - } -} - -function propFilter( props, specialEasing ) { - var index, name, easing, value, hooks; - - // camelCase, specialEasing and expand cssHook pass - for ( index in props ) { - name = jQuery.camelCase( index ); - easing = specialEasing[ name ]; - value = props[ index ]; - if ( Array.isArray( value ) ) { - easing = value[ 1 ]; - value = props[ index ] = value[ 0 ]; - } - - if ( index !== name ) { - props[ name ] = value; - delete props[ index ]; - } - - hooks = jQuery.cssHooks[ name ]; - if ( hooks && "expand" in hooks ) { - value = hooks.expand( value ); - delete props[ name ]; - - // Not quite $.extend, this won't overwrite existing keys. - // Reusing 'index' because we have the correct "name" - for ( index in value ) { - if ( !( index in props ) ) { - props[ index ] = value[ index ]; - specialEasing[ index ] = easing; - } - } - } else { - specialEasing[ name ] = easing; - } - } -} - -function Animation( elem, properties, options ) { - var result, - stopped, - index = 0, - length = Animation.prefilters.length, - deferred = jQuery.Deferred().always( function() { - - // Don't match elem in the :animated selector - delete tick.elem; - } ), - tick = function() { - if ( stopped ) { - return false; - } - var currentTime = fxNow || createFxNow(), - remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), - - // Support: Android 2.3 only - // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) - temp = remaining / animation.duration || 0, - percent = 1 - temp, - index = 0, - length = animation.tweens.length; - - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( percent ); - } - - deferred.notifyWith( elem, [ animation, percent, remaining ] ); - - // If there's more to do, yield - if ( percent < 1 && length ) { - return remaining; - } - - // If this was an empty animation, synthesize a final progress notification - if ( !length ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - } - - // Resolve the animation and report its conclusion - deferred.resolveWith( elem, [ animation ] ); - return false; - }, - animation = deferred.promise( { - elem: elem, - props: jQuery.extend( {}, properties ), - opts: jQuery.extend( true, { - specialEasing: {}, - easing: jQuery.easing._default - }, options ), - originalProperties: properties, - originalOptions: options, - startTime: fxNow || createFxNow(), - duration: options.duration, - tweens: [], - createTween: function( prop, end ) { - var tween = jQuery.Tween( elem, animation.opts, prop, end, - animation.opts.specialEasing[ prop ] || animation.opts.easing ); - animation.tweens.push( tween ); - return tween; - }, - stop: function( gotoEnd ) { - var index = 0, - - // If we are going to the end, we want to run all the tweens - // otherwise we skip this part - length = gotoEnd ? animation.tweens.length : 0; - if ( stopped ) { - return this; - } - stopped = true; - for ( ; index < length; index++ ) { - animation.tweens[ index ].run( 1 ); - } - - // Resolve when we played the last frame; otherwise, reject - if ( gotoEnd ) { - deferred.notifyWith( elem, [ animation, 1, 0 ] ); - deferred.resolveWith( elem, [ animation, gotoEnd ] ); - } else { - deferred.rejectWith( elem, [ animation, gotoEnd ] ); - } - return this; - } - } ), - props = animation.props; - - propFilter( props, animation.opts.specialEasing ); - - for ( ; index < length; index++ ) { - result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); - if ( result ) { - if ( jQuery.isFunction( result.stop ) ) { - jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = - jQuery.proxy( result.stop, result ); - } - return result; - } - } - - jQuery.map( props, createTween, animation ); - - if ( jQuery.isFunction( animation.opts.start ) ) { - animation.opts.start.call( elem, animation ); - } - - // Attach callbacks from options - animation - .progress( animation.opts.progress ) - .done( animation.opts.done, animation.opts.complete ) - .fail( animation.opts.fail ) - .always( animation.opts.always ); - - jQuery.fx.timer( - jQuery.extend( tick, { - elem: elem, - anim: animation, - queue: animation.opts.queue - } ) - ); - - return animation; -} - -jQuery.Animation = jQuery.extend( Animation, { - - tweeners: { - "*": [ function( prop, value ) { - var tween = this.createTween( prop, value ); - adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); - return tween; - } ] - }, - - tweener: function( props, callback ) { - if ( jQuery.isFunction( props ) ) { - callback = props; - props = [ "*" ]; - } else { - props = props.match( rnothtmlwhite ); - } - - var prop, - index = 0, - length = props.length; - - for ( ; index < length; index++ ) { - prop = props[ index ]; - Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; - Animation.tweeners[ prop ].unshift( callback ); - } - }, - - prefilters: [ defaultPrefilter ], - - prefilter: function( callback, prepend ) { - if ( prepend ) { - Animation.prefilters.unshift( callback ); - } else { - Animation.prefilters.push( callback ); - } - } -} ); - -jQuery.speed = function( speed, easing, fn ) { - var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { - complete: fn || !fn && easing || - jQuery.isFunction( speed ) && speed, - duration: speed, - easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing - }; - - // Go to the end state if fx are off - if ( jQuery.fx.off ) { - opt.duration = 0; - - } else { - if ( typeof opt.duration !== "number" ) { - if ( opt.duration in jQuery.fx.speeds ) { - opt.duration = jQuery.fx.speeds[ opt.duration ]; - - } else { - opt.duration = jQuery.fx.speeds._default; - } - } - } - - // Normalize opt.queue - true/undefined/null -> "fx" - if ( opt.queue == null || opt.queue === true ) { - opt.queue = "fx"; - } - - // Queueing - opt.old = opt.complete; - - opt.complete = function() { - if ( jQuery.isFunction( opt.old ) ) { - opt.old.call( this ); - } - - if ( opt.queue ) { - jQuery.dequeue( this, opt.queue ); - } - }; - - return opt; -}; - -jQuery.fn.extend( { - fadeTo: function( speed, to, easing, callback ) { - - // Show any hidden elements after setting opacity to 0 - return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() - - // Animate to the value specified - .end().animate( { opacity: to }, speed, easing, callback ); - }, - animate: function( prop, speed, easing, callback ) { - var empty = jQuery.isEmptyObject( prop ), - optall = jQuery.speed( speed, easing, callback ), - doAnimation = function() { - - // Operate on a copy of prop so per-property easing won't be lost - var anim = Animation( this, jQuery.extend( {}, prop ), optall ); - - // Empty animations, or finishing resolves immediately - if ( empty || dataPriv.get( this, "finish" ) ) { - anim.stop( true ); - } - }; - doAnimation.finish = doAnimation; - - return empty || optall.queue === false ? - this.each( doAnimation ) : - this.queue( optall.queue, doAnimation ); - }, - stop: function( type, clearQueue, gotoEnd ) { - var stopQueue = function( hooks ) { - var stop = hooks.stop; - delete hooks.stop; - stop( gotoEnd ); - }; - - if ( typeof type !== "string" ) { - gotoEnd = clearQueue; - clearQueue = type; - type = undefined; - } - if ( clearQueue && type !== false ) { - this.queue( type || "fx", [] ); - } - - return this.each( function() { - var dequeue = true, - index = type != null && type + "queueHooks", - timers = jQuery.timers, - data = dataPriv.get( this ); - - if ( index ) { - if ( data[ index ] && data[ index ].stop ) { - stopQueue( data[ index ] ); - } - } else { - for ( index in data ) { - if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { - stopQueue( data[ index ] ); - } - } - } - - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && - ( type == null || timers[ index ].queue === type ) ) { - - timers[ index ].anim.stop( gotoEnd ); - dequeue = false; - timers.splice( index, 1 ); - } - } - - // Start the next in the queue if the last step wasn't forced. - // Timers currently will call their complete callbacks, which - // will dequeue but only if they were gotoEnd. - if ( dequeue || !gotoEnd ) { - jQuery.dequeue( this, type ); - } - } ); - }, - finish: function( type ) { - if ( type !== false ) { - type = type || "fx"; - } - return this.each( function() { - var index, - data = dataPriv.get( this ), - queue = data[ type + "queue" ], - hooks = data[ type + "queueHooks" ], - timers = jQuery.timers, - length = queue ? queue.length : 0; - - // Enable finishing flag on private data - data.finish = true; - - // Empty the queue first - jQuery.queue( this, type, [] ); - - if ( hooks && hooks.stop ) { - hooks.stop.call( this, true ); - } - - // Look for any active animations, and finish them - for ( index = timers.length; index--; ) { - if ( timers[ index ].elem === this && timers[ index ].queue === type ) { - timers[ index ].anim.stop( true ); - timers.splice( index, 1 ); - } - } - - // Look for any animations in the old queue and finish them - for ( index = 0; index < length; index++ ) { - if ( queue[ index ] && queue[ index ].finish ) { - queue[ index ].finish.call( this ); - } - } - - // Turn off finishing flag - delete data.finish; - } ); - } -} ); - -jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) { - var cssFn = jQuery.fn[ name ]; - jQuery.fn[ name ] = function( speed, easing, callback ) { - return speed == null || typeof speed === "boolean" ? - cssFn.apply( this, arguments ) : - this.animate( genFx( name, true ), speed, easing, callback ); - }; -} ); - -// Generate shortcuts for custom animations -jQuery.each( { - slideDown: genFx( "show" ), - slideUp: genFx( "hide" ), - slideToggle: genFx( "toggle" ), - fadeIn: { opacity: "show" }, - fadeOut: { opacity: "hide" }, - fadeToggle: { opacity: "toggle" } -}, function( name, props ) { - jQuery.fn[ name ] = function( speed, easing, callback ) { - return this.animate( props, speed, easing, callback ); - }; -} ); - -jQuery.timers = []; -jQuery.fx.tick = function() { - var timer, - i = 0, - timers = jQuery.timers; - - fxNow = jQuery.now(); - - for ( ; i < timers.length; i++ ) { - timer = timers[ i ]; - - // Run the timer and safely remove it when done (allowing for external removal) - if ( !timer() && timers[ i ] === timer ) { - timers.splice( i--, 1 ); - } - } - - if ( !timers.length ) { - jQuery.fx.stop(); - } - fxNow = undefined; -}; - -jQuery.fx.timer = function( timer ) { - jQuery.timers.push( timer ); - jQuery.fx.start(); -}; - -jQuery.fx.interval = 13; -jQuery.fx.start = function() { - if ( inProgress ) { - return; - } - - inProgress = true; - schedule(); -}; - -jQuery.fx.stop = function() { - inProgress = null; -}; - -jQuery.fx.speeds = { - slow: 600, - fast: 200, - - // Default speed - _default: 400 -}; - - -// Based off of the plugin by Clint Helfers, with permission. -// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ -jQuery.fn.delay = function( time, type ) { - time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; - type = type || "fx"; - - return this.queue( type, function( next, hooks ) { - var timeout = window.setTimeout( next, time ); - hooks.stop = function() { - window.clearTimeout( timeout ); - }; - } ); -}; - - -( function() { - var input = document.createElement( "input" ), - select = document.createElement( "select" ), - opt = select.appendChild( document.createElement( "option" ) ); - - input.type = "checkbox"; - - // Support: Android <=4.3 only - // Default value for a checkbox should be "on" - support.checkOn = input.value !== ""; - - // Support: IE <=11 only - // Must access selectedIndex to make default options select - support.optSelected = opt.selected; - - // Support: IE <=11 only - // An input loses its value after becoming a radio - input = document.createElement( "input" ); - input.value = "t"; - input.type = "radio"; - support.radioValue = input.value === "t"; -} )(); - - -var boolHook, - attrHandle = jQuery.expr.attrHandle; - -jQuery.fn.extend( { - attr: function( name, value ) { - return access( this, jQuery.attr, name, value, arguments.length > 1 ); - }, - - removeAttr: function( name ) { - return this.each( function() { - jQuery.removeAttr( this, name ); - } ); - } -} ); - -jQuery.extend( { - attr: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set attributes on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - // Fallback to prop when attributes are not supported - if ( typeof elem.getAttribute === "undefined" ) { - return jQuery.prop( elem, name, value ); - } - - // Attribute hooks are determined by the lowercase version - // Grab necessary hook if one is defined - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - hooks = jQuery.attrHooks[ name.toLowerCase() ] || - ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); - } - - if ( value !== undefined ) { - if ( value === null ) { - jQuery.removeAttr( elem, name ); - return; - } - - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - elem.setAttribute( name, value + "" ); - return value; - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - ret = jQuery.find.attr( elem, name ); - - // Non-existent attributes return null, we normalize to undefined - return ret == null ? undefined : ret; - }, - - attrHooks: { - type: { - set: function( elem, value ) { - if ( !support.radioValue && value === "radio" && - nodeName( elem, "input" ) ) { - var val = elem.value; - elem.setAttribute( "type", value ); - if ( val ) { - elem.value = val; - } - return value; - } - } - } - }, - - removeAttr: function( elem, value ) { - var name, - i = 0, - - // Attribute names can contain non-HTML whitespace characters - // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 - attrNames = value && value.match( rnothtmlwhite ); - - if ( attrNames && elem.nodeType === 1 ) { - while ( ( name = attrNames[ i++ ] ) ) { - elem.removeAttribute( name ); - } - } - } -} ); - -// Hooks for boolean attributes -boolHook = { - set: function( elem, value, name ) { - if ( value === false ) { - - // Remove boolean attributes when set to false - jQuery.removeAttr( elem, name ); - } else { - elem.setAttribute( name, name ); - } - return name; - } -}; - -jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) { - var getter = attrHandle[ name ] || jQuery.find.attr; - - attrHandle[ name ] = function( elem, name, isXML ) { - var ret, handle, - lowercaseName = name.toLowerCase(); - - if ( !isXML ) { - - // Avoid an infinite loop by temporarily removing this function from the getter - handle = attrHandle[ lowercaseName ]; - attrHandle[ lowercaseName ] = ret; - ret = getter( elem, name, isXML ) != null ? - lowercaseName : - null; - attrHandle[ lowercaseName ] = handle; - } - return ret; - }; -} ); - - - - -var rfocusable = /^(?:input|select|textarea|button)$/i, - rclickable = /^(?:a|area)$/i; - -jQuery.fn.extend( { - prop: function( name, value ) { - return access( this, jQuery.prop, name, value, arguments.length > 1 ); - }, - - removeProp: function( name ) { - return this.each( function() { - delete this[ jQuery.propFix[ name ] || name ]; - } ); - } -} ); - -jQuery.extend( { - prop: function( elem, name, value ) { - var ret, hooks, - nType = elem.nodeType; - - // Don't get/set properties on text, comment and attribute nodes - if ( nType === 3 || nType === 8 || nType === 2 ) { - return; - } - - if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { - - // Fix name and attach hooks - name = jQuery.propFix[ name ] || name; - hooks = jQuery.propHooks[ name ]; - } - - if ( value !== undefined ) { - if ( hooks && "set" in hooks && - ( ret = hooks.set( elem, value, name ) ) !== undefined ) { - return ret; - } - - return ( elem[ name ] = value ); - } - - if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { - return ret; - } - - return elem[ name ]; - }, - - propHooks: { - tabIndex: { - get: function( elem ) { - - // Support: IE <=9 - 11 only - // elem.tabIndex doesn't always return the - // correct value when it hasn't been explicitly set - // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ - // Use proper attribute retrieval(#12072) - var tabindex = jQuery.find.attr( elem, "tabindex" ); - - if ( tabindex ) { - return parseInt( tabindex, 10 ); - } - - if ( - rfocusable.test( elem.nodeName ) || - rclickable.test( elem.nodeName ) && - elem.href - ) { - return 0; - } - - return -1; - } - } - }, - - propFix: { - "for": "htmlFor", - "class": "className" - } -} ); - -// Support: IE <=11 only -// Accessing the selectedIndex property -// forces the browser to respect setting selected -// on the option -// The getter ensures a default option is selected -// when in an optgroup -// eslint rule "no-unused-expressions" is disabled for this code -// since it considers such accessions noop -if ( !support.optSelected ) { - jQuery.propHooks.selected = { - get: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent && parent.parentNode ) { - parent.parentNode.selectedIndex; - } - return null; - }, - set: function( elem ) { - - /* eslint no-unused-expressions: "off" */ - - var parent = elem.parentNode; - if ( parent ) { - parent.selectedIndex; - - if ( parent.parentNode ) { - parent.parentNode.selectedIndex; - } - } - } - }; -} - -jQuery.each( [ - "tabIndex", - "readOnly", - "maxLength", - "cellSpacing", - "cellPadding", - "rowSpan", - "colSpan", - "useMap", - "frameBorder", - "contentEditable" -], function() { - jQuery.propFix[ this.toLowerCase() ] = this; -} ); - - - - - // Strip and collapse whitespace according to HTML spec - // https://html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace - function stripAndCollapse( value ) { - var tokens = value.match( rnothtmlwhite ) || []; - return tokens.join( " " ); - } - - -function getClass( elem ) { - return elem.getAttribute && elem.getAttribute( "class" ) || ""; -} - -jQuery.fn.extend( { - addClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - if ( cur.indexOf( " " + clazz + " " ) < 0 ) { - cur += clazz + " "; - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - removeClass: function( value ) { - var classes, elem, cur, curValue, clazz, j, finalValue, - i = 0; - - if ( jQuery.isFunction( value ) ) { - return this.each( function( j ) { - jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); - } ); - } - - if ( !arguments.length ) { - return this.attr( "class", "" ); - } - - if ( typeof value === "string" && value ) { - classes = value.match( rnothtmlwhite ) || []; - - while ( ( elem = this[ i++ ] ) ) { - curValue = getClass( elem ); - - // This expression is here for better compressibility (see addClass) - cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); - - if ( cur ) { - j = 0; - while ( ( clazz = classes[ j++ ] ) ) { - - // Remove *all* instances - while ( cur.indexOf( " " + clazz + " " ) > -1 ) { - cur = cur.replace( " " + clazz + " ", " " ); - } - } - - // Only assign if different to avoid unneeded rendering. - finalValue = stripAndCollapse( cur ); - if ( curValue !== finalValue ) { - elem.setAttribute( "class", finalValue ); - } - } - } - } - - return this; - }, - - toggleClass: function( value, stateVal ) { - var type = typeof value; - - if ( typeof stateVal === "boolean" && type === "string" ) { - return stateVal ? this.addClass( value ) : this.removeClass( value ); - } - - if ( jQuery.isFunction( value ) ) { - return this.each( function( i ) { - jQuery( this ).toggleClass( - value.call( this, i, getClass( this ), stateVal ), - stateVal - ); - } ); - } - - return this.each( function() { - var className, i, self, classNames; - - if ( type === "string" ) { - - // Toggle individual class names - i = 0; - self = jQuery( this ); - classNames = value.match( rnothtmlwhite ) || []; - - while ( ( className = classNames[ i++ ] ) ) { - - // Check each className given, space separated list - if ( self.hasClass( className ) ) { - self.removeClass( className ); - } else { - self.addClass( className ); - } - } - - // Toggle whole class name - } else if ( value === undefined || type === "boolean" ) { - className = getClass( this ); - if ( className ) { - - // Store className if set - dataPriv.set( this, "__className__", className ); - } - - // If the element has a class name or if we're passed `false`, - // then remove the whole classname (if there was one, the above saved it). - // Otherwise bring back whatever was previously saved (if anything), - // falling back to the empty string if nothing was stored. - if ( this.setAttribute ) { - this.setAttribute( "class", - className || value === false ? - "" : - dataPriv.get( this, "__className__" ) || "" - ); - } - } - } ); - }, - - hasClass: function( selector ) { - var className, elem, - i = 0; - - className = " " + selector + " "; - while ( ( elem = this[ i++ ] ) ) { - if ( elem.nodeType === 1 && - ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { - return true; - } - } - - return false; - } -} ); - - - - -var rreturn = /\r/g; - -jQuery.fn.extend( { - val: function( value ) { - var hooks, ret, isFunction, - elem = this[ 0 ]; - - if ( !arguments.length ) { - if ( elem ) { - hooks = jQuery.valHooks[ elem.type ] || - jQuery.valHooks[ elem.nodeName.toLowerCase() ]; - - if ( hooks && - "get" in hooks && - ( ret = hooks.get( elem, "value" ) ) !== undefined - ) { - return ret; - } - - ret = elem.value; - - // Handle most common string cases - if ( typeof ret === "string" ) { - return ret.replace( rreturn, "" ); - } - - // Handle cases where value is null/undef or number - return ret == null ? "" : ret; - } - - return; - } - - isFunction = jQuery.isFunction( value ); - - return this.each( function( i ) { - var val; - - if ( this.nodeType !== 1 ) { - return; - } - - if ( isFunction ) { - val = value.call( this, i, jQuery( this ).val() ); - } else { - val = value; - } - - // Treat null/undefined as ""; convert numbers to string - if ( val == null ) { - val = ""; - - } else if ( typeof val === "number" ) { - val += ""; - - } else if ( Array.isArray( val ) ) { - val = jQuery.map( val, function( value ) { - return value == null ? "" : value + ""; - } ); - } - - hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; - - // If set returns undefined, fall back to normal setting - if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { - this.value = val; - } - } ); - } -} ); - -jQuery.extend( { - valHooks: { - option: { - get: function( elem ) { - - var val = jQuery.find.attr( elem, "value" ); - return val != null ? - val : - - // Support: IE <=10 - 11 only - // option.text throws exceptions (#14686, #14858) - // Strip and collapse whitespace - // https://html.spec.whatwg.org/#strip-and-collapse-whitespace - stripAndCollapse( jQuery.text( elem ) ); - } - }, - select: { - get: function( elem ) { - var value, option, i, - options = elem.options, - index = elem.selectedIndex, - one = elem.type === "select-one", - values = one ? null : [], - max = one ? index + 1 : options.length; - - if ( index < 0 ) { - i = max; - - } else { - i = one ? index : 0; - } - - // Loop through all the selected options - for ( ; i < max; i++ ) { - option = options[ i ]; - - // Support: IE <=9 only - // IE8-9 doesn't update selected after form reset (#2551) - if ( ( option.selected || i === index ) && - - // Don't return options that are disabled or in a disabled optgroup - !option.disabled && - ( !option.parentNode.disabled || - !nodeName( option.parentNode, "optgroup" ) ) ) { - - // Get the specific value for the option - value = jQuery( option ).val(); - - // We don't need an array for one selects - if ( one ) { - return value; - } - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - }, - - set: function( elem, value ) { - var optionSet, option, - options = elem.options, - values = jQuery.makeArray( value ), - i = options.length; - - while ( i-- ) { - option = options[ i ]; - - /* eslint-disable no-cond-assign */ - - if ( option.selected = - jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 - ) { - optionSet = true; - } - - /* eslint-enable no-cond-assign */ - } - - // Force browsers to behave consistently when non-matching value is set - if ( !optionSet ) { - elem.selectedIndex = -1; - } - return values; - } - } - } -} ); - -// Radios and checkboxes getter/setter -jQuery.each( [ "radio", "checkbox" ], function() { - jQuery.valHooks[ this ] = { - set: function( elem, value ) { - if ( Array.isArray( value ) ) { - return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); - } - } - }; - if ( !support.checkOn ) { - jQuery.valHooks[ this ].get = function( elem ) { - return elem.getAttribute( "value" ) === null ? "on" : elem.value; - }; - } -} ); - - - - -// Return jQuery for attributes-only inclusion - - -var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/; - -jQuery.extend( jQuery.event, { - - trigger: function( event, data, elem, onlyHandlers ) { - - var i, cur, tmp, bubbleType, ontype, handle, special, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] && - dataPriv.get( cur, "handle" ); - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( ( !special._default || - special._default.apply( eventPath.pop(), data ) === false ) && - acceptData( elem ) ) { - - // Call a native DOM method on the target with the same name as the event. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - elem[ type ](); - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - // Piggyback on a donor event to simulate a different one - // Used only for `focus(in | out)` events - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - } - ); - - jQuery.event.trigger( e, null, elem ); - } - -} ); - -jQuery.fn.extend( { - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " + - "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + - "change select submit keydown keypress keyup contextmenu" ).split( " " ), - function( i, name ) { - - // Handle event binding - jQuery.fn[ name ] = function( data, fn ) { - return arguments.length > 0 ? - this.on( name, null, data, fn ) : - this.trigger( name ); - }; -} ); - -jQuery.fn.extend( { - hover: function( fnOver, fnOut ) { - return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); - } -} ); - - - - -support.focusin = "onfocusin" in window; - - -// Support: Firefox <=44 -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = dataPriv.access( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - dataPriv.remove( doc, fix ); - - } else { - dataPriv.access( doc, fix, attaches ); - } - } - }; - } ); -} -var location = window.location; - -var nonce = jQuery.now(); - -var rquery = ( /\?/ ); - - - -// Cross-browser xml parsing -jQuery.parseXML = function( data ) { - var xml; - if ( !data || typeof data !== "string" ) { - return null; - } - - // Support: IE 9 - 11 only - // IE throws on parseFromString with invalid input. - try { - xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); - } catch ( e ) { - xml = undefined; - } - - if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { - jQuery.error( "Invalid XML: " + data ); - } - return xml; -}; - - -var - rbracket = /\[\]$/, - rCRLF = /\r?\n/g, - rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, - rsubmittable = /^(?:input|select|textarea|keygen)/i; - -function buildParams( prefix, obj, traditional, add ) { - var name; - - if ( Array.isArray( obj ) ) { - - // Serialize array item. - jQuery.each( obj, function( i, v ) { - if ( traditional || rbracket.test( prefix ) ) { - - // Treat each array item as a scalar. - add( prefix, v ); - - } else { - - // Item is non-scalar (array or object), encode its numeric index. - buildParams( - prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", - v, - traditional, - add - ); - } - } ); - - } else if ( !traditional && jQuery.type( obj ) === "object" ) { - - // Serialize object item. - for ( name in obj ) { - buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); - } - - } else { - - // Serialize scalar item. - add( prefix, obj ); - } -} - -// Serialize an array of form elements or a set of -// key/values into a query string -jQuery.param = function( a, traditional ) { - var prefix, - s = [], - add = function( key, valueOrFunction ) { - - // If value is a function, invoke it and use its return value - var value = jQuery.isFunction( valueOrFunction ) ? - valueOrFunction() : - valueOrFunction; - - s[ s.length ] = encodeURIComponent( key ) + "=" + - encodeURIComponent( value == null ? "" : value ); - }; - - // If an array was passed in, assume that it is an array of form elements. - if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { - - // Serialize the form elements - jQuery.each( a, function() { - add( this.name, this.value ); - } ); - - } else { - - // If traditional, encode the "old" way (the way 1.3.2 or older - // did it), otherwise encode params recursively. - for ( prefix in a ) { - buildParams( prefix, a[ prefix ], traditional, add ); - } - } - - // Return the resulting serialization - return s.join( "&" ); -}; - -jQuery.fn.extend( { - serialize: function() { - return jQuery.param( this.serializeArray() ); - }, - serializeArray: function() { - return this.map( function() { - - // Can add propHook for "elements" to filter or add form elements - var elements = jQuery.prop( this, "elements" ); - return elements ? jQuery.makeArray( elements ) : this; - } ) - .filter( function() { - var type = this.type; - - // Use .is( ":disabled" ) so that fieldset[disabled] works - return this.name && !jQuery( this ).is( ":disabled" ) && - rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && - ( this.checked || !rcheckableType.test( type ) ); - } ) - .map( function( i, elem ) { - var val = jQuery( this ).val(); - - if ( val == null ) { - return null; - } - - if ( Array.isArray( val ) ) { - return jQuery.map( val, function( val ) { - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ); - } - - return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; - } ).get(); - } -} ); - - -var - r20 = /%20/g, - rhash = /#.*$/, - rantiCache = /([?&])_=[^&]*/, - rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, - - // #7653, #8125, #8152: local protocol detection - rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, - rnoContent = /^(?:GET|HEAD)$/, - rprotocol = /^\/\//, - - /* Prefilters - * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) - * 2) These are called: - * - BEFORE asking for a transport - * - AFTER param serialization (s.data is a string if s.processData is true) - * 3) key is the dataType - * 4) the catchall symbol "*" can be used - * 5) execution will start with transport dataType and THEN continue down to "*" if needed - */ - prefilters = {}, - - /* Transports bindings - * 1) key is the dataType - * 2) the catchall symbol "*" can be used - * 3) selection will start with transport dataType and THEN go to "*" if needed - */ - transports = {}, - - // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression - allTypes = "*/".concat( "*" ), - - // Anchor tag for parsing the document origin - originAnchor = document.createElement( "a" ); - originAnchor.href = location.href; - -// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport -function addToPrefiltersOrTransports( structure ) { - - // dataTypeExpression is optional and defaults to "*" - return function( dataTypeExpression, func ) { - - if ( typeof dataTypeExpression !== "string" ) { - func = dataTypeExpression; - dataTypeExpression = "*"; - } - - var dataType, - i = 0, - dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; - - if ( jQuery.isFunction( func ) ) { - - // For each dataType in the dataTypeExpression - while ( ( dataType = dataTypes[ i++ ] ) ) { - - // Prepend if requested - if ( dataType[ 0 ] === "+" ) { - dataType = dataType.slice( 1 ) || "*"; - ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); - - // Otherwise append - } else { - ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); - } - } - } - }; -} - -// Base inspection function for prefilters and transports -function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { - - var inspected = {}, - seekingTransport = ( structure === transports ); - - function inspect( dataType ) { - var selected; - inspected[ dataType ] = true; - jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { - var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); - if ( typeof dataTypeOrTransport === "string" && - !seekingTransport && !inspected[ dataTypeOrTransport ] ) { - - options.dataTypes.unshift( dataTypeOrTransport ); - inspect( dataTypeOrTransport ); - return false; - } else if ( seekingTransport ) { - return !( selected = dataTypeOrTransport ); - } - } ); - return selected; - } - - return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); -} - -// A special extend for ajax options -// that takes "flat" options (not to be deep extended) -// Fixes #9887 -function ajaxExtend( target, src ) { - var key, deep, - flatOptions = jQuery.ajaxSettings.flatOptions || {}; - - for ( key in src ) { - if ( src[ key ] !== undefined ) { - ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; - } - } - if ( deep ) { - jQuery.extend( true, target, deep ); - } - - return target; -} - -/* Handles responses to an ajax request: - * - finds the right dataType (mediates between content-type and expected dataType) - * - returns the corresponding response - */ -function ajaxHandleResponses( s, jqXHR, responses ) { - - var ct, type, finalDataType, firstDataType, - contents = s.contents, - dataTypes = s.dataTypes; - - // Remove auto dataType and get content-type in the process - while ( dataTypes[ 0 ] === "*" ) { - dataTypes.shift(); - if ( ct === undefined ) { - ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); - } - } - - // Check if we're dealing with a known content-type - if ( ct ) { - for ( type in contents ) { - if ( contents[ type ] && contents[ type ].test( ct ) ) { - dataTypes.unshift( type ); - break; - } - } - } - - // Check to see if we have a response for the expected dataType - if ( dataTypes[ 0 ] in responses ) { - finalDataType = dataTypes[ 0 ]; - } else { - - // Try convertible dataTypes - for ( type in responses ) { - if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { - finalDataType = type; - break; - } - if ( !firstDataType ) { - firstDataType = type; - } - } - - // Or just use first one - finalDataType = finalDataType || firstDataType; - } - - // If we found a dataType - // We add the dataType to the list if needed - // and return the corresponding response - if ( finalDataType ) { - if ( finalDataType !== dataTypes[ 0 ] ) { - dataTypes.unshift( finalDataType ); - } - return responses[ finalDataType ]; - } -} - -/* Chain conversions given the request and the original response - * Also sets the responseXXX fields on the jqXHR instance - */ -function ajaxConvert( s, response, jqXHR, isSuccess ) { - var conv2, current, conv, tmp, prev, - converters = {}, - - // Work with a copy of dataTypes in case we need to modify it for conversion - dataTypes = s.dataTypes.slice(); - - // Create converters map with lowercased keys - if ( dataTypes[ 1 ] ) { - for ( conv in s.converters ) { - converters[ conv.toLowerCase() ] = s.converters[ conv ]; - } - } - - current = dataTypes.shift(); - - // Convert to each sequential dataType - while ( current ) { - - if ( s.responseFields[ current ] ) { - jqXHR[ s.responseFields[ current ] ] = response; - } - - // Apply the dataFilter if provided - if ( !prev && isSuccess && s.dataFilter ) { - response = s.dataFilter( response, s.dataType ); - } - - prev = current; - current = dataTypes.shift(); - - if ( current ) { - - // There's only work to do if current dataType is non-auto - if ( current === "*" ) { - - current = prev; - - // Convert response if prev dataType is non-auto and differs from current - } else if ( prev !== "*" && prev !== current ) { - - // Seek a direct converter - conv = converters[ prev + " " + current ] || converters[ "* " + current ]; - - // If none found, seek a pair - if ( !conv ) { - for ( conv2 in converters ) { - - // If conv2 outputs current - tmp = conv2.split( " " ); - if ( tmp[ 1 ] === current ) { - - // If prev can be converted to accepted input - conv = converters[ prev + " " + tmp[ 0 ] ] || - converters[ "* " + tmp[ 0 ] ]; - if ( conv ) { - - // Condense equivalence converters - if ( conv === true ) { - conv = converters[ conv2 ]; - - // Otherwise, insert the intermediate dataType - } else if ( converters[ conv2 ] !== true ) { - current = tmp[ 0 ]; - dataTypes.unshift( tmp[ 1 ] ); - } - break; - } - } - } - } - - // Apply converter (if not an equivalence) - if ( conv !== true ) { - - // Unless errors are allowed to bubble, catch and return them - if ( conv && s.throws ) { - response = conv( response ); - } else { - try { - response = conv( response ); - } catch ( e ) { - return { - state: "parsererror", - error: conv ? e : "No conversion from " + prev + " to " + current - }; - } - } - } - } - } - } - - return { state: "success", data: response }; -} - -jQuery.extend( { - - // Counter for holding the number of active queries - active: 0, - - // Last-Modified header cache for next request - lastModified: {}, - etag: {}, - - ajaxSettings: { - url: location.href, - type: "GET", - isLocal: rlocalProtocol.test( location.protocol ), - global: true, - processData: true, - async: true, - contentType: "application/x-www-form-urlencoded; charset=UTF-8", - - /* - timeout: 0, - data: null, - dataType: null, - username: null, - password: null, - cache: null, - throws: false, - traditional: false, - headers: {}, - */ - - accepts: { - "*": allTypes, - text: "text/plain", - html: "text/html", - xml: "application/xml, text/xml", - json: "application/json, text/javascript" - }, - - contents: { - xml: /\bxml\b/, - html: /\bhtml/, - json: /\bjson\b/ - }, - - responseFields: { - xml: "responseXML", - text: "responseText", - json: "responseJSON" - }, - - // Data converters - // Keys separate source (or catchall "*") and destination types with a single space - converters: { - - // Convert anything to text - "* text": String, - - // Text to html (true = no transformation) - "text html": true, - - // Evaluate text as a json expression - "text json": JSON.parse, - - // Parse text as xml - "text xml": jQuery.parseXML - }, - - // For options that shouldn't be deep extended: - // you can add your own custom options here if - // and when you create one that shouldn't be - // deep extended (see ajaxExtend) - flatOptions: { - url: true, - context: true - } - }, - - // Creates a full fledged settings object into target - // with both ajaxSettings and settings fields. - // If target is omitted, writes into ajaxSettings. - ajaxSetup: function( target, settings ) { - return settings ? - - // Building a settings object - ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : - - // Extending ajaxSettings - ajaxExtend( jQuery.ajaxSettings, target ); - }, - - ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), - ajaxTransport: addToPrefiltersOrTransports( transports ), - - // Main method - ajax: function( url, options ) { - - // If url is an object, simulate pre-1.5 signature - if ( typeof url === "object" ) { - options = url; - url = undefined; - } - - // Force options to be an object - options = options || {}; - - var transport, - - // URL without anti-cache param - cacheURL, - - // Response headers - responseHeadersString, - responseHeaders, - - // timeout handle - timeoutTimer, - - // Url cleanup var - urlAnchor, - - // Request state (becomes false upon send and true upon completion) - completed, - - // To know if global events are to be dispatched - fireGlobals, - - // Loop variable - i, - - // uncached part of the url - uncached, - - // Create the final options object - s = jQuery.ajaxSetup( {}, options ), - - // Callbacks context - callbackContext = s.context || s, - - // Context for global events is callbackContext if it is a DOM node or jQuery collection - globalEventContext = s.context && - ( callbackContext.nodeType || callbackContext.jquery ) ? - jQuery( callbackContext ) : - jQuery.event, - - // Deferreds - deferred = jQuery.Deferred(), - completeDeferred = jQuery.Callbacks( "once memory" ), - - // Status-dependent callbacks - statusCode = s.statusCode || {}, - - // Headers (they are sent all at once) - requestHeaders = {}, - requestHeadersNames = {}, - - // Default abort message - strAbort = "canceled", - - // Fake xhr - jqXHR = { - readyState: 0, - - // Builds headers hashtable if needed - getResponseHeader: function( key ) { - var match; - if ( completed ) { - if ( !responseHeaders ) { - responseHeaders = {}; - while ( ( match = rheaders.exec( responseHeadersString ) ) ) { - responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ]; - } - } - match = responseHeaders[ key.toLowerCase() ]; - } - return match == null ? null : match; - }, - - // Raw string - getAllResponseHeaders: function() { - return completed ? responseHeadersString : null; - }, - - // Caches the header - setRequestHeader: function( name, value ) { - if ( completed == null ) { - name = requestHeadersNames[ name.toLowerCase() ] = - requestHeadersNames[ name.toLowerCase() ] || name; - requestHeaders[ name ] = value; - } - return this; - }, - - // Overrides response content-type header - overrideMimeType: function( type ) { - if ( completed == null ) { - s.mimeType = type; - } - return this; - }, - - // Status-dependent callbacks - statusCode: function( map ) { - var code; - if ( map ) { - if ( completed ) { - - // Execute the appropriate callbacks - jqXHR.always( map[ jqXHR.status ] ); - } else { - - // Lazy-add the new callbacks in a way that preserves old ones - for ( code in map ) { - statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; - } - } - } - return this; - }, - - // Cancel the request - abort: function( statusText ) { - var finalText = statusText || strAbort; - if ( transport ) { - transport.abort( finalText ); - } - done( 0, finalText ); - return this; - } - }; - - // Attach deferreds - deferred.promise( jqXHR ); - - // Add protocol if not provided (prefilters might expect it) - // Handle falsy url in the settings object (#10093: consistency with old signature) - // We also use the url parameter if available - s.url = ( ( url || s.url || location.href ) + "" ) - .replace( rprotocol, location.protocol + "//" ); - - // Alias method option to type as per ticket #12004 - s.type = options.method || options.type || s.method || s.type; - - // Extract dataTypes list - s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; - - // A cross-domain request is in order when the origin doesn't match the current origin. - if ( s.crossDomain == null ) { - urlAnchor = document.createElement( "a" ); - - // Support: IE <=8 - 11, Edge 12 - 13 - // IE throws exception on accessing the href property if url is malformed, - // e.g. http://example.com:80x/ - try { - urlAnchor.href = s.url; - - // Support: IE <=8 - 11 only - // Anchor's host property isn't correctly set when s.url is relative - urlAnchor.href = urlAnchor.href; - s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== - urlAnchor.protocol + "//" + urlAnchor.host; - } catch ( e ) { - - // If there is an error parsing the URL, assume it is crossDomain, - // it can be rejected by the transport if it is invalid - s.crossDomain = true; - } - } - - // Convert data if not already a string - if ( s.data && s.processData && typeof s.data !== "string" ) { - s.data = jQuery.param( s.data, s.traditional ); - } - - // Apply prefilters - inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); - - // If request was aborted inside a prefilter, stop there - if ( completed ) { - return jqXHR; - } - - // We can fire global events as of now if asked to - // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) - fireGlobals = jQuery.event && s.global; - - // Watch for a new set of requests - if ( fireGlobals && jQuery.active++ === 0 ) { - jQuery.event.trigger( "ajaxStart" ); - } - - // Uppercase the type - s.type = s.type.toUpperCase(); - - // Determine if request has content - s.hasContent = !rnoContent.test( s.type ); - - // Save the URL in case we're toying with the If-Modified-Since - // and/or If-None-Match header later on - // Remove hash to simplify url manipulation - cacheURL = s.url.replace( rhash, "" ); - - // More options handling for requests with no content - if ( !s.hasContent ) { - - // Remember the hash so we can put it back - uncached = s.url.slice( cacheURL.length ); - - // If data is available, append data to url - if ( s.data ) { - cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; - - // #9682: remove data so that it's not used in an eventual retry - delete s.data; - } - - // Add or update anti-cache param if needed - if ( s.cache === false ) { - cacheURL = cacheURL.replace( rantiCache, "$1" ); - uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached; - } - - // Put hash and anti-cache on the URL that will be requested (gh-1732) - s.url = cacheURL + uncached; - - // Change '%20' to '+' if this is encoded form body content (gh-2658) - } else if ( s.data && s.processData && - ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { - s.data = s.data.replace( r20, "+" ); - } - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - if ( jQuery.lastModified[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); - } - if ( jQuery.etag[ cacheURL ] ) { - jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); - } - } - - // Set the correct header, if data is being sent - if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { - jqXHR.setRequestHeader( "Content-Type", s.contentType ); - } - - // Set the Accepts header for the server, depending on the dataType - jqXHR.setRequestHeader( - "Accept", - s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? - s.accepts[ s.dataTypes[ 0 ] ] + - ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : - s.accepts[ "*" ] - ); - - // Check for headers option - for ( i in s.headers ) { - jqXHR.setRequestHeader( i, s.headers[ i ] ); - } - - // Allow custom headers/mimetypes and early abort - if ( s.beforeSend && - ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { - - // Abort if not done already and return - return jqXHR.abort(); - } - - // Aborting is no longer a cancellation - strAbort = "abort"; - - // Install callbacks on deferreds - completeDeferred.add( s.complete ); - jqXHR.done( s.success ); - jqXHR.fail( s.error ); - - // Get transport - transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); - - // If no transport, we auto-abort - if ( !transport ) { - done( -1, "No Transport" ); - } else { - jqXHR.readyState = 1; - - // Send global event - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); - } - - // If request was aborted inside ajaxSend, stop there - if ( completed ) { - return jqXHR; - } - - // Timeout - if ( s.async && s.timeout > 0 ) { - timeoutTimer = window.setTimeout( function() { - jqXHR.abort( "timeout" ); - }, s.timeout ); - } - - try { - completed = false; - transport.send( requestHeaders, done ); - } catch ( e ) { - - // Rethrow post-completion exceptions - if ( completed ) { - throw e; - } - - // Propagate others as results - done( -1, e ); - } - } - - // Callback for when everything is done - function done( status, nativeStatusText, responses, headers ) { - var isSuccess, success, error, response, modified, - statusText = nativeStatusText; - - // Ignore repeat invocations - if ( completed ) { - return; - } - - completed = true; - - // Clear timeout if it exists - if ( timeoutTimer ) { - window.clearTimeout( timeoutTimer ); - } - - // Dereference transport for early garbage collection - // (no matter how long the jqXHR object will be used) - transport = undefined; - - // Cache response headers - responseHeadersString = headers || ""; - - // Set readyState - jqXHR.readyState = status > 0 ? 4 : 0; - - // Determine if successful - isSuccess = status >= 200 && status < 300 || status === 304; - - // Get response data - if ( responses ) { - response = ajaxHandleResponses( s, jqXHR, responses ); - } - - // Convert no matter what (that way responseXXX fields are always set) - response = ajaxConvert( s, response, jqXHR, isSuccess ); - - // If successful, handle type chaining - if ( isSuccess ) { - - // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. - if ( s.ifModified ) { - modified = jqXHR.getResponseHeader( "Last-Modified" ); - if ( modified ) { - jQuery.lastModified[ cacheURL ] = modified; - } - modified = jqXHR.getResponseHeader( "etag" ); - if ( modified ) { - jQuery.etag[ cacheURL ] = modified; - } - } - - // if no content - if ( status === 204 || s.type === "HEAD" ) { - statusText = "nocontent"; - - // if not modified - } else if ( status === 304 ) { - statusText = "notmodified"; - - // If we have data, let's convert it - } else { - statusText = response.state; - success = response.data; - error = response.error; - isSuccess = !error; - } - } else { - - // Extract error from statusText and normalize for non-aborts - error = statusText; - if ( status || !statusText ) { - statusText = "error"; - if ( status < 0 ) { - status = 0; - } - } - } - - // Set data for the fake xhr object - jqXHR.status = status; - jqXHR.statusText = ( nativeStatusText || statusText ) + ""; - - // Success/Error - if ( isSuccess ) { - deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); - } else { - deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); - } - - // Status-dependent callbacks - jqXHR.statusCode( statusCode ); - statusCode = undefined; - - if ( fireGlobals ) { - globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", - [ jqXHR, s, isSuccess ? success : error ] ); - } - - // Complete - completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); - - if ( fireGlobals ) { - globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); - - // Handle the global AJAX counter - if ( !( --jQuery.active ) ) { - jQuery.event.trigger( "ajaxStop" ); - } - } - } - - return jqXHR; - }, - - getJSON: function( url, data, callback ) { - return jQuery.get( url, data, callback, "json" ); - }, - - getScript: function( url, callback ) { - return jQuery.get( url, undefined, callback, "script" ); - } -} ); - -jQuery.each( [ "get", "post" ], function( i, method ) { - jQuery[ method ] = function( url, data, callback, type ) { - - // Shift arguments if data argument was omitted - if ( jQuery.isFunction( data ) ) { - type = type || callback; - callback = data; - data = undefined; - } - - // The url can be an options object (which then must have .url) - return jQuery.ajax( jQuery.extend( { - url: url, - type: method, - dataType: type, - data: data, - success: callback - }, jQuery.isPlainObject( url ) && url ) ); - }; -} ); - - -jQuery._evalUrl = function( url ) { - return jQuery.ajax( { - url: url, - - // Make this explicit, since user can override this through ajaxSetup (#11264) - type: "GET", - dataType: "script", - cache: true, - async: false, - global: false, - "throws": true - } ); -}; - - -jQuery.fn.extend( { - wrapAll: function( html ) { - var wrap; - - if ( this[ 0 ] ) { - if ( jQuery.isFunction( html ) ) { - html = html.call( this[ 0 ] ); - } - - // The elements to wrap the target around - wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); - - if ( this[ 0 ].parentNode ) { - wrap.insertBefore( this[ 0 ] ); - } - - wrap.map( function() { - var elem = this; - - while ( elem.firstElementChild ) { - elem = elem.firstElementChild; - } - - return elem; - } ).append( this ); - } - - return this; - }, - - wrapInner: function( html ) { - if ( jQuery.isFunction( html ) ) { - return this.each( function( i ) { - jQuery( this ).wrapInner( html.call( this, i ) ); - } ); - } - - return this.each( function() { - var self = jQuery( this ), - contents = self.contents(); - - if ( contents.length ) { - contents.wrapAll( html ); - - } else { - self.append( html ); - } - } ); - }, - - wrap: function( html ) { - var isFunction = jQuery.isFunction( html ); - - return this.each( function( i ) { - jQuery( this ).wrapAll( isFunction ? html.call( this, i ) : html ); - } ); - }, - - unwrap: function( selector ) { - this.parent( selector ).not( "body" ).each( function() { - jQuery( this ).replaceWith( this.childNodes ); - } ); - return this; - } -} ); - - -jQuery.expr.pseudos.hidden = function( elem ) { - return !jQuery.expr.pseudos.visible( elem ); -}; -jQuery.expr.pseudos.visible = function( elem ) { - return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); -}; - - - - -jQuery.ajaxSettings.xhr = function() { - try { - return new window.XMLHttpRequest(); - } catch ( e ) {} -}; - -var xhrSuccessStatus = { - - // File protocol always yields status code 0, assume 200 - 0: 200, - - // Support: IE <=9 only - // #1450: sometimes IE returns 1223 when it should be 204 - 1223: 204 - }, - xhrSupported = jQuery.ajaxSettings.xhr(); - -support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); -support.ajax = xhrSupported = !!xhrSupported; - -jQuery.ajaxTransport( function( options ) { - var callback, errorCallback; - - // Cross domain only allowed if supported through XMLHttpRequest - if ( support.cors || xhrSupported && !options.crossDomain ) { - return { - send: function( headers, complete ) { - var i, - xhr = options.xhr(); - - xhr.open( - options.type, - options.url, - options.async, - options.username, - options.password - ); - - // Apply custom fields if provided - if ( options.xhrFields ) { - for ( i in options.xhrFields ) { - xhr[ i ] = options.xhrFields[ i ]; - } - } - - // Override mime type if needed - if ( options.mimeType && xhr.overrideMimeType ) { - xhr.overrideMimeType( options.mimeType ); - } - - // X-Requested-With header - // For cross-domain requests, seeing as conditions for a preflight are - // akin to a jigsaw puzzle, we simply never set it to be sure. - // (it can always be set on a per-request basis or even using ajaxSetup) - // For same-domain requests, won't change header if already provided. - if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { - headers[ "X-Requested-With" ] = "XMLHttpRequest"; - } - - // Set headers - for ( i in headers ) { - xhr.setRequestHeader( i, headers[ i ] ); - } - - // Callback - callback = function( type ) { - return function() { - if ( callback ) { - callback = errorCallback = xhr.onload = - xhr.onerror = xhr.onabort = xhr.onreadystatechange = null; - - if ( type === "abort" ) { - xhr.abort(); - } else if ( type === "error" ) { - - // Support: IE <=9 only - // On a manual native abort, IE9 throws - // errors on any property access that is not readyState - if ( typeof xhr.status !== "number" ) { - complete( 0, "error" ); - } else { - complete( - - // File: protocol always yields status 0; see #8605, #14207 - xhr.status, - xhr.statusText - ); - } - } else { - complete( - xhrSuccessStatus[ xhr.status ] || xhr.status, - xhr.statusText, - - // Support: IE <=9 only - // IE9 has no XHR2 but throws on binary (trac-11426) - // For XHR2 non-text, let the caller handle it (gh-2498) - ( xhr.responseType || "text" ) !== "text" || - typeof xhr.responseText !== "string" ? - { binary: xhr.response } : - { text: xhr.responseText }, - xhr.getAllResponseHeaders() - ); - } - } - }; - }; - - // Listen to events - xhr.onload = callback(); - errorCallback = xhr.onerror = callback( "error" ); - - // Support: IE 9 only - // Use onreadystatechange to replace onabort - // to handle uncaught aborts - if ( xhr.onabort !== undefined ) { - xhr.onabort = errorCallback; - } else { - xhr.onreadystatechange = function() { - - // Check readyState before timeout as it changes - if ( xhr.readyState === 4 ) { - - // Allow onerror to be called first, - // but that will not handle a native abort - // Also, save errorCallback to a variable - // as xhr.onerror cannot be accessed - window.setTimeout( function() { - if ( callback ) { - errorCallback(); - } - } ); - } - }; - } - - // Create the abort callback - callback = callback( "abort" ); - - try { - - // Do send the request (this may raise an exception) - xhr.send( options.hasContent && options.data || null ); - } catch ( e ) { - - // #14683: Only rethrow if this hasn't been notified as an error yet - if ( callback ) { - throw e; - } - } - }, - - abort: function() { - if ( callback ) { - callback(); - } - } - }; - } -} ); - - - - -// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) -jQuery.ajaxPrefilter( function( s ) { - if ( s.crossDomain ) { - s.contents.script = false; - } -} ); - -// Install script dataType -jQuery.ajaxSetup( { - accepts: { - script: "text/javascript, application/javascript, " + - "application/ecmascript, application/x-ecmascript" - }, - contents: { - script: /\b(?:java|ecma)script\b/ - }, - converters: { - "text script": function( text ) { - jQuery.globalEval( text ); - return text; - } - } -} ); - -// Handle cache's special case and crossDomain -jQuery.ajaxPrefilter( "script", function( s ) { - if ( s.cache === undefined ) { - s.cache = false; - } - if ( s.crossDomain ) { - s.type = "GET"; - } -} ); - -// Bind script tag hack transport -jQuery.ajaxTransport( "script", function( s ) { - - // This transport only deals with cross domain requests - if ( s.crossDomain ) { - var script, callback; - return { - send: function( _, complete ) { - script = jQuery( " - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

API Reference

-
-

Data Containers

-
-

Batch

-
-
-
-class gunpowder.Batch[source]
-

Contains the requested batch as a collection of Arrays -and Graph that is passed through the pipeline from sources to -sinks.

-

This collection mimics a dictionary. Items can be added with:

-
batch = Batch()
-batch[array_key] = Array(...)
-batch[graph_key] = Graph(...)
-
-
-

Here, array_key and graph_key are ArrayKey and -GraphKey. The items can be queried with:

-
array = batch[array_key]
-graph = batch[graph_key]
-
-
-

Furthermore, pairs of keys/values can be iterated over using -batch.items().

-

To access only arrays or graphs, use the dictionaries batch.arrays -or batch.graphs, respectively.

-
-
-arrays
-

Contains all arrays that have been requested for this batch.

-
-
Type
-

dict from ArrayKey to Array

-
-
-
- -
-
-graphs
-

Contains all graphs that have been requested for this batch.

-
-
Type
-

dict from GraphKey to Graph

-
-
-
- -
-
-crop(request, copy=False)[source]
-

Crop batch to meet the given request.

-
- -
-
-get_total_roi()[source]
-

Get the union of all the array ROIs in the batch.

-
- -
-
-items()[source]
-

Provides a generator iterating over key/value pairs.

-
- -
-
-merge(batch, merge_profiling_stats=True)[source]
-

Merge this batch (a) with another batch (b).

-

This creates a new batch c containing arrays and graphs from -both batches a and b:

-
-
    -
  • Arrays or Graphs that exist in either a or b will be -referenced in c (not copied).

  • -
  • Arrays or Graphs that exist in both batches will keep only -a reference to the version in b in c.

  • -
-
-

All other cases will lead to an exception.

-
- -
- -
-
-
-

Array

-
-
-
-class gunpowder.Array(data, spec=None, attrs=None)[source]
-

A numpy array with a specification describing the data.

-
-
Parameters
-
    -
  • data (array-like) – The data to be stored in the array. Will be converted to a numpy -array, if necessary.

  • -
  • spec (ArraySpec, optional) – A spec describing the data.

  • -
  • attrs (dict, optional) – Optional attributes to describe this array.

  • -
-
-
-
-
-copy()[source]
-

Create a copy of this array.

-
- -
-
-crop(roi, copy=True)[source]
-

Create a cropped copy of this Array.

-
-
Parameters
-
    -
  • roi (Roi) – ROI in world units to crop to.

  • -
  • copy (bool) – Make a copy of the data.

  • -
-
-
-
- -
-
-merge(array, copy_from_self=False, copy=False)[source]
-

Merge this array with another one. The resulting array will have the -size of the larger one, with values replaced from array.

-

This only works if one of the two arrays is contained in the other. In -this case, array will overwrite values in self (unless -copy_from_self is set to True).

-

A copy will only be made if necessary or copy is set to True.

-
- -
- -
-
-
-

Graph

-
-
-
-class gunpowder.Graph(nodes: Iterator[gunpowder.graph.Node], edges: Iterator[gunpowder.graph.Edge], spec: gunpowder.graph_spec.GraphSpec)[source]
-

A structure containing a list of Node, a list of Edge, -and a specification describing the data.

-
-
Parameters
-
    -
  • nodes (iterator, Node) – An iterator containing Vertices.

  • -
  • edges (iterator, Edge) – An iterator containing Edges.

  • -
  • spec (GraphSpec) – A spec describing the data.

  • -
-
-
-
-
-add_edge(edge: gunpowder.graph.Edge)[source]
-

Adds an edge to the graph. -If an edge exists with the same u and v, its attributes -will be overwritten.

-
- -
-
-add_node(node: gunpowder.graph.Node)[source]
-

Adds a node to the graph. -If a node exists with the same id as the node you are adding, -its attributes will be overwritten.

-
- -
-
-crop(roi: gunpowder.roi.Roi)[source]
-

Will remove all nodes from self that are not contained in roi except for -“dangling” nodes. This means that if there are nodes A, B s.t. there -is an edge (A, B) and A is contained in roi but B is not, the edge (A, B) -is considered contained in the roi and thus node B will be kept as a -“dangling” node.

-

Note there is a helper function trim that will remove B and replace it with -a node at the intersection of the edge (A, B) and the bounding box of roi.

-
-
Parameters
-

roi (Roi) – ROI in world units to crop to.

-
-
-
- -
-
-classmethod from_nx_graph(graph, spec)[source]
-

Create a gunpowder graph from a networkx graph

-
- -
-
-merge(other, copy_from_self=False, copy=False)[source]
-

Merge this graph with another. The resulting graph will have the Roi -of the larger one.

-

This only works if one of the two graphs contains the other. -In this case, other will overwrite edges and nodes with the same -ID in self (unless copy_from_self is set to True). -Vertices and edges in self that are contained in the Roi of other -will be removed (vice versa for copy_from_self)

-

A copy will only be made if necessary or copy is set to True.

-
- -
-
-node(id: int)[source]
-

Get node with a specific id

-
- -
-
-relabel_connected_components()[source]
-

create a new attribute “component” for each node -in this Graph

-
- -
-
-remove_edge(edge: gunpowder.graph.Edge)[source]
-

Remove an edge from the graph.

-
- -
-
-remove_node(node: gunpowder.graph.Node, retain_connectivity=False)[source]
-

Remove a node.

-

retain_connectivity: preserve removed nodes neighboring edges. -Given graph: a->b->c, removing b without retain_connectivity -would leave us with two connected components, {‘a’} and {‘b’}. -removing ‘b’ with retain_connectivity flag set to True would -leave us with the graph: a->c, and only one connected component -{a, c}, thus preserving the connectivity of ‘a’ and ‘c’

-
- -
-
-to_nx_graph()[source]
-

returns a pure networkx graph containing data from -this Graph.

-
- -
-
-trim(roi: gunpowder.roi.Roi)[source]
-

Create a copy of self and replace “dangling” nodes with contained nodes.

-

A “dangling” node is defined by: Let A, B be nodes s.t. there exists an -edge (A, B) and A is contained in roi but B is not. Edge (A, B) is considered -contained, and thus B is kept as a “dangling” node.

-
- -
- -
-
-
-

Node

-
-
-
-class gunpowder.Node(id: int, location: numpy.ndarray, temporary: bool = False, attrs: Optional[Dict[str, Any]] = None)[source]
-

A stucture representing each node in a Graph.

-
-
Parameters
-
    -
  • id (int) – A unique identifier for this Node

  • -
  • location (np.ndarray) – A numpy array containing a nodes location

  • -
  • attrs (Optional) – A dictionary containing a mapping from attribute to value. -Used to store any extra attributes associated with the -Node such as color, size, etc.

  • -
  • temporary (Optional) – A tag to mark a node as temporary. Some operations such -as trim might make new nodes that are just biproducts -of viewing the data with a limited scope. These nodes -are only guaranteed to have an id different from those -in the same Graph, but may have conflicts if you request -multiple graphs from the same source with different rois.

  • -
-
-
-
- -
-
-
-

Edge

-
-
-
-class gunpowder.Edge(u: int, v: int, attrs: Optional[Dict[str, Any]] = None)[source]
-

A structure representing edges in a graph.

-
-
Parameters
-
    -
  • u (int) – The id of the ‘u’ node of this edge

  • -
  • v (int) – the id of the v node of this edge

  • -
-
-
-
- -
-
-
-

ArrayKey

-
-
-
-class gunpowder.ArrayKey(identifier)[source]
-

A key to identify arrays in requests, batches, and across nodes.

-

Used as key in BatchRequest and Batch to retrieve array -specs or arrays.

-
-
Parameters
-

identifier (string) – A unique, human readable identifier for this array key. Will be -used in log messages and to look up arrays in requests and batches. -Should be upper case (like RAW, GT_LABELS). The identifier -is unique: Two array keys with the same identifier will refer to -the same array.

-
-
-
- -
-
-
-

GraphKey

-
-
-
-class gunpowder.GraphKey(identifier)[source]
-

A key to identify graphs in requests, batches, and across -nodes.

-

Used as key in BatchRequest and Batch to retrieve specs -or graphs.

-
-
Parameters
-

identifier (string) – A unique, human readable identifier for this graph key. Will be -used in log messages and to look up graphs in requests and batches. -Should be upper case (like CENTER_GRAPH). The identifier is -unique: Two graph keys with the same identifier will refer to the -same graph.

-
-
-
- -
-
-
-
-

Requests and Specifications

-
-

ProviderSpec

-
-
-
-class gunpowder.ProviderSpec(array_specs=None, graph_specs=None, points_specs=None)[source]
-

A collection of (possibly partial) ArraySpecs and -GraphSpecs describing a -BatchProvider's offered arrays and graphs.

-

This collection mimics a dictionary. Specs can be added with:

-
provider_spec = ProviderSpec()
-provider_spec[array_key] = ArraySpec(...)
-provider_spec[graph_key] = GraphSpec(...)
-
-
-

Here, array_key and graph_key are ArrayKey and -GraphKey. The specs can be queried with:

-
array_spec = provider_spec[array_key]
-graph_spec = provider_spec[graph_key]
-
-
-

Furthermore, pairs of keys/values can be iterated over using -provider_spec.items().

-

To access only array or graph specs, use the dictionaries -provider_spec.array_specs or provider_spec.graph_specs, -respectively.

-
-
Parameters
-
-
-
-
-
-array_specs
-

Contains all array specs contained in this provider spec.

-
-
Type
-

dict, ArrayKey -> ArraySpec

-
-
-
- -
-
-graph_specs
-

Contains all graph specs contained in this provider spec.

-
-
Type
-

dict, GraphKey -> GraphSpec

-
-
-
- -
-
-items()[source]
-

Provides a generator iterating over key/value pairs.

-
- -
- -
-
-
-

BatchRequest

-
-
-
-class gunpowder.BatchRequest(*args, random_seed=None, **kwargs)[source]
-

A collection of (possibly partial) ArraySpec and -GraphSpec forming a request.

-

Inherits from ProviderSpec.

-

See sec_requests_batches for how to use a batch request to obtain a -batch.

-

Additional Kwargs:

-
-

random_seed (int):

-
-

The random seed that will be associated with this batch to -guarantee deterministic and repeatable batch requests.

-
-
-
-
-add(key, shape, voxel_size=None, directed=None, placeholder=False)[source]
-

Convenience method to add an array or graph spec by providing only -the shape of a ROI (in world units).

-

A ROI with zero-offset will be generated. If more than one request is -added, the ROIs with smaller shapes will be shifted to be centered in -the largest one.

-
-
Parameters
-
    -
  • key (ArrayKey or GraphKey) – The key for which to add a spec.

  • -
  • shape (Coordinate) – A tuple containing the shape of the desired roi

  • -
  • voxel_size (Coordinate) – A tuple contening the voxel sizes for each corresponding -dimension

  • -
-
-
-
- -
- -
-
-
-

ArraySpec

-
-
-
-class gunpowder.ArraySpec(roi=None, voxel_size=None, interpolatable=None, nonspatial=False, dtype=None, placeholder=False)[source]
-

Contains meta-information about an array. This is used by -BatchProviders to communicate the arrays they -offer, as well as by Arrays to describe the data they -contain.

-
-
-roi
-

The region of interested represented by this array spec. Can be -None for BatchProviders that allow -requests for arrays everywhere, but will always be set for array -specs that are part of a Array.

-
-
Type
-

Roi

-
-
-
- -
-
-voxel_size
-

The size of the spatial axises in world units.

-
-
Type
-

Coordinate

-
-
-
- -
-
-interpolatable
-

Whether the values of this array can be interpolated.

-
-
Type
-

bool

-
-
-
- -
-
-nonspatial
-

If set, this array does not represent spatial data (e.g., a list of -labels for samples in a batch). roi and voxel_size have to -be None. No consistency checks will be performed.

-
-
Type
-

bool, optional

-
-
-
- -
-
-dtype
-

The data type of the array.

-
-
Type
-

np.dtype

-
-
-
- -
-
-copy()[source]
-

Create a copy of this spec.

-
- -
- -
-
-
-

GraphSpec

-
-
-
-class gunpowder.GraphSpec(roi=None, directed=None, dtype=<class 'numpy.float32'>, placeholder=False)[source]
-

Contains meta-information about a graph. This is used by -BatchProviders to communicate the graphs they -offer, as well as by Graph to describe the data they contain.

-
-
-roi
-

The region of interested represented by this graph.

-
-
Type
-

Roi

-
-
-
- -
-
-directed
-

Whether the graph is directed or not.

-
-
Type
-

bool, optional

-
-
-
- -
-
-dtype
-

The data type of the “location” attribute. -Currently only supports np.float32.

-
-
Type
-

dtype, optional

-
-
-
- -
-
-copy()[source]
-

Create a copy of this spec.

-
- -
- -
-
-
-
-

Geometry

-
-

Coordinate

-
-
-
-class gunpowder.Coordinate(array_like)[source]
-

A tuple of integers.

-

Allows the following element-wise operators: addition, subtraction, -multiplication, division, absolute value, and negation. This allows to -perform simple arithmetics with coordinates, e.g.:

-
shape = Coordinate((2, 3, 4))
-voxel_size = Coordinate((10, 5, 1))
-size = shape*voxel_size # == Coordinate((20, 15, 4))
-
-
-
- -
-
-
-

Roi

-
-
-
-class gunpowder.Roi(offset=None, shape=None)[source]
-

A rectangular region of interest, defined by an offset and a shape.

-

Similar to Coordinate, supports simple arithmetics, e.g.:

-
roi = Roi((1, 1, 1), (10, 10, 10))
-voxel_size = Coordinate((10, 5, 1))
-scale_shift = roi*voxel_size + 1 # == Roi((11, 6, 2), (101, 51, 11))
-
-
-
-
Parameters
-
    -
  • offset (array-like of int, optional) – The starting point (inclusive) of the ROI. Can be None -(default) if the ROI only characterizes a shape.

  • -
  • shape (array-like) – The shape of the ROI. Entries can be None to indicate -unboundedness. If None is passed instead of a tuple, all -dimensions are set to None, if the number of dimensions can be -inferred from offset.

  • -
-
-
-
-
-contains(other)[source]
-

Test if this ROI contains other, which can be another -Roi or a Coordinate.

-
- -
-
-copy()[source]
-

Create a copy of this ROI.

-
- -
-
-dims()[source]
-

The the number of dimensions of this ROI.

-
- -
-
-empty()[source]
-

Test if this ROI is empty.

-
- -
-
-get_begin()[source]
-

Smallest coordinate inside ROI.

-
- -
-
-get_bounding_box()[source]
-

Alias for to_slices().

-
- -
-
-get_center()[source]
-

Get the center of this ROI.

-
- -
-
-get_end()[source]
-

Smallest coordinate which is component-wise larger than any inside ROI.

-
- -
-
-get_shape()[source]
-

Get the shape of this ROI.

-
- -
-
-grow(amount_neg, amount_pos)[source]
-

Grow a ROI by the given amounts in each direction:

-
-
Parameters
-
    -
  • amount_neg (Coordinate or None) – Amount (per dimension) to grow into the negative direction.

  • -
  • amount_pos (Coordinate or None) – Amount (per dimension) to grow into the positive direction.

  • -
-
-
-
- -
-
-intersect(other)[source]
-

Get the intersection of this ROI with another Roi.

-
- -
-
-intersects(other)[source]
-

Test if this ROI intersects with another Roi.

-
- -
-
-set_shape(shape)[source]
-

Set the shape of this ROI.

-
-
Parameters
-

shape (array-like or None) – The new shape. Entries can be None to indicate -unboundedness. If None is passed instead of a tuple, all -dimensions are set to None, if the number of dimensions can -be inferred from an existing offset or previous shape.

-
-
-
- -
-
-shift(by)[source]
-

Shift this ROI.

-
- -
-
-size()[source]
-

Get the volume of this ROI. Returns None if the ROI is -unbounded.

-
- -
-
-snap_to_grid(voxel_size, mode='grow')[source]
-

Align a ROI with a given voxel size.

-
-
Parameters
-
    -
  • voxel_size (Coordinate) – The voxel size of the grid to snap to.

  • -
  • mode (string, optional) – How to align the ROI if it is not a multiple of the voxel size. -Available modes are ‘grow’, ‘shrink’, and ‘closest’. Defaults to -‘grow’.

  • -
-
-
-
- -
-
-to_slices()[source]
-

Get a tuple of slice that represent this ROI and can be used -to index arrays.

-
- -
-
-unbounded()[source]
-

Test if this ROI is unbounded.

-
- -
-
-union(other)[source]
-

Get the union of this ROI with another Roi.

-
- -
- -
-
-
-
-

Node Base Classes

-
-

BatchProvider

-
-
-
-class gunpowder.BatchProvider[source]
-

Superclass for all nodes in a gunpowder graph.

-

A BatchProvider provides Batches containing -Arrays and/or Graph. The available data is -specified in a ProviderSpec instance, accessible via spec.

-

To create a new node, subclass this class and implement (at least) -setup() and provide().

-

A BatchProvider can be linked to any number of other -BatchProviders upstream. If your node accepts -exactly one upstream provider, consider subclassing BatchFilter -instead.

-
-
-provide(request)[source]
-

To be implemented in subclasses.

-

This function takes a BatchRequest and should return the -corresponding Batch.

-
-
Parameters
-

request (BatchRequest) – The request to process.

-
-
-
- -
-
-provides(key, spec)[source]
-

Introduce a new output provided by this BatchProvider.

-

Implementations should call this in their setup() method, which -will be called when the pipeline is build.

-
-
Parameters
-
-
-
-
- -
-
-request_batch(request)[source]
-

Request a batch from this provider.

-
-
Parameters
-

request (BatchRequest) – A request containing (possibly partial) -ArraySpecs and -GraphSpecs.

-
-
-
- -
-
-setup()[source]
-

To be implemented in subclasses.

-

Called during initialization of the DAG. Callees can assume that all -upstream providers are set up already.

-

In setup, call provides() to announce the arrays and points -provided by this node.

-
- -
-
-property spec
-

Get the ProviderSpec of this BatchProvider.

-

Note that the spec is only available after the pipeline has been build. -Before that, it is None.

-
- -
-
-teardown()[source]
-

To be implemented in subclasses.

-

Called during destruction of the DAG. Subclasses should use this to -stop worker processes, if they used some.

-
- -
- -
-
-
-

BatchFilter

-
-
-
-class gunpowder.BatchFilter[source]
-

Convenience wrapper for BatchProviders with -exactly one input provider.

-

By default, a node of this class will expose the same ProviderSpec -as the upstream provider. You can modify the provider spec by calling -provides() and updates() in setup().

-

Subclasses need to implement at least process() to modify a passed -batch (downstream). Optionally, the following methods can be implemented:

-
-

setup()

-
-

Initialize this filter. Called after setup of the DAG. All upstream -providers will be set up already.

-
-

teardown()

-
-

Destruct this filter, free resources, stop worker processes.

-
-

prepare()

-
-

Prepare for a batch request. Always called before each -process(). Used to communicate dependencies.

-
-
-
-
-enable_autoskip(skip=True)[source]
-

Enable automatic skipping of this BatchFilter, based on -given updates() and provides() calls. Has to be called in -setup().

-

By default, BatchFilters are not skipped -automatically, regardless of what they update or provide. If autskip is -enabled, BatchFilters will only be run if the -request contains at least one key reported earlier with -updates() or provides().

-
- -
-
-prepare(request)[source]
-

To be implemented in subclasses.

-

Prepare for a batch request. Should return a BatchRequest of -needed dependencies. If None is returned, it will be assumed that all -of request is needed.

-
- -
-
-process(batch, request)[source]
-

To be implemented in subclasses.

-

Filter a batch, will be called after prepare(). Should return a -Batch containing modified Arrays and Graphs. Keys in the returned -batch will replace the associated data in the original batch. If None is -returned it is assumed that the batch has been modified in place. request -is the same as passed to prepare(), provided for convenience.

-
-
Parameters
-
    -
  • batch (Batch) – The batch received from upstream to be modified by this node.

  • -
  • request (BatchRequest) – The request this node received. The updated batch should meet -this request.

  • -
-
-
-
- -
-
-provides(key, spec)
-

Introduce a new output provided by this BatchProvider.

-

Implementations should call this in their setup() method, which -will be called when the pipeline is build.

-
-
Parameters
-
-
-
-
- -
-
-request_batch(request)
-

Request a batch from this provider.

-
-
Parameters
-

request (BatchRequest) – A request containing (possibly partial) -ArraySpecs and -GraphSpecs.

-
-
-
- -
-
-setup()[source]
-

To be implemented in subclasses.

-

Called during initialization of the DAG. Callees can assume that all -upstream providers are set up already.

-

In setup, call provides() or updates() to announce the -arrays and points provided or changed by this node.

-
- -
-
-property spec
-

Get the ProviderSpec of this BatchProvider.

-

Note that the spec is only available after the pipeline has been build. -Before that, it is None.

-
- -
-
-teardown()
-

To be implemented in subclasses.

-

Called during destruction of the DAG. Subclasses should use this to -stop worker processes, if they used some.

-
- -
-
-updates(key, spec)[source]
-

Update an output provided by this BatchFilter.

-

Implementations should call this in their setup() method, which -will be called when the pipeline is build.

-
-
Parameters
-
-
-
-
- -
- -
-
-
-
-

Source Nodes

-
-

ZarrSource

-
-
-
-class gunpowder.ZarrSource(filename, datasets, array_specs=None, channels_first=True)[source]
-

A zarr data source.

-

Provides arrays from zarr datasets. If the attribute resolution is set -in a zarr dataset, it will be used as the array’s voxel_size. If the -attribute offset is set in a dataset, it will be used as the offset of -the Roi for this array. It is assumed that the offset is given in -world units.

-
-
Parameters
-
    -
  • filename (string) – The zarr directory.

  • -
  • datasets (dict, ArrayKey -> string) – Dictionary of array keys to dataset names that this source offers.

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – An optional dictionary of array keys to array specs to overwrite -the array specs automatically determined from the data file. This -is useful to set a missing voxel_size, for example. Only fields -that are not None in the given ArraySpec will be used.

  • -
  • channels_first (bool, optional) – Specifies the ordering of the dimensions of the HDF5-like data source. -If channels_first is set (default), then the input shape is expected -to be (channels, spatial dimensions). This is recommended because of -better performance. If channels_first is set to false, then the input -data is read in channels_last manner and converted to channels_first.

  • -
-
-
-
- -
-
-
-

Hdf5Source

-
-
-
-class gunpowder.Hdf5Source(filename, datasets, array_specs=None, channels_first=True)[source]
-

An HDF5 data source.

-

Provides arrays from HDF5 datasets. If the attribute resolution is set -in a HDF5 dataset, it will be used as the array’s voxel_size. If the -attribute offset is set in a dataset, it will be used as the offset of -the Roi for this array. It is assumed that the offset is given in -world units.

-
-
Parameters
-
    -
  • filename (string) – The HDF5 file.

  • -
  • datasets (dict, ArrayKey -> string) – Dictionary of array keys to dataset names that this source offers.

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – An optional dictionary of array keys to array specs to overwrite -the array specs automatically determined from the data file. This -is useful to set a missing voxel_size, for example. Only fields -that are not None in the given ArraySpec will be used.

  • -
  • channels_first (bool, optional) – Specifies the ordering of the dimensions of the HDF5-like data source. -If channels_first is set (default), then the input shape is expected -to be (channels, spatial dimensions). This is recommended because of -better performance. If channels_first is set to false, then the input -data is read in channels_last manner and converted to channels_first.

  • -
-
-
-
- -
-
-
-

KlbSource

-
-
-
-class gunpowder.KlbSource(filename, array, array_spec=None, num_threads=1)[source]
-

A KLB -data source.

-

Provides a single array from the given KLB dataset.

-
-
Parameters
-
    -
  • filename (string) – The name of the KLB file. This string can be a glob expression -(e.g., frame_*.klb), in which case all files that match are -sorted and stacked together to form an additional dimension (like -time). The additional dimension will start at 0 and have a default -voxel size of 1 (which can be overwritten using the array_spec -argument).

  • -
  • array (ArrayKey) – ArrayKey that this source offers.

  • -
  • array_spec (ArraySpec, optional) – An optional ArraySpec to overwrite the array specs -automatically determined from the KLB file. This is useful to set -voxel_size, for example. Only fields that are not None in -the given ArraySpec will be used.

  • -
  • num_threads (int) – An optional integer to pass to pyklb reader indicating the number -of threads to use when reading klb files. Entering None causes -uses the pyklb default, which now is based on the number of cores -in the machine. This pyklb default is bad for jobs on the cluster that -are limited to the number of cores requested, and 1 is recommended.

  • -
-
-
-
- -
-
-
-

DvidSource

-
-
-
-class gunpowder.DvidSource(hostname, port, uuid, datasets, masks=None, array_specs=None)[source]
-

A DVID array source.

-

Provides arrays from DVID servers for each array key given.

-
-
Parameters
-
    -
  • hostname (string) – The name of the DVID server.

  • -
  • port (int) – The port of the DVID server.

  • -
  • uuid (string) – The UUID of the DVID node to use.

  • -
  • datasets (dict, ArrayKey -> string) – Dictionary mapping array keys to DVID data instance names that this -source offers.

  • -
  • masks (dict, ArrayKey -> string, optional) – Dictionary of array keys to DVID ROI instance names. This will -create binary masks from DVID ROIs.

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – An optional dictionary of array keys to specs to overwrite the -array specs automatically determined from the DVID server. This is -useful to set voxel_size, for example. Only fields that are not -None in the given ArraySpec will be used.

  • -
-
-
-
- -
-
-
-

CsvPointsSource

-
-
-
-class gunpowder.CsvPointsSource(filename, points, points_spec=None, scale=None, ndims=None, id_dim=None)[source]
-

Read a set of points from a comma-separated-values text file. Each line -in the file represents one point, e.g. z y x (id)

-
-
Parameters
-
    -
  • filename (string) – The file to read from.

  • -
  • points (GraphKey) – The key of the points set to create.

  • -
  • points_spec (GraphSpec, optional) – An optional GraphSpec to overwrite the points specs -automatically determined from the CSV file. This is useful to set -the Roi manually.

  • -
  • scale (scalar or array-like) – An optional scaling to apply to the coordinates of the points read -from the CSV file. This is useful if the points refer to voxel -positions to convert them to world units.

  • -
  • ndims (int) –

    -
    If ndims is None, all values in one line are considered as the

    location of the point. If positive, only the first ndims are used. -If negative, all but the last -ndims are used.

    -
    -
    -

    id_dim (int):

    -
    -

    Each line may optionally contain an id for each point. This parameter -specifies its location, has to come after the position values.

    -
    -

  • -
-
-
-
- -
-
-
-
-

Augmentation Nodes

-
-

DefectAugment

-
-
-
-class gunpowder.DefectAugment(intensities, prob_missing=0.05, prob_low_contrast=0.05, prob_artifact=0.0, prob_deform=0.0, contrast_scale=0.1, artifact_source=None, artifacts=None, artifacts_mask=None, deformation_strength=20, axis=0)[source]
-

Augment intensity arrays section-wise with artifacts like missing -sections, low-contrast sections, by blending in artifacts drawn from a -separate source, or by deforming a section.

-
-
Parameters
-
    -
  • intensities (ArrayKey) – The key of the array of intensities to modify.

  • -
  • prob_missing (float) –

  • -
  • prob_low_contrast (float) –

  • -
  • prob_artifact (float) –

  • -
  • prob_deform (float) – Probabilities of having a missing section, low-contrast section, an -artifact (see param artifact_source) or a deformed slice. The -sum should not exceed 1. Values in missing sections will be set to -0.

  • -
  • contrast_scale (float, optional) – By how much to scale the intensities for a low-contrast section, -used if prob_low_contrast > 0.

  • -
  • (class (artifact_source) –

    BatchProvider, optional):

    -

    A gunpowder batch provider that delivers intensities (via -ArrayKey artifacts) and an alpha mask (via -ArrayKey artifacts_mask), used if prob_artifact > 0.

    -

  • -
  • artifacts (ArrayKey, optional) – The key to query artifact_source for to get the intensities -of the artifacts.

  • -
  • artifacts_mask (ArrayKey, optional) – The key to query artifact_source for to get the alpha mask -of the artifacts to blend them with intensities.

  • -
  • deformation_strength (int, optional) – Strength of the slice deformation in voxels, used if -prob_deform > 0. The deformation models a fold by shifting the -section contents towards a randomly oriented line in the section. -The line itself will be drawn with a value of 0.

  • -
  • axis (int, optional) – Along which axis sections are cut.

  • -
-
-
-
- -
-
-
-

ElasticAugment

-
-
-
-class gunpowder.ElasticAugment(control_point_spacing, jitter_sigma, rotation_interval, prob_slip=0, prob_shift=0, max_misalign=0, subsample=1, spatial_dims=3, use_fast_points_transform=False, recompute_missing_points=True)[source]
-

Elasticly deform a batch. Requests larger batches upstream to avoid data -loss due to rotation and jitter.

-
-
Parameters
-
    -
  • control_point_spacing (tuple of int) – Distance between control points for the elastic deformation, in -voxels per dimension.

  • -
  • jitter_sigma (tuple of float) – Standard deviation of control point jitter distribution, in voxels -per dimension.

  • -
  • rotation_interval (tuple of two floats) – Interval to randomly sample rotation angles from (0, 2PI).

  • -
  • prob_slip (float) – Probability of a section to “slip”, i.e., be independently moved in -x-y.

  • -
  • prob_shift (float) – Probability of a section and all following sections to move in x-y.

  • -
  • max_misalign (int) – Maximal voxels to shift in x and y. Samples will be drawn -uniformly. Used if prob_slip + prob_shift > 0.

  • -
  • subsample (int) – Instead of creating an elastic transformation on the full -resolution, create one subsampled by the given factor, and linearly -interpolate to obtain the full resolution transformation. This can -significantly speed up this node, at the expense of having visible -piecewise linear deformations for large factors. Usually, a factor -of 4 can savely by used without noticable changes. However, the -default is 1 (i.e., no subsampling).

  • -
  • spatial_dims (int) – The number of spatial dimensions in arrays. Spatial dimensions are -assumed to be the last ones and cannot be more than 3 (default). -Set this value here to avoid treating channels as spacial -dimension. If, for example, your array is indexed as (c,y,x) -(2D plus channels), you would want to set spatial_dims=2 to -perform the elastic deformation only on x and y.

  • -
  • use_fast_points_transform (bool) – By solving for all of your points simultaneously with the following -3 step proceedure: -1) Rasterize nodes into numpy array -2) Apply elastic transform to array -3) Read out nodes via center of mass of transformed points -You can gain substantial speed up as opposed to calculating the -elastic transform for each point individually. However this may -lead to nodes being lost during the transform.

  • -
  • recompute_missing_points (bool) – Whether or not to compute the elastic transform node wise for nodes -that were lossed during the fast elastic transform process.

  • -
-
-
-
- -
-
-
-

IntensityAugment

-
-
-
-class gunpowder.IntensityAugment(array, scale_min, scale_max, shift_min, shift_max, z_section_wise=False, clip=True)[source]
-

Randomly scale and shift the values of an intensity array.

-
-
Parameters
-
    -
  • array (ArrayKey) – The intensity array to modify.

  • -
  • scale_min (float) –

  • -
  • scale_max (float) –

  • -
  • shift_min (float) –

  • -
  • shift_max (float) –

    The min and max of the uniformly randomly drawn scaling and -shifting values for the intensity augmentation. Intensities are -changed as:

    -
    a = a.mean() + (a-a.mean())*scale + shift
    -
    -
    -

  • -
  • z_section_wise (bool) – Perform the augmentation z-section wise. Requires 3D arrays and -assumes that z is the first dimension.

  • -
  • clip (bool) – Set to False if modified values should not be clipped to [0, 1] -Disables range check!

  • -
-
-
-
- -
-
-
-

NoiseAugment

-
-
-
-class gunpowder.NoiseAugment(array, mode='gaussian', seed=None, clip=True, **kwargs)[source]
-

Add random noise to an array. Uses the scikit-image function skimage.util.random_noise. -See scikit-image documentation for more information on arguments and additional kwargs.

-
-
Parameters
-
    -
  • array (ArrayKey) – The intensity array to modify. Should be of type float and within range [-1, 1] or [0, 1].

  • -
  • mode (string) – Type of noise to add, see scikit-image documentation.

  • -
  • seed (int) – Optionally set a random seed, see scikit-image documentation.

  • -
  • clip (bool) – Whether to preserve the image range (either [-1, 1] or [0, 1]) by clipping values in the end, see -scikit-image documentation

  • -
-
-
-
- -
-
-
-

SimpleAugment

-
-
-
-class gunpowder.SimpleAugment(mirror_only=None, transpose_only=None)[source]
-

Randomly mirror and transpose all Arrays and -Graph in a batch.

-
-
Parameters
-
    -
  • mirror_only (list of int, optional) – If set, only mirror between the given axes. This is useful to -exclude channels that have a set direction, like time.

  • -
  • transpose_only (list of int, optional) – If set, only transpose between the given axes. This is useful to -limit the transpose to axes with the same resolution or to exclude -non-spatial dimensions.

  • -
-
-
-
- -
-
-
-
-

Location Manipulation Nodes

-
-

Crop

-
-
-
-class gunpowder.Crop(key, roi=None, fraction_negative=None, fraction_positive=None)[source]
-

Limits provided ROIs by either giving a new Roi or crop -fractions from either face of the provided ROI.

-
-
Parameters
-
    -
  • key (ArrayKey or GraphKey) – The key of the array or points set to modify.

  • -
  • roi (Roi or None) – The ROI to crop to.

  • -
  • fraction_negative (tuple of float) – Relative crop starting from the negative end of the provided ROI.

  • -
  • fraction_positive (tuple of float) – Relative crop starting from the positive end of the provided ROI.

  • -
-
-
-
- -
-
-
-

Pad

-
-
-
-class gunpowder.Pad(key, size, value=None)[source]
-

Add a constant intensity padding around arrays of another batch -provider. This is useful if your requested batches can be larger than what -your source provides.

-
-
Parameters
-
    -
  • key (ArrayKey or GraphKey) – The array or points set to pad.

  • -
  • size (Coordinate or None) – The padding to be added. If None, an infinite padding is added. If -a coordinate, this amount will be added to the ROI in the positive -and negative direction.

  • -
  • value (scalar or None) – The value to report inside the padding. If not given, 0 is used. -Only used for Array.

  • -
-
-
-
- -
-
-
-

RandomLocation

-
-
-
-class gunpowder.RandomLocation(min_masked=0, mask=None, ensure_nonempty=None, p_nonempty=1.0, ensure_centered=None, point_balance_radius=1)[source]
-

Choses a batch at a random location in the bounding box of the upstream -provider.

-

The random location is chosen such that the batch request ROI lies entirely -inside the provider’s ROI.

-

If min_masked and mask are set, only batches are returned that have -at least the given ratio of masked-in voxels. This is in general faster -than using the Reject node, at the expense of storing an integral -array of the complete mask.

-

If ensure_nonempty is set to a GraphKey, only batches are -returned that have at least one point of this point collection within the -requested ROI.

-

Additional tests for randomly picked locations can be implemented by -subclassing and overwriting of accepts(). This method takes the -randomly shifted request that meets all previous criteria (like -min_masked and ensure_nonempty) and should return True if the -request is acceptable.

-
-
Parameters
-
    -
  • min_masked (float, optional) – If non-zero, require that the random sample contains at least that -ratio of masked-in voxels.

  • -
  • mask (ArrayKey, optional) – The array to use for mask checks.

  • -
  • ensure_nonempty (GraphKey, optional) – Ensures that when finding a random location, a request for -ensure_nonempty will contain at least one point.

  • -
  • p_nonempty (float, optional) – If ensure_nonempty is set, it defines the probability that a -request for ensure_nonempty will contain at least one point. -Default value is 1.0.

  • -
  • ensure_centered (bool, optional) – if ensure_nonempty is set, ensure_centered guarantees -that the center voxel of the roi contains a point.

  • -
  • point_balance_radius (int) – if ensure_nonempty is set, point_balance_radius defines -a radius s.t. for every point p in ensure_nonempty, the -probability of picking p is inversely related to the number of -other points within a distance of point_balance_radius to p. -This helps avoid oversampling of dense regions of the graph, and -undersampling of sparse regions.

  • -
-
-
-
- -
-
-
-

Reject

-
-
-
-class gunpowder.Reject(mask=None, min_masked=0.5, ensure_nonempty=None, reject_probability=1.0)[source]
-

Reject batches based on the masked-in vs. masked-out ratio.

-
-
Parameters
-
    -
  • mask (ArrayKey, optional) – The mask to use, if any.

  • -
  • min_masked (float, optional) – The minimal required ratio of masked-in vs. masked-out voxels. -Defaults to 0.5.

  • -
  • ensure_nonempty (GraphKey, optional) – Ensures there is at least one point in the batch.

  • -
  • reject_probability (float, optional) – The probability by which a batch that is not valid (less than -min_masked) is actually rejected. Defaults to 1., i.e. strict -rejection.

  • -
-
-
-
- -
-
-
-

SpecifiedLocation

-
-
-
-class gunpowder.SpecifiedLocation(locations, choose_randomly=False, extra_data=None, jitter=None)[source]
-

Choses a batch at a location from the list provided at init, making sure -it is in the bounding box of the upstream provider.

-

Locations should be given in world units.

-

Locations will be chosen in order or at random from the list depending on the -choose_randomly parameter.

-

If a location requires a shift outside the bounding box of any upstream provider -the module will skip that location with a warning.

-
-
Parameters
-
    -
  • locations (list of locations) – Locations to center batches around.

  • -
  • choose_randomly (bool) – Defines whether locations should be picked in order or at random -from the list.

  • -
  • extra_data (list of array-like) – A list of data that will be passed along with the arrays provided -by this node. This data will be appended as an attribute to the -dataset so it must be a data format compatible with hdf5.

  • -
  • jitter (tuple of int) – How far to allow the point to shift in each direction. -Default is None, which places the point in the center. -Chooses uniformly from [loc - jitter, loc + jitter] in each -direction.

  • -
-
-
-
- -
-
-
-
-

Array Manipulation Nodes

-
-

Squeeze

-
-
-
-class gunpowder.Squeeze(arrays: List[gunpowder.array.ArrayKey], axis: int = 0)[source]
-

Squeeze a batch at a given axis

-
-
Parameters
-
    -
  • arrays (List[ArrayKey]) – ArrayKeys to squeeze.

  • -
  • axis – Position of the single-dimensional axis to remove, defaults to 0.

  • -
-
-
-
- -
-
-
-

Unsqueeze

-
-
-
-class gunpowder.Unsqueeze(arrays: List[gunpowder.array.ArrayKey], axis: int = 0)[source]
-

Unsqueeze a batch at a given axis

-
-
Parameters
-
    -
  • arrays (List[ArrayKey]) – ArrayKeys to unsqueeze.

  • -
  • axis – Position where the new axis is placed, defaults to 0.

  • -
-
-
-
- -
-
-
-
-

Image Processing Nodes

-
-

DownSample

-
-
-
-class gunpowder.DownSample(source, factor, target)[source]
-

Downsample arrays in a batch by given factors.

-
-
Parameters
-
    -
  • source (ArrayKey) – The key of the array to downsample.

  • -
  • factor (int or tuple of int) – The factor to downsample with.

  • -
  • target (ArrayKey) – The key of the array to store the downsampled source.

  • -
-
-
-
- -
-
-
-

UpSample

-
-
-
-class gunpowder.UpSample(source, factor, target)[source]
-

Upsample arrays in a batch by given factors.

-
-
Parameters
-
    -
  • source (ArrayKey) – The key of the array to upsample.

  • -
  • factor (int or tuple of int) – The factor to upsample with.

  • -
  • target (ArrayKey) – The key of the array to store the upsampled source.

  • -
-
-
-
- -
-
-
-

IntensityScaleShift

-
-
-
-class gunpowder.IntensityScaleShift(array, scale, shift)[source]
-

Scales the intensities of a batch by scale, then adds shift.

-
-
Parameters
-
    -
  • array (ArrayKey) – The key of the array to modify.

  • -
  • scale (float) –

  • -
  • shift (float) – The shift and scale to apply to array.

  • -
-
-
-
- -
-
-
-

Normalize

-
-
-
-class gunpowder.Normalize(array, factor=None, dtype=<class 'numpy.float32'>)[source]
-

Normalize the values of an array to be floats between 0 and 1, based on -the type of the array.

-
-
Parameters
-
    -
  • array (ArrayKey) – The key of the array to modify.

  • -
  • factor (scalar, optional) – The factor to use. If not given, a factor is chosen based on the -dtype of the array (e.g., np.uint8 would result in a factor -of 1.0/255).

  • -
  • dtype (data-type, optional) – The datatype of the normalized array. Defaults to np.float32.

  • -
-
-
-
- -
-
-
-
-

Label Manipulation Nodes

-
-

AddAffinities

-
-
-
-class gunpowder.AddAffinities(affinity_neighborhood, labels, affinities, labels_mask=None, unlabelled=None, affinities_mask=None, dtype=<class 'numpy.uint8'>)[source]
-

Add an array with affinities for a given label array and neighborhood to -the batch. Affinity values are created one for each voxel and entry in the -neighborhood list, i.e., for each voxel and each neighbor of this voxel. -Values are 1 iff both labels (of the voxel and the neighbor) are equal and -non-zero.

-
-
Parameters
-
    -
  • affinity_neighborhood (list of array-like) – List of offsets for the affinities to consider for each voxel.

  • -
  • labels (ArrayKey) – The array to read the labels from.

  • -
  • affinities (ArrayKey) – The array to generate containing the affinities.

  • -
  • labels_mask (ArrayKey, optional) – The array to use as a mask for labels. Affinities connecting at -least one masked out label will be masked out in -affinities_mask. If not given, affinities_mask will contain -ones everywhere (if requested).

  • -
  • unlabelled (ArrayKey, optional) – A binary array to indicate unlabelled areas with 0. Affinities from -labelled to unlabelled voxels are set to 0, affinities between -unlabelled voxels are masked out (they will not be used for -training).

  • -
  • affinities_mask (ArrayKey, optional) – The array to generate containing the affinitiy mask, as derived -from parameter labels_mask.

  • -
-
-
-
- -
-
-
-

BalanceLabels

-
-
-
-class gunpowder.BalanceLabels(labels, scales, mask=None, slab=None, num_classes=2, clipmin=0.05, clipmax=0.95)[source]
-

Creates a scale array to balance the loss between class labels.

-

Note that this only balances loss weights per-batch and does not accumulate -statistics about class balance across batches.

-
-
Parameters
-
    -
  • labels (ArrayKey) – An array containing binary or integer labels.

  • -
  • scales (ArrayKey) – A array with scales to be created. This new array will have the -same ROI and resolution as labels.

  • -
  • mask (ArrayKey, optional) – An optional mask (or list of masks) to consider for balancing. -Every voxel marked with a 0 will not contribute to the scaling and -will have a scale of 0 in scales.

  • -
  • slab (tuple of int, optional) –

    A shape specification to perform the balancing in slabs of this -size. -1 can be used to refer to the actual size of the label -array. For example, a slab of:

    -
    (2, -1, -1, -1)
    -
    -
    -

    will perform the balancing for every each slice [0:2,:], -[2:4,:], … individually.

    -

  • -
  • num_classes (int, optional) – The number of classes. Labels will be expected to be in the -interval [0, num_classes). Defaults to 2 for binary -classification.

  • -
  • clipmin (float, optional) – Clip class fraction to clipmin when calculating class weights. -Defaults to 0.05. Set to None if you do not want to clip min values.

  • -
  • clipmax (float, optional) – Clip class fraction to clipmax when calculating class weights. -Defaults to 0.95. Set to None, if you do not want to clip max -values.

  • -
-
-
-
- -
-
-
-

ExcludeLabels

-
-
-
-class gunpowder.ExcludeLabels(labels, exclude, ignore_mask=None, ignore_mask_erode=0, background_value=0)[source]
-

Excludes several labels from the ground-truth.

-

The labels will be replaced by background_value. An optional ignore mask -will be created and set to 0 for the excluded locations that are further -than a threshold away from not excluded locations.

-
-
Parameters
-
    -
  • labels (ArrayKey) – The array containing the labels.

  • -
  • exclude (list of int) – The labels to exclude from labels.

  • -
  • ignore_mask (ArrayKey, optional) – The ignore mask to create.

  • -
  • ignore_mask_erode (float, optional) – By how much (in world units) to erode the ignore mask.

  • -
  • background_value (int, optional) – Value to replace excluded IDs, defaults to 0.

  • -
-
-
-
- -
-
-
-

GrowBoundary

-
-
-
-class gunpowder.GrowBoundary(labels, mask=None, steps=1, background=0, only_xy=False)[source]
-

Grow a boundary between regions in a label array. Does not grow at the -border of the batch or an optionally provided mask.

-
-
Parameters
-
    -
  • labels (ArrayKey) – The array containing labels.

  • -
  • mask (ArrayKey, optional) – A mask indicating unknown regions. This is to avoid boundaries to -grow between labelled and unknown regions.

  • -
  • steps (int, optional) – Number of voxels (not world units!) to grow.

  • -
  • background (int, optional) – The label to assign to the boundary voxels.

  • -
  • only_xy (bool, optional) – Do not grow a boundary in the z direction.

  • -
-
-
-
- -
-
-
-

RenumberConnectedComponents

-
-
-
-class gunpowder.RenumberConnectedComponents(labels)[source]
-

Find connected components of the same value, and replace each component -with a new label.

-
-
Parameters
-

labels (ArrayKey) – The label array to modify.

-
-
-
- -
-
-
-
-

Point Processing Nodes

-
-

RasterizeGraph

-
-
-
-class gunpowder.RasterizeGraph(graph, array, array_spec=None, settings=None)[source]
-

Draw graphs into a binary array as balls/tubes of a given radius.

-
-
Parameters
-
    -
  • graph (GraphKey) – The key of the graph to rasterize.

  • -
  • array (ArrayKey) – The key of the binary array to create.

  • -
  • array_spec (ArraySpec, optional) – The spec of the array to create. Use this to set the datatype and -voxel size.

  • -
  • settings (RasterizationSettings, optional) – Which settings to use to rasterize the graph.

  • -
-
-
-
- -
-
-class gunpowder.RasterizationSettings(radius, mode='ball', mask=None, inner_radius_fraction=None, fg_value=1, bg_value=0, edges=True, color_attr=None)[source]
-

Data structure to store parameters for rasterization of graph.

-
-
Parameters
-
    -
  • radius (float or tuple of float) – The radius (for balls or tubes) or sigma (for peaks) in world units.

  • -
  • mode (string) – One of ball or peak. If ball (the default), a ball with the -given radius will be drawn. If peak, the point will be -rasterized as a peak with values \(\exp(-|x-p|^2/\sigma)\) with -sigma set by radius.

  • -
  • mask (ArrayKey, optional) – Used to mask the rasterization of points. The array is assumed to -contain discrete labels. The object id at the specific point being -rasterized is used to intersect the rasterization to keep it inside -the specific object.

  • -
  • inner_radius_fraction (float, optional) –

    Only for mode ball.

    -

    If set, instead of a ball, a hollow sphere is rastered. The radius -of the whole sphere corresponds to the radius specified with -radius. This parameter sets the radius of the hollow area, as a -fraction of radius.

    -

  • -
  • fg_value (int, optional) –

    Only for mode ball.

    -

    The value to use to rasterize points, defaults to 1.

    -

  • -
  • bg_value (int, optional) –

    Only for mode ball.

    -

    The value to use to for the background in the output array, -defaults to 0.

    -

  • -
  • edges (bool, optional) – Whether to rasterize edges by linearly interpolating between Nodes. -Default is True.

  • -
  • color_attr (str, optional) – Which graph attribute to use for coloring nodes and edges. One -useful example might be component which would color your graph -based on the component labels. -Notes: -- Only available in “ball” mode -- Nodes and Edges missing the attribute will be skipped. -- color_attr must be populated for nodes and edges upstream of this node

  • -
-
-
-
- -
-
-
-
-

Provider Combination Nodes

-
-

MergeProvider

-
-
-
-class gunpowder.MergeProvider[source]
-

Merges different providers:

-
(a + b + c) + MergeProvider()
-
-
-

will create a provider that combines the arrays and points offered by -a, b, and c. Array and point keys of a, b, and c should be -the disjoint.

-
- -
-
-
-

RandomProvider

-
-
-
-class gunpowder.RandomProvider(probabilities=None)[source]
-

Randomly selects one of the upstream providers:

-
(a + b + c) + RandomProvider()
-
-
-

will create a provider that randomly relays requests to providers a, -b, or c. Array and point keys of a, b, and c should be -the same.

-
-
Parameters
-

probabilities (1-D array-like, optional) – An optional list of -probabilities for choosing upstream providers, given in the -same order. Probabilities do not need to be normalized. Default -is None, corresponding to equal probabilities.

-
-
-
- -
-
-
-
-

Training and Prediction Nodes

-
-

Stack

-
-
-
-class gunpowder.Stack(num_repetitions)[source]
-

Request several batches and stack them together, introducing a new -dimension for each array. This is useful to create batches with several -samples and only makes sense if there is a source of randomness upstream.

-

This node stacks only arrays, not points. The resulting batch will have the -same point sets as found in the first batch requested upstream.

-
-
Parameters
-

num_repetitions (int) – How many upstream batches to stack.

-
-
-
- -
-
-
-

torch.Train

-
-
-
-class gunpowder.torch.Train(model, loss, optimizer, inputs: Dict[str, gunpowder.array.ArrayKey], outputs: Dict[Union[int, str], gunpowder.array.ArrayKey], loss_inputs: Dict[Union[int, str], gunpowder.array.ArrayKey], gradients: Dict[Union[int, str], gunpowder.array.ArrayKey] = {}, array_specs: Optional[Dict[gunpowder.array.ArrayKey, gunpowder.array_spec.ArraySpec]] = None, checkpoint_basename: str = 'model', save_every: int = 2000, log_dir: str = None, log_every: int = 1, spawn_subprocess: bool = False)[source]
-

Torch implementation of gunpowder.nodes.GenericTrain.

-
-
Parameters
-
    -
  • model (subclass of torch.nn.Module) – The model to train.

  • -
  • loss – The torch loss to use.

  • -
  • optimizer – The torch optimizer to use.

  • -
  • inputs (dict, string -> ArrayKey) – Dictionary from the names of input tensors (argument names of the -forward method) in the model to array keys.

  • -
  • loss_inputs (dict, string or int -> ArrayKey) – Dictionary with the names of input variables to the loss function as -keys, and ArrayKeys containing the desired data as values. Keys can -be either strings or integers. If the key is an integer, it will -be treated as a positional argument to the loss function, a -string will be used as a named argument

  • -
  • outputs (dict, string or int -> ArrayKey) – Dictionary from the names of tensors in the network to array -keys. If the key is a string, the tensor will be retrieved -by checking the model for an attribute with they key as its name. -If the key is an integer, it is interpreted as a tuple index of -the outputs of the network. -New arrays will be generated by this node for each entry (if -requested downstream).

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – Used to set the specs of generated arrays (at the moment only -output). This is useful to set the voxel_size, for example, -if they differ from the voxel size of the input arrays. Only fields -that are not None in the given ArraySpec will be used.

  • -
  • checkpoint_basename (string, optional) – The basename used for checkpoint files. Defaults to model.

  • -
  • save_every (int, optional) – After how many iterations to create a checkpoint to store the -learnt weights.

  • -
  • log_dir (string, optional) – Directory for saving tensorboard summaries.

  • -
  • log_every (int, optional) – After how many iterations to write out tensorboard summaries.

  • -
  • spawn_subprocess (bool, optional) – Whether to run the train_step in a separate process. Default is false.

  • -
-
-
-
- -
-
-
-

torch.Predict

-
-
-
-class gunpowder.torch.Predict(model, inputs: Dict[str, gunpowder.array.ArrayKey], outputs: Dict[Union[int, str], gunpowder.array.ArrayKey], array_specs: Dict[gunpowder.array.ArrayKey, gunpowder.array_spec.ArraySpec] = None, checkpoint: str = None, device='cuda', spawn_subprocess=False)[source]
-

Torch implementation of gunpowder.nodes.Predict.

-
-
Parameters
-
    -
  • model (subclass of torch.nn.Module) – The model to use for prediction.

  • -
  • inputs (dict, string -> ArrayKey) – Dictionary from the names of input tensors (argument names of the -forward method) in the model to array keys.

  • -
  • outputs (dict, string or int -> ArrayKey) – Dictionary from the names of tensors in the network to array -keys. If the key is a string, the tensor will be retrieved -by checking the model for an attribute with the key as its name. -If the key is an integer, it is interpreted as a tuple index of -the outputs of the network. -New arrays will be generated by this node for each entry (if -requested downstream).

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – Used to set the specs of generated arrays (outputs). This is -useful to set the voxel_size, for example, if they differ from -the voxel size of the input arrays. Only fields that are not -None in the given ArraySpec will be used.

  • -
  • checkpoint

    (string, optional):

    -

    An optional path to the saved parameters for your torch module. -These will be loaded and used for prediction if provided.

    -

  • -
  • device (string, optional) – Which device to use for prediction ("cpu" or "cuda"). -Default is "cuda", which falls back to CPU if CUDA is not -available.

  • -
  • spawn_subprocess (bool, optional) – Whether to run predict in a -separate process. Default is false.

  • -
-
-
-
- -
-
-
-

tensorflow.Train

-
-
-
-class gunpowder.tensorflow.Train(graph, optimizer, loss, inputs, outputs, gradients, summary=None, array_specs=None, save_every=2000, log_dir='./', log_every=1)[source]
-

Tensorflow implementation of gunpowder.nodes.Train.

-
-
Parameters
-
    -
  • graph (string) –

    Filename of a tensorflow meta-graph storing the tensorflow graph -containing an optimizer. A meta-graph file can be created by -running:

    -
    # create tensorflow graph
    -...
    -
    -# store it
    -tf.train.export_meta_graph(filename='...')
    -
    -
    -

  • -
  • optimizer (string or function) –

    Either the name of the tensorflow operator performing a training -iteration, or a function that, given the graph of the meta-graph -file, adds a custom loss and optimizer.

    -

    If a function is given, it should return a tuple (loss, -optimizer) of a tensor and an operator representing the loss and -the optimizer, respectively. In this case, parameter loss -should be None.

    -

    Example:

    -
    def add_custom_optimizer(graph):
    -
    -    # get the output of your graph
    -    output = graph.get_tensor_by_name('...')
    -
    -    # create your custom loss
    -    loss = custom_loss(output)
    -
    -    # add an optimizer of your choice
    -    optimizer = tf.train.AdamOptimizer().minimize(loss)
    -
    -    return (loss, optimizer)
    -
    -
    -

  • -
  • loss (string or None) – The name of the tensorflow tensor containing the loss, or None -if optimizer is a function.

  • -
  • inputs (dict, string -> ArrayKey) – Dictionary from the names of input tensors in the network to -array keys.

  • -
  • outputs (dict, string -> ArrayKey) – Dictionary from the names of output tensors in the network to array -keys. New arrays will be generated by this node for each entry (if -requested downstream).

  • -
  • gradients (dict, string -> ArrayKey) – Dictionary from the names of output tensors in the network to -array keys. New arrays containing the gradient of an output with -respect to the loss will be generated by this node for each entry -(if requested downstream).

  • -
  • (string or (summary) –

    -
    dict, string -> (string (tensor name), freq),

    optional):

    -
    -
    -

    The name of the tensorflow tensor containing the tensorboard -summaries or dictionary for different subcategories of summaires -(key: string, value: tuple with tensor/op name and frequency, -of evaluation).

    -

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – Used to set the specs of generated arrays (outputs). This is -useful to set the voxel_size, for example, if they differ from -the voxel size of the input arrays. Only fields that are not -None in the given ArraySpec will be used.

  • -
  • save_every (int, optional) – After how many iterations to create a checkpoint to store the -learnt weights.

  • -
  • log_dir (string, optional) – Directory for saving tensorboard summaries.

  • -
  • log_every (int, optional) – After how many iterations to write out tensorboard summaries.

  • -
-
-
-
- -
-
-
-

tensorflow.Predict

-
-
-
-class gunpowder.tensorflow.Predict(checkpoint, inputs, outputs, array_specs=None, graph=None, skip_empty=False, max_shared_memory=1073741824)[source]
-

Tensorflow implementation of gunpowder.nodes.Predict.

-
-
Parameters
-
    -
  • checkpoint (string) – Basename of a tensorflow checkpoint storing the tensorflow graph -and associated tensor values and metadata, as created by -gunpowder.nodes.Train, for example.

  • -
  • inputs (dict, string -> ArrayKey) – Dictionary from the names of input tensors in the network to -array keys.

  • -
  • outputs (dict, string -> ArrayKey) – Dictionary from the names of output tensors in the network to array -keys. New arrays will be generated by this node for each entry (if -requested downstream).

  • -
  • array_specs (dict, ArrayKey -> ArraySpec, optional) – Used to set the specs of generated arrays (outputs). This is -useful to set the voxel_size, for example, if they differ from -the voxel size of the input arrays. Only fields that are not -None in the given ArraySpec will be used.

  • -
  • graph

    (string, optional):

    -

    An optional path to a tensorflow computation graph that should be -used for prediction. The checkpoint is used to restore the values -of matching variable names in the graph. Note that the graph -specified here can differ from the one associated to the -checkpoint.

    -

  • -
  • skip_empty (bool, optional) – Skip prediction, if all inputs are empty (contain only 0). In this -case, outputs are simply set to 0.

  • -
  • max_shared_memory (int, optional) – The maximal amount of shared memory in bytes to allocate to send -batches to the GPU processes. Defaults to 1GB.

  • -
-
-
-
- -
-
-
-
-

Output Nodes

-
-

Hdf5Write

-
-
-
-class gunpowder.Hdf5Write(dataset_names, output_dir='.', output_filename='output.hdf', compression_type=None, dataset_dtypes=None)[source]
-

Assemble arrays of passing batches in one HDF5 file. This is useful to -store chunks produced by Scan on disk without keeping the larger -array in memory. The ROIs of the passing arrays will be used to determine -the position where to store the data in the dataset.

-
-
Parameters
-
    -
  • dataset_names (dict, ArrayKey -> string) – A dictionary from array keys to names of the datasets to store them -in.

  • -
  • output_dir (string) – The directory to save the HDF5 file. Will be created, if it does -not exist.

  • -
  • output_filename (string) – The output filename of the container. Will be created, if it does -not exist, otherwise data is overwritten in the existing container.

  • -
  • compression_type (string or int) – Compression strategy. Legal values are gzip, szip, -lzf. If an integer between 1 and 10, this indicates gzip -compression level.

  • -
  • dataset_dtypes (dict, ArrayKey -> data type) – A dictionary from array keys to datatype (eg. np.int8). If -given, arrays are stored using this type. The original arrays -within the pipeline remain unchanged.

  • -
-
-
-
- -
-
-
-

ZarrWrite

-
-
-
-class gunpowder.ZarrWrite(dataset_names, output_dir='.', output_filename='output.hdf', compression_type=None, dataset_dtypes=None)[source]
-

Assemble arrays of passing batches in one zarr container. This is useful -to store chunks produced by Scan on disk without keeping the -larger array in memory. The ROIs of the passing arrays will be used to -determine the position where to store the data in the dataset.

-
-
Parameters
-
    -
  • dataset_names (dict, ArrayKey -> string) – A dictionary from array keys to names of the datasets to store them -in.

  • -
  • output_dir (string) – The directory to save the zarr container. Will be created, if it does -not exist.

  • -
  • output_filename (string) – The output filename of the container. Will be created, if it does -not exist, otherwise data is overwritten in the existing container.

  • -
  • compression_type (string or int) – Compression strategy. Legal values are gzip, szip, -lzf. If an integer between 1 and 10, this indicates gzip -compression level.

  • -
  • dataset_dtypes (dict, ArrayKey -> data type) – A dictionary from array keys to datatype (eg. np.int8). If -given, arrays are stored using this type. The original arrays -within the pipeline remain unchanged.

  • -
-
-
-
- -
-
-
-

Snapshot

-
-
-
-class gunpowder.Snapshot(dataset_names, output_dir='snapshots', output_filename='{id}.zarr', every=1, additional_request=None, compression_type=None, dataset_dtypes=None, store_value_range=False)[source]
-

Save a passing batch in an HDF file.

-
-
Parameters
-
    -
  • dataset_names (dict, ArrayKey -> string) – A dictionary from array keys to names of the datasets to store them -in.

  • -
  • output_dir (string) – The directory to save the snapshots. Will be created, if it does -not exist.

  • -
  • output_filename (string) – Template for output filenames. {id} in the string will be -replaced with the ID of the batch. {iteration} with the training -iteration (if training was performed on this batch).

  • -
  • every (int) – How often to save a batch. every=1 indicates that every batch -will be stored, every=2 every second and so on. By default, -every batch will be stored.

  • -
  • additional_request (BatchRequest) – An additional batch request to merge with the passing request, if a -snapshot is to be made. If not given, only the arrays that are in -the batch anyway are recorded. This is useful to request additional -arrays like loss gradients for visualization that are otherwise not -needed.

  • -
  • compression_type (string or int) – Compression strategy. Legal values are gzip, szip, -lzf. If an integer between 1 and 10, this indicates gzip -compression level.

  • -
  • dataset_dtypes (dict, ArrayKey -> data type) – A dictionary from array keys to datatype (eg. np.int8). If -given, arrays are stored using this type. The original arrays -within the pipeline remain unchanged.

  • -
  • store_value_range (bool) – If set to True, store range of values in data set attributes.

  • -
-
-
-
- -
-
-
-
-

Performance Nodes

-
-

PreCache

-
-
-
-class gunpowder.PreCache(cache_size=50, num_workers=20)[source]
-

Pre-cache repeated equal batch requests. For the first of a series of -equal batch request, a set of workers is spawned to pre-cache the batches -in parallel processes. This way, subsequent requests can be served quickly.

-

A note on changing the requests sent to PreCache. -Given requests A and B, if requests are sent in the sequence: -A, …, A, B, A, …, A, B, A, … -Precache will build a Queue of batches that satisfy A, and handle requests -B on demand. This prevents PreCache from discarding the queue on every -SnapshotRequest. -However if B request replace A as the most common request, i.e.: -A, A, A, …, A, B, B, B, …, -PreCache will discard the A queue and build a B queue after it has seen -more B requests than A requests out of the last 5 requests.

-

This node only makes sense if:

-
    -
  1. Incoming batch requests are repeatedly the same.

  2. -
  3. There is a source of randomness in upstream nodes.

  4. -
-
-
Parameters
-
    -
  • cache_size (int) – How many batches to hold at most in the cache.

  • -
  • num_workers (int) – How many processes to spawn to fill the cache.

  • -
-
-
-
- -
-
-
-

PrintProfilingStats

-
-
-
-class gunpowder.PrintProfilingStats(every=1)[source]
-

Print profiling information about nodes upstream of this node in the DAG.

-

The output also includes a TOTAL section, which shows the wall-time -spent in the upstream and downstream passes. For the downstream pass, this -information is not available in the first iteration, since the request-batch -cycle is not completed, yet.

-
-
Parameters
-

every (int) – Collect statistics about that many batch requests and show min, -max, mean, and median runtimes.

-
-
-
- -
-
-
-
-

Iterative Processing Nodes

-
-

Scan

-
-
-
-class gunpowder.Scan(reference, num_workers=1, cache_size=50)[source]
-

Iteratively requests batches of size reference from upstream -providers in a scanning fashion, until all requested ROIs are covered. If -the batch request to this node is empty, it will scan the complete upstream -ROIs (and return nothing). Otherwise, it scans only the requested ROIs and -returns a batch assembled of the smaller requests. In either case, the -upstream requests will be contained in the downstream requested ROI or -upstream ROIs.

-

See also Hdf5Write.

-
-
Parameters
-
    -
  • reference (BatchRequest) – A reference BatchRequest. This request will be shifted in -a scanning fashion over the upstream ROIs of the requested arrays -or points.

  • -
  • num_workers (int, optional) – If set to >1, upstream requests are made in parallel with that -number of workers.

  • -
  • cache_size (int, optional) – If multiple workers are used, how many batches to hold at most.

  • -
-
-
-
- -
-
-
-

DaisyRequestBlocks

-
-
-
-class gunpowder.DaisyRequestBlocks(reference, roi_map, num_workers=1, block_done_callback=None)[source]
-

Iteratively requests batches similar to reference from upstream -providers, with their ROIs set to blocks distributed by daisy.

-

The ROIs of the array or point specs in the reference can be set to either -the block’s read_roi or write_roi, see parameter roi_map.

-

The batch request to this node has to be empty, as there is no guarantee -that this node will get to process all chunks required to fulfill a -particular batch request.

-
-
Parameters
-

reference (BatchRequest) – A reference BatchRequest. This request will be shifted -according to blocks distributed by daisy.

-
-
-

:param roi_map (dict from ArrayKey or GraphKey to: -:param string): A map indicating which daisy block ROI (read_roi or

-
-

write_roi) to use for which item in the reference request.

-
-
-
Parameters
-
    -
  • num_workers (int, optional) – If set to >1, upstream requests are made in parallel with that -number of workers.

  • -
  • block_done_callback (function, optional) –

    If given, will be called with arguments (block, start, -duration) for each block that was processed. start and -duration will be given in seconds, as in start = -time.time() and duration = time.time() - start, right before -and after a block gets processed.

    -

    This callback can be used to log blocks that have successfully -finished processing, which can be used in check_function of -daisy.run_blockwise to skip already processed blocks in -repeated runs.

    -

  • -
-
-
-
- -
-
-
-
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/build/Makefile b/docs/build/Makefile deleted file mode 100644 index 830f9d8b..00000000 --- a/docs/build/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = python -msphinx -SPHINXPROJ = gunpowder -SOURCEDIR = . -BUILDDIR = _build - -default: - @$(SPHINXBUILD) -M html "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -rm ../*.html - -rm ../*.inv - -rm ../*.js - -rm -r ../_sources - -rm -r ../_modules - -rm -r ../_static - -rm -r ../_downloads - -rm -r ../_images - cp -r _build/html/* .. - -rm -r ../_themes - -clean: - @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/build/_themes/sphinx_rtd_theme/__init__.py b/docs/build/_themes/sphinx_rtd_theme/__init__.py deleted file mode 100644 index a323a352..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -"""Sphinx ReadTheDocs theme. - -From https://github.com/ryan-roemer/sphinx-bootstrap-theme. - -""" -from os import path - -__version__ = '0.2.5b2' -__version_full__ = __version__ - - -def get_html_theme_path(): - """Return list of HTML theme paths.""" - cur_dir = path.abspath(path.dirname(path.dirname(__file__))) - return cur_dir - -# See http://www.sphinx-doc.org/en/stable/theming.html#distribute-your-theme-as-a-python-package -def setup(app): - app.add_html_theme('sphinx_rtd_theme', path.abspath(path.dirname(__file__))) diff --git a/docs/build/_themes/sphinx_rtd_theme/breadcrumbs.html b/docs/build/_themes/sphinx_rtd_theme/breadcrumbs.html deleted file mode 100644 index 31550d8b..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/breadcrumbs.html +++ /dev/null @@ -1,82 +0,0 @@ -{# Support for Sphinx 1.3+ page_source_suffix, but don't break old builds. #} - -{% if page_source_suffix %} -{% set suffix = page_source_suffix %} -{% else %} -{% set suffix = source_suffix %} -{% endif %} - -{% if meta is defined and meta is not none %} -{% set check_meta = True %} -{% else %} -{% set check_meta = False %} -{% endif %} - -{% if check_meta and 'github_url' in meta %} -{% set display_github = True %} -{% endif %} - -{% if check_meta and 'bitbucket_url' in meta %} -{% set display_bitbucket = True %} -{% endif %} - -{% if check_meta and 'gitlab_url' in meta %} -{% set display_gitlab = True %} -{% endif %} - -
- - - - {% if (theme_prev_next_buttons_location == 'top' or theme_prev_next_buttons_location == 'both') and (next or prev) %} - - {% endif %} -
-
diff --git a/docs/build/_themes/sphinx_rtd_theme/footer.html b/docs/build/_themes/sphinx_rtd_theme/footer.html deleted file mode 100644 index 448d1457..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/footer.html +++ /dev/null @@ -1,52 +0,0 @@ -
- {% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %} - - {% endif %} - -
- -
-

- {%- if show_copyright %} - {%- if hasdoc('copyright') %} - {% trans path=pathto('copyright'), copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} - {%- else %} - {% trans copyright=copyright|e %}© Copyright {{ copyright }}.{% endtrans %} - {%- endif %} - {%- endif %} - - {%- if build_id and build_url %} - {% trans build_url=build_url, build_id=build_id %} - - Build - {{ build_id }}. - - {% endtrans %} - {%- elif commit %} - {% trans commit=commit %} - - Revision {{ commit }}. - - {% endtrans %} - {%- elif last_updated %} - {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} - {%- endif %} - -

-
- - {%- if show_sphinx %} - {% trans %}Built with Sphinx using a theme provided by Read the Docs{% endtrans %}. - {%- endif %} - - {%- block extrafooter %} {% endblock %} - -
- diff --git a/docs/build/_themes/sphinx_rtd_theme/layout.html b/docs/build/_themes/sphinx_rtd_theme/layout.html deleted file mode 100644 index c6e2514c..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/layout.html +++ /dev/null @@ -1,229 +0,0 @@ -{# TEMPLATE VAR SETTINGS #} -{%- set url_root = pathto('', 1) %} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} -{%- if not embedded and docstitle %} - {%- set titlesuffix = " — "|safe + docstitle|e %} -{%- else %} - {%- set titlesuffix = "" %} -{%- endif %} -{%- set lang_attr = 'en' if language == None else (language | replace('_', '-')) %} - - - - - - - {{ metatags }} - - {% block htmltitle %} - {{ title|striptags|e }}{{ titlesuffix }} - {% endblock %} - - {# FAVICON #} - {% if favicon %} - - {% endif %} - {# CANONICAL URL #} - {% if theme_canonical_url %} - - {% endif %} - - {# CSS #} - - {# OPENSEARCH #} - {% if not embedded %} - {% if use_opensearch %} - - {% endif %} - - {% endif %} - - {# RTD hosts this file, so just load on non RTD builds #} - {%- if not READTHEDOCS %} - - {%- endif %} - - {%- for css in css_files %} - {%- if css|attr("rel") %} - - {%- else %} - - {%- endif %} - {%- endfor %} - {%- for cssfile in extra_css_files %} - - {%- endfor %} - - {%- block linktags %} - {%- if hasdoc('about') %} - - {%- endif %} - {%- if hasdoc('genindex') %} - - {%- endif %} - {%- if hasdoc('search') %} - - {%- endif %} - {%- if hasdoc('copyright') %} - - {%- endif %} - {%- if next %} - - {%- endif %} - {%- if prev %} - - {%- endif %} - {%- endblock %} - {%- block extrahead %} {% endblock %} - - {# Keep modernizr in head - http://modernizr.com/docs/#installing #} - - - - - - - {% block extrabody %} {% endblock %} -
- - {# SIDE NAV, TOGGLES ON MOBILE #} - - -
- - {# MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #} - - - -
- {%- block content %} - {% if theme_style_external_links|tobool %} - - -
- -
- {% include "versions.html" %} - - {% if not embedded %} - - - {%- for scriptfile in script_files %} - - {%- endfor %} - - {% endif %} - - {# RTD hosts this file, so just load on non RTD builds #} - {% if not READTHEDOCS %} - - {% endif %} - - - - {%- block footer %} {% endblock %} - - - diff --git a/docs/build/_themes/sphinx_rtd_theme/search.html b/docs/build/_themes/sphinx_rtd_theme/search.html deleted file mode 100644 index e3aa9b5c..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/search.html +++ /dev/null @@ -1,50 +0,0 @@ -{# - basic/search.html - ~~~~~~~~~~~~~~~~~ - - Template for the search page. - - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- extends "layout.html" %} -{% set title = _('Search') %} -{% set script_files = script_files + ['_static/searchtools.js'] %} -{% block footer %} - - {# this is used when loading the search index using $.ajax fails, - such as on Chrome for documents on localhost #} - - {{ super() }} -{% endblock %} -{% block body %} - - - {% if search_performed %} -

{{ _('Search Results') }}

- {% if not search_results %} -

{{ _('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.') }}

- {% endif %} - {% endif %} -
- {% if search_results %} -
    - {% for href, caption, context in search_results %} -
  • - {{ caption }} -

    {{ context|e }}

    -
  • - {% endfor %} -
- {% endif %} -
-{% endblock %} diff --git a/docs/build/_themes/sphinx_rtd_theme/searchbox.html b/docs/build/_themes/sphinx_rtd_theme/searchbox.html deleted file mode 100644 index 606f5c8c..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/searchbox.html +++ /dev/null @@ -1,9 +0,0 @@ -{%- if builder != 'singlehtml' %} -
-
- - - -
-
-{%- endif %} diff --git a/docs/build/_themes/sphinx_rtd_theme/static/css/badge_only.css b/docs/build/_themes/sphinx_rtd_theme/static/css/badge_only.css deleted file mode 100644 index 23602728..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/static/css/badge_only.css +++ /dev/null @@ -1,224 +0,0 @@ -@charset "UTF-8"; -.fa:before { - -webkit-font-smoothing: antialiased; -} - -.clearfix { - *zoom: 1; -} -.clearfix:before, .clearfix:after { - display: table; - content: ""; -} -.clearfix:after { - clear: both; -} - -@font-face { - font-family: FontAwesome; - font-weight: normal; - font-style: normal; - src: url("../fonts/fontawesome-webfont.eot"); - src: url("../fonts/fontawesome-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/fontawesome-webfont.woff") format("woff"), url("../fonts/fontawesome-webfont.ttf") format("truetype"), url("../fonts/fontawesome-webfont.svg#FontAwesome") format("svg"); -} -.fa:before { - display: inline-block; - font-family: FontAwesome; - font-style: normal; - font-weight: normal; - line-height: 1; - text-decoration: inherit; -} - -a .fa { - display: inline-block; - text-decoration: inherit; -} - -li .fa { - display: inline-block; -} -li .fa-large:before, -li .fa-large:before { - /* 1.5 increased font size for fa-large * 1.25 width */ - width: 1.875em; -} - -ul.fas { - list-style-type: none; - margin-left: 2em; - text-indent: -0.8em; -} -ul.fas li .fa { - width: 0.8em; -} -ul.fas li .fa-large:before, -ul.fas li .fa-large:before { - /* 1.5 increased font size for fa-large * 1.25 width */ - vertical-align: baseline; -} - -.fa-book:before { - content: ""; -} - -.icon-book:before { - content: ""; -} - -.fa-caret-down:before { - content: ""; -} - -.icon-caret-down:before { - content: ""; -} - -.fa-caret-up:before { - content: ""; -} - -.icon-caret-up:before { - content: ""; -} - -.fa-caret-left:before { - content: ""; -} - -.icon-caret-left:before { - content: ""; -} - -.fa-caret-right:before { - content: ""; -} - -.icon-caret-right:before { - content: ""; -} - -.rst-versions { - position: fixed; - bottom: 0; - left: 0; - overflow-y: scroll; - width: 300px; - color: #fcfcfc; - background: #1f1d1d; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - z-index: 400; -} -.rst-versions a { - color: #60c557; - text-decoration: none; -} -.rst-versions .rst-badge-small { - display: none; -} -.rst-versions .rst-current-version { - padding: 12px; - background-color: #272525; - display: block; - text-align: right; - font-size: 90%; - cursor: pointer; - color: #84d27d; - *zoom: 1; -} -.rst-versions .rst-current-version:before, .rst-versions .rst-current-version:after { - display: table; - content: ""; -} -.rst-versions .rst-current-version:after { - clear: both; -} -.rst-versions .rst-current-version .fa { - color: #fcfcfc; -} -.rst-versions .rst-current-version .fa-book { - float: left; -} -.rst-versions .rst-current-version .icon-book { - float: left; -} -.rst-versions .rst-current-version.rst-out-of-date { - background-color: #E74C3C; - color: #fff; -} -.rst-versions .rst-current-version.rst-active-old-version { - background-color: #F1C40F; - color: #000; -} -.rst-versions.shift-up { - max-height: 100%; -} -.rst-versions.shift-up .rst-other-versions { - display: block; -} -.rst-versions .rst-other-versions { - font-size: 90%; - padding: 12px; - color: gray; - display: none; -} -.rst-versions .rst-other-versions hr { - display: block; - height: 1px; - border: 0; - margin: 20px 0; - padding: 0; - border-top: solid 1px #413d3d; -} -.rst-versions .rst-other-versions dd { - display: inline-block; - margin: 0; -} -.rst-versions .rst-other-versions dd a { - display: inline-block; - padding: 6px; - color: #fcfcfc; -} -.rst-versions.rst-badge { - width: auto; - bottom: 20px; - right: 20px; - left: auto; - border: none; - max-width: 300px; -} -.rst-versions.rst-badge .icon-book { - float: none; -} -.rst-versions.rst-badge .fa-book { - float: none; -} -.rst-versions.rst-badge.shift-up .rst-current-version { - text-align: right; -} -.rst-versions.rst-badge.shift-up .rst-current-version .fa-book { - float: left; -} -.rst-versions.rst-badge.shift-up .rst-current-version .icon-book { - float: left; -} -.rst-versions.rst-badge .rst-current-version { - width: auto; - height: 30px; - line-height: 30px; - padding: 0 6px; - display: block; - text-align: center; -} - -@media screen and (max-width: 768px) { - .rst-versions { - width: 85%; - display: none; - } - .rst-versions.shift { - display: block; - } -} - -/*# sourceMappingURL=badge_only.css.map */ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/css/badge_only.css.map b/docs/build/_themes/sphinx_rtd_theme/static/css/badge_only.css.map deleted file mode 100644 index 8e6887d0..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/static/css/badge_only.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": "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", -"sources": ["../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/bourbon/dist/css3/_font-face.scss","../../../sass/_theme_badge_fa.sass","../../../sass/_theme_badge.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss"], -"names": [], -"file": "badge_only.css" -} diff --git a/docs/build/_themes/sphinx_rtd_theme/static/css/theme.css b/docs/build/_themes/sphinx_rtd_theme/static/css/theme.css deleted file mode 100644 index 0f5a806a..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/static/css/theme.css +++ /dev/null @@ -1,5778 +0,0 @@ -@charset "UTF-8"; -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -article, aside, details, figcaption, figure, footer, header, hgroup, nav, section { - display: block; -} - -audio, canvas, video { - display: inline-block; - *display: inline; - *zoom: 1; -} - -audio:not([controls]) { - display: none; -} - -[hidden] { - display: none; -} - -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} - -body { - margin: 0; -} - -a:hover, a:active { - outline: 0; -} - -abbr[title] { - border-bottom: 1px dotted; -} - -b, strong { - font-weight: bold; -} - -blockquote { - margin: 0; -} - -dfn { - font-style: italic; -} - -ins { - background: #ff9; - color: #000; - text-decoration: none; -} - -mark { - background: #ff0; - color: #000; - font-style: italic; - font-weight: bold; -} - -pre, code, .rst-content tt, .rst-content code, kbd, samp { - font-family: monospace, serif; - _font-family: "courier new", monospace; - font-size: 1em; -} - -pre { - white-space: pre; -} - -q { - quotes: none; -} - -q:before, q:after { - content: ""; - content: none; -} - -small { - font-size: 85%; -} - -sub, sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sup { - top: -0.5em; -} - -sub { - bottom: -0.25em; -} - -ul, ol, dl { - margin: 0; - padding: 0; - list-style: none; - list-style-image: none; -} - -li { - list-style: none; -} - -dd { - margin: 0; -} - -img { - border: 0; - -ms-interpolation-mode: bicubic; - vertical-align: middle; - max-width: 100%; -} - -svg:not(:root) { - overflow: hidden; -} - -figure { - margin: 0; -} - -form { - margin: 0; -} - -fieldset { - border: 0; - margin: 0; - padding: 0; -} - -label { - cursor: pointer; -} - -legend { - border: 0; - *margin-left: -7px; - padding: 0; - white-space: normal; -} - -button, input, select, textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; -} - -button, input { - line-height: normal; -} - -button, input[type="button"], input[type="reset"], input[type="submit"] { - cursor: pointer; - -webkit-appearance: button; - *overflow: visible; -} - -button[disabled], input[disabled] { - cursor: default; -} - -input[type="checkbox"], input[type="radio"] { - box-sizing: border-box; - padding: 0; - *width: 13px; - *height: 13px; -} - -input[type="search"] { - -webkit-appearance: textfield; - -moz-box-sizing: content-box; - -webkit-box-sizing: content-box; - box-sizing: content-box; -} - -input[type="search"]::-webkit-search-decoration, input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; -} - -textarea { - overflow: auto; - vertical-align: top; - resize: vertical; -} - -table { - border-collapse: collapse; - border-spacing: 0; -} - -td { - vertical-align: top; -} - -.chromeframe { - margin: 0.2em 0; - background: #ccc; - color: black; - padding: 0.2em 0; -} - -.ir { - display: block; - border: 0; - text-indent: -999em; - overflow: hidden; - background-color: transparent; - background-repeat: no-repeat; - text-align: left; - direction: ltr; - *line-height: 0; -} - -.ir br { - display: none; -} - -.hidden { - display: none !important; - visibility: hidden; -} - -.visuallyhidden { - border: 0; - clip: rect(0 0 0 0); - height: 1px; - margin: -1px; - overflow: hidden; - padding: 0; - position: absolute; - width: 1px; -} - -.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { - clip: auto; - height: auto; - margin: 0; - overflow: visible; - position: static; - width: auto; -} - -.invisible { - visibility: hidden; -} - -.relative { - position: relative; -} - -big, small { - font-size: 100%; -} - -@media print { - html, body, section { - background: none !important; - } - - * { - box-shadow: none !important; - text-shadow: none !important; - filter: none !important; - -ms-filter: none !important; - } - - a, a:visited { - text-decoration: underline; - } - - .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { - content: ""; - } - - pre, blockquote { - page-break-inside: avoid; - } - - thead { - display: table-header-group; - } - - tr, img { - page-break-inside: avoid; - } - - img { - max-width: 100% !important; - } - - @page { - margin: 0.5cm; - } - p, h2, .rst-content .toctree-wrapper p.caption, h3 { - orphans: 3; - widows: 3; - } - - h2, .rst-content .toctree-wrapper p.caption, h3 { - page-break-after: avoid; - } -} -.fa:before, .wy-menu-vertical li span.toctree-expand:before, .wy-menu-vertical li.on a span.toctree-expand:before, .wy-menu-vertical li.current > a span.toctree-expand:before, .rst-content .admonition-title:before, .rst-content h1 .headerlink:before, .rst-content h2 .headerlink:before, .rst-content h3 .headerlink:before, .rst-content h4 .headerlink:before, .rst-content h5 .headerlink:before, .rst-content h6 .headerlink:before, .rst-content dl dt .headerlink:before, .rst-content p.caption .headerlink:before, .rst-content table > caption .headerlink:before, .rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before, .icon:before, .wy-dropdown .caret:before, .wy-inline-validate.wy-inline-validate-success .wy-input-context:before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before, .wy-alert, .rst-content .note, .rst-content .attention, .rst-content .caution, .rst-content .danger, .rst-content .error, .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .warning, .rst-content .seealso, .rst-content .admonition-todo, .rst-content .admonition, .btn, input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"], select, textarea, .wy-menu-vertical li.on a, .wy-menu-vertical li.current > a, .wy-side-nav-search > a, .wy-side-nav-search .wy-dropdown > a, .wy-nav-top a { - -webkit-font-smoothing: antialiased; -} - -.clearfix { - *zoom: 1; -} -.clearfix:before, .clearfix:after { - display: table; - content: ""; -} -.clearfix:after { - clear: both; -} - -/*! - * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */ -/* FONT PATH - * -------------------------- */ -@font-face { - font-family: 'FontAwesome'; - src: url("../fonts/fontawesome-webfont.eot?v=4.7.0"); - src: url("../fonts/fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"), url("../fonts/fontawesome-webfont.woff2?v=4.7.0") format("woff2"), url("../fonts/fontawesome-webfont.woff?v=4.7.0") format("woff"), url("../fonts/fontawesome-webfont.ttf?v=4.7.0") format("truetype"), url("../fonts/fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg"); - font-weight: normal; - font-style: normal; -} -.fa, .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand, .rst-content .admonition-title, .rst-content h1 .headerlink, .rst-content h2 .headerlink, .rst-content h3 .headerlink, .rst-content h4 .headerlink, .rst-content h5 .headerlink, .rst-content h6 .headerlink, .rst-content dl dt .headerlink, .rst-content p.caption .headerlink, .rst-content table > caption .headerlink, .rst-content tt.download span:first-child, .rst-content code.download span:first-child, .icon { - display: inline-block; - font: normal normal normal 14px/1 FontAwesome; - font-size: inherit; - text-rendering: auto; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/* makes the font 33% larger relative to the icon container */ -.fa-lg { - font-size: 1.3333333333em; - line-height: 0.75em; - vertical-align: -15%; -} - -.fa-2x { - font-size: 2em; -} - -.fa-3x { - font-size: 3em; -} - -.fa-4x { - font-size: 4em; -} - -.fa-5x { - font-size: 5em; -} - -.fa-fw { - width: 1.2857142857em; - text-align: center; -} - -.fa-ul { - padding-left: 0; - margin-left: 2.1428571429em; - list-style-type: none; -} -.fa-ul > li { - position: relative; -} - -.fa-li { - position: absolute; - left: -2.1428571429em; - width: 2.1428571429em; - top: 0.1428571429em; - text-align: center; -} -.fa-li.fa-lg { - left: -1.8571428571em; -} - -.fa-border { - padding: .2em .25em .15em; - border: solid 0.08em #eee; - border-radius: .1em; -} - -.fa-pull-left { - float: left; -} - -.fa-pull-right { - float: right; -} - -.fa.fa-pull-left, .wy-menu-vertical li span.fa-pull-left.toctree-expand, .wy-menu-vertical li.on a span.fa-pull-left.toctree-expand, .wy-menu-vertical li.current > a span.fa-pull-left.toctree-expand, .rst-content .fa-pull-left.admonition-title, .rst-content h1 .fa-pull-left.headerlink, .rst-content h2 .fa-pull-left.headerlink, .rst-content h3 .fa-pull-left.headerlink, .rst-content h4 .fa-pull-left.headerlink, .rst-content h5 .fa-pull-left.headerlink, .rst-content h6 .fa-pull-left.headerlink, .rst-content dl dt .fa-pull-left.headerlink, .rst-content p.caption .fa-pull-left.headerlink, .rst-content table > caption .fa-pull-left.headerlink, .rst-content tt.download span.fa-pull-left:first-child, .rst-content code.download span.fa-pull-left:first-child, .fa-pull-left.icon { - margin-right: .3em; -} -.fa.fa-pull-right, .wy-menu-vertical li span.fa-pull-right.toctree-expand, .wy-menu-vertical li.on a span.fa-pull-right.toctree-expand, .wy-menu-vertical li.current > a span.fa-pull-right.toctree-expand, .rst-content .fa-pull-right.admonition-title, .rst-content h1 .fa-pull-right.headerlink, .rst-content h2 .fa-pull-right.headerlink, .rst-content h3 .fa-pull-right.headerlink, .rst-content h4 .fa-pull-right.headerlink, .rst-content h5 .fa-pull-right.headerlink, .rst-content h6 .fa-pull-right.headerlink, .rst-content dl dt .fa-pull-right.headerlink, .rst-content p.caption .fa-pull-right.headerlink, .rst-content table > caption .fa-pull-right.headerlink, .rst-content tt.download span.fa-pull-right:first-child, .rst-content code.download span.fa-pull-right:first-child, .fa-pull-right.icon { - margin-left: .3em; -} - -/* Deprecated as of 4.4.0 */ -.pull-right { - float: right; -} - -.pull-left { - float: left; -} - -.fa.pull-left, .wy-menu-vertical li span.pull-left.toctree-expand, .wy-menu-vertical li.on a span.pull-left.toctree-expand, .wy-menu-vertical li.current > a span.pull-left.toctree-expand, .rst-content .pull-left.admonition-title, .rst-content h1 .pull-left.headerlink, .rst-content h2 .pull-left.headerlink, .rst-content h3 .pull-left.headerlink, .rst-content h4 .pull-left.headerlink, .rst-content h5 .pull-left.headerlink, .rst-content h6 .pull-left.headerlink, .rst-content dl dt .pull-left.headerlink, .rst-content p.caption .pull-left.headerlink, .rst-content table > caption .pull-left.headerlink, .rst-content tt.download span.pull-left:first-child, .rst-content code.download span.pull-left:first-child, .pull-left.icon { - margin-right: .3em; -} -.fa.pull-right, .wy-menu-vertical li span.pull-right.toctree-expand, .wy-menu-vertical li.on a span.pull-right.toctree-expand, .wy-menu-vertical li.current > a span.pull-right.toctree-expand, .rst-content .pull-right.admonition-title, .rst-content h1 .pull-right.headerlink, .rst-content h2 .pull-right.headerlink, .rst-content h3 .pull-right.headerlink, .rst-content h4 .pull-right.headerlink, .rst-content h5 .pull-right.headerlink, .rst-content h6 .pull-right.headerlink, .rst-content dl dt .pull-right.headerlink, .rst-content p.caption .pull-right.headerlink, .rst-content table > caption .pull-right.headerlink, .rst-content tt.download span.pull-right:first-child, .rst-content code.download span.pull-right:first-child, .pull-right.icon { - margin-left: .3em; -} - -.fa-spin { - -webkit-animation: fa-spin 2s infinite linear; - animation: fa-spin 2s infinite linear; -} - -.fa-pulse { - -webkit-animation: fa-spin 1s infinite steps(8); - animation: fa-spin 1s infinite steps(8); -} - -@-webkit-keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -@keyframes fa-spin { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(359deg); - transform: rotate(359deg); - } -} -.fa-rotate-90 { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; - -webkit-transform: rotate(90deg); - -ms-transform: rotate(90deg); - transform: rotate(90deg); -} - -.fa-rotate-180 { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; - -webkit-transform: rotate(180deg); - -ms-transform: rotate(180deg); - transform: rotate(180deg); -} - -.fa-rotate-270 { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; - -webkit-transform: rotate(270deg); - -ms-transform: rotate(270deg); - transform: rotate(270deg); -} - -.fa-flip-horizontal { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; - -webkit-transform: scale(-1, 1); - -ms-transform: scale(-1, 1); - transform: scale(-1, 1); -} - -.fa-flip-vertical { - -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; - -webkit-transform: scale(1, -1); - -ms-transform: scale(1, -1); - transform: scale(1, -1); -} - -:root .fa-rotate-90, -:root .fa-rotate-180, -:root .fa-rotate-270, -:root .fa-flip-horizontal, -:root .fa-flip-vertical { - filter: none; -} - -.fa-stack { - position: relative; - display: inline-block; - width: 2em; - height: 2em; - line-height: 2em; - vertical-align: middle; -} - -.fa-stack-1x, .fa-stack-2x { - position: absolute; - left: 0; - width: 100%; - text-align: center; -} - -.fa-stack-1x { - line-height: inherit; -} - -.fa-stack-2x { - font-size: 2em; -} - -.fa-inverse { - color: #fff; -} - -/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen - readers do not read off random characters that represent icons */ -.fa-glass:before { - content: ""; -} - -.fa-music:before { - content: ""; -} - -.fa-search:before, .icon-search:before { - content: ""; -} - -.fa-envelope-o:before { - content: ""; -} - -.fa-heart:before { - content: ""; -} - -.fa-star:before { - content: ""; -} - -.fa-star-o:before { - content: ""; -} - -.fa-user:before { - content: ""; -} - -.fa-film:before { - content: ""; -} - -.fa-th-large:before { - content: ""; -} - -.fa-th:before { - content: ""; -} - -.fa-th-list:before { - content: ""; -} - -.fa-check:before { - content: ""; -} - -.fa-remove:before, -.fa-close:before, -.fa-times:before { - content: ""; -} - -.fa-search-plus:before { - content: ""; -} - -.fa-search-minus:before { - content: ""; -} - -.fa-power-off:before { - content: ""; -} - -.fa-signal:before { - content: ""; -} - -.fa-gear:before, -.fa-cog:before { - content: ""; -} - -.fa-trash-o:before { - content: ""; -} - -.fa-home:before, .icon-home:before { - content: ""; -} - -.fa-file-o:before { - content: ""; -} - -.fa-clock-o:before { - content: ""; -} - -.fa-road:before { - content: ""; -} - -.fa-download:before, .rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before { - content: ""; -} - -.fa-arrow-circle-o-down:before { - content: ""; -} - -.fa-arrow-circle-o-up:before { - content: ""; -} - -.fa-inbox:before { - content: ""; -} - -.fa-play-circle-o:before { - content: ""; -} - -.fa-rotate-right:before, -.fa-repeat:before { - content: ""; -} - -.fa-refresh:before { - content: ""; -} - -.fa-list-alt:before { - content: ""; -} - -.fa-lock:before { - content: ""; -} - -.fa-flag:before { - content: ""; -} - -.fa-headphones:before { - content: ""; -} - -.fa-volume-off:before { - content: ""; -} - -.fa-volume-down:before { - content: ""; -} - -.fa-volume-up:before { - content: ""; -} - -.fa-qrcode:before { - content: ""; -} - -.fa-barcode:before { - content: ""; -} - -.fa-tag:before { - content: ""; -} - -.fa-tags:before { - content: ""; -} - -.fa-book:before, .icon-book:before { - content: ""; -} - -.fa-bookmark:before { - content: ""; -} - -.fa-print:before { - content: ""; -} - -.fa-camera:before { - content: ""; -} - -.fa-font:before { - content: ""; -} - -.fa-bold:before { - content: ""; -} - -.fa-italic:before { - content: ""; -} - -.fa-text-height:before { - content: ""; -} - -.fa-text-width:before { - content: ""; -} - -.fa-align-left:before { - content: ""; -} - -.fa-align-center:before { - content: ""; -} - -.fa-align-right:before { - content: ""; -} - -.fa-align-justify:before { - content: ""; -} - -.fa-list:before { - content: ""; -} - -.fa-dedent:before, -.fa-outdent:before { - content: ""; -} - -.fa-indent:before { - content: ""; -} - -.fa-video-camera:before { - content: ""; -} - -.fa-photo:before, -.fa-image:before, -.fa-picture-o:before { - content: ""; -} - -.fa-pencil:before { - content: ""; -} - -.fa-map-marker:before { - content: ""; -} - -.fa-adjust:before { - content: ""; -} - -.fa-tint:before { - content: ""; -} - -.fa-edit:before, -.fa-pencil-square-o:before { - content: ""; -} - -.fa-share-square-o:before { - content: ""; -} - -.fa-check-square-o:before { - content: ""; -} - -.fa-arrows:before { - content: ""; -} - -.fa-step-backward:before { - content: ""; -} - -.fa-fast-backward:before { - content: ""; -} - -.fa-backward:before { - content: ""; -} - -.fa-play:before { - content: ""; -} - -.fa-pause:before { - content: ""; -} - -.fa-stop:before { - content: ""; -} - -.fa-forward:before { - content: ""; -} - -.fa-fast-forward:before { - content: ""; -} - -.fa-step-forward:before { - content: ""; -} - -.fa-eject:before { - content: ""; -} - -.fa-chevron-left:before { - content: ""; -} - -.fa-chevron-right:before { - content: ""; -} - -.fa-plus-circle:before { - content: ""; -} - -.fa-minus-circle:before { - content: ""; -} - -.fa-times-circle:before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before { - content: ""; -} - -.fa-check-circle:before, .wy-inline-validate.wy-inline-validate-success .wy-input-context:before { - content: ""; -} - -.fa-question-circle:before { - content: ""; -} - -.fa-info-circle:before { - content: ""; -} - -.fa-crosshairs:before { - content: ""; -} - -.fa-times-circle-o:before { - content: ""; -} - -.fa-check-circle-o:before { - content: ""; -} - -.fa-ban:before { - content: ""; -} - -.fa-arrow-left:before { - content: ""; -} - -.fa-arrow-right:before { - content: ""; -} - -.fa-arrow-up:before { - content: ""; -} - -.fa-arrow-down:before { - content: ""; -} - -.fa-mail-forward:before, -.fa-share:before { - content: ""; -} - -.fa-expand:before { - content: ""; -} - -.fa-compress:before { - content: ""; -} - -.fa-plus:before { - content: ""; -} - -.fa-minus:before { - content: ""; -} - -.fa-asterisk:before { - content: ""; -} - -.fa-exclamation-circle:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before, .rst-content .admonition-title:before { - content: ""; -} - -.fa-gift:before { - content: ""; -} - -.fa-leaf:before { - content: ""; -} - -.fa-fire:before, .icon-fire:before { - content: ""; -} - -.fa-eye:before { - content: ""; -} - -.fa-eye-slash:before { - content: ""; -} - -.fa-warning:before, -.fa-exclamation-triangle:before { - content: ""; -} - -.fa-plane:before { - content: ""; -} - -.fa-calendar:before { - content: ""; -} - -.fa-random:before { - content: ""; -} - -.fa-comment:before { - content: ""; -} - -.fa-magnet:before { - content: ""; -} - -.fa-chevron-up:before { - content: ""; -} - -.fa-chevron-down:before { - content: ""; -} - -.fa-retweet:before { - content: ""; -} - -.fa-shopping-cart:before { - content: ""; -} - -.fa-folder:before { - content: ""; -} - -.fa-folder-open:before { - content: ""; -} - -.fa-arrows-v:before { - content: ""; -} - -.fa-arrows-h:before { - content: ""; -} - -.fa-bar-chart-o:before, -.fa-bar-chart:before { - content: ""; -} - -.fa-twitter-square:before { - content: ""; -} - -.fa-facebook-square:before { - content: ""; -} - -.fa-camera-retro:before { - content: ""; -} - -.fa-key:before { - content: ""; -} - -.fa-gears:before, -.fa-cogs:before { - content: ""; -} - -.fa-comments:before { - content: ""; -} - -.fa-thumbs-o-up:before { - content: ""; -} - -.fa-thumbs-o-down:before { - content: ""; -} - -.fa-star-half:before { - content: ""; -} - -.fa-heart-o:before { - content: ""; -} - -.fa-sign-out:before { - content: ""; -} - -.fa-linkedin-square:before { - content: ""; -} - -.fa-thumb-tack:before { - content: ""; -} - -.fa-external-link:before { - content: ""; -} - -.fa-sign-in:before { - content: ""; -} - -.fa-trophy:before { - content: ""; -} - -.fa-github-square:before { - content: ""; -} - -.fa-upload:before { - content: ""; -} - -.fa-lemon-o:before { - content: ""; -} - -.fa-phone:before { - content: ""; -} - -.fa-square-o:before { - content: ""; -} - -.fa-bookmark-o:before { - content: ""; -} - -.fa-phone-square:before { - content: ""; -} - -.fa-twitter:before { - content: ""; -} - -.fa-facebook-f:before, -.fa-facebook:before { - content: ""; -} - -.fa-github:before, .icon-github:before { - content: ""; -} - -.fa-unlock:before { - content: ""; -} - -.fa-credit-card:before { - content: ""; -} - -.fa-feed:before, -.fa-rss:before { - content: ""; -} - -.fa-hdd-o:before { - content: ""; -} - -.fa-bullhorn:before { - content: ""; -} - -.fa-bell:before { - content: ""; -} - -.fa-certificate:before { - content: ""; -} - -.fa-hand-o-right:before { - content: ""; -} - -.fa-hand-o-left:before { - content: ""; -} - -.fa-hand-o-up:before { - content: ""; -} - -.fa-hand-o-down:before { - content: ""; -} - -.fa-arrow-circle-left:before, .icon-circle-arrow-left:before { - content: ""; -} - -.fa-arrow-circle-right:before, .icon-circle-arrow-right:before { - content: ""; -} - -.fa-arrow-circle-up:before { - content: ""; -} - -.fa-arrow-circle-down:before { - content: ""; -} - -.fa-globe:before { - content: ""; -} - -.fa-wrench:before { - content: ""; -} - -.fa-tasks:before { - content: ""; -} - -.fa-filter:before { - content: ""; -} - -.fa-briefcase:before { - content: ""; -} - -.fa-arrows-alt:before { - content: ""; -} - -.fa-group:before, -.fa-users:before { - content: ""; -} - -.fa-chain:before, -.fa-link:before, -.icon-link:before { - content: ""; -} - -.fa-cloud:before { - content: ""; -} - -.fa-flask:before { - content: ""; -} - -.fa-cut:before, -.fa-scissors:before { - content: ""; -} - -.fa-copy:before, -.fa-files-o:before { - content: ""; -} - -.fa-paperclip:before { - content: ""; -} - -.fa-save:before, -.fa-floppy-o:before { - content: ""; -} - -.fa-square:before { - content: ""; -} - -.fa-navicon:before, -.fa-reorder:before, -.fa-bars:before { - content: ""; -} - -.fa-list-ul:before { - content: ""; -} - -.fa-list-ol:before { - content: ""; -} - -.fa-strikethrough:before { - content: ""; -} - -.fa-underline:before { - content: ""; -} - -.fa-table:before { - content: ""; -} - -.fa-magic:before { - content: ""; -} - -.fa-truck:before { - content: ""; -} - -.fa-pinterest:before { - content: ""; -} - -.fa-pinterest-square:before { - content: ""; -} - -.fa-google-plus-square:before { - content: ""; -} - -.fa-google-plus:before { - content: ""; -} - -.fa-money:before { - content: ""; -} - -.fa-caret-down:before, .wy-dropdown .caret:before, .icon-caret-down:before { - content: ""; -} - -.fa-caret-up:before { - content: ""; -} - -.fa-caret-left:before { - content: ""; -} - -.fa-caret-right:before { - content: ""; -} - -.fa-columns:before { - content: ""; -} - -.fa-unsorted:before, -.fa-sort:before { - content: ""; -} - -.fa-sort-down:before, -.fa-sort-desc:before { - content: ""; -} - -.fa-sort-up:before, -.fa-sort-asc:before { - content: ""; -} - -.fa-envelope:before { - content: ""; -} - -.fa-linkedin:before { - content: ""; -} - -.fa-rotate-left:before, -.fa-undo:before { - content: ""; -} - -.fa-legal:before, -.fa-gavel:before { - content: ""; -} - -.fa-dashboard:before, -.fa-tachometer:before { - content: ""; -} - -.fa-comment-o:before { - content: ""; -} - -.fa-comments-o:before { - content: ""; -} - -.fa-flash:before, -.fa-bolt:before { - content: ""; -} - -.fa-sitemap:before { - content: ""; -} - -.fa-umbrella:before { - content: ""; -} - -.fa-paste:before, -.fa-clipboard:before { - content: ""; -} - -.fa-lightbulb-o:before { - content: ""; -} - -.fa-exchange:before { - content: ""; -} - -.fa-cloud-download:before { - content: ""; -} - -.fa-cloud-upload:before { - content: ""; -} - -.fa-user-md:before { - content: ""; -} - -.fa-stethoscope:before { - content: ""; -} - -.fa-suitcase:before { - content: ""; -} - -.fa-bell-o:before { - content: ""; -} - -.fa-coffee:before { - content: ""; -} - -.fa-cutlery:before { - content: ""; -} - -.fa-file-text-o:before { - content: ""; -} - -.fa-building-o:before { - content: ""; -} - -.fa-hospital-o:before { - content: ""; -} - -.fa-ambulance:before { - content: ""; -} - -.fa-medkit:before { - content: ""; -} - -.fa-fighter-jet:before { - content: ""; -} - -.fa-beer:before { - content: ""; -} - -.fa-h-square:before { - content: ""; -} - -.fa-plus-square:before { - content: ""; -} - -.fa-angle-double-left:before { - content: ""; -} - -.fa-angle-double-right:before { - content: ""; -} - -.fa-angle-double-up:before { - content: ""; -} - -.fa-angle-double-down:before { - content: ""; -} - -.fa-angle-left:before { - content: ""; -} - -.fa-angle-right:before { - content: ""; -} - -.fa-angle-up:before { - content: ""; -} - -.fa-angle-down:before { - content: ""; -} - -.fa-desktop:before { - content: ""; -} - -.fa-laptop:before { - content: ""; -} - -.fa-tablet:before { - content: ""; -} - -.fa-mobile-phone:before, -.fa-mobile:before { - content: ""; -} - -.fa-circle-o:before { - content: ""; -} - -.fa-quote-left:before { - content: ""; -} - -.fa-quote-right:before { - content: ""; -} - -.fa-spinner:before { - content: ""; -} - -.fa-circle:before { - content: ""; -} - -.fa-mail-reply:before, -.fa-reply:before { - content: ""; -} - -.fa-github-alt:before { - content: ""; -} - -.fa-folder-o:before { - content: ""; -} - -.fa-folder-open-o:before { - content: ""; -} - -.fa-smile-o:before { - content: ""; -} - -.fa-frown-o:before { - content: ""; -} - -.fa-meh-o:before { - content: ""; -} - -.fa-gamepad:before { - content: ""; -} - -.fa-keyboard-o:before { - content: ""; -} - -.fa-flag-o:before { - content: ""; -} - -.fa-flag-checkered:before { - content: ""; -} - -.fa-terminal:before { - content: ""; -} - -.fa-code:before { - content: ""; -} - -.fa-mail-reply-all:before, -.fa-reply-all:before { - content: ""; -} - -.fa-star-half-empty:before, -.fa-star-half-full:before, -.fa-star-half-o:before { - content: ""; -} - -.fa-location-arrow:before { - content: ""; -} - -.fa-crop:before { - content: ""; -} - -.fa-code-fork:before { - content: ""; -} - -.fa-unlink:before, -.fa-chain-broken:before { - content: ""; -} - -.fa-question:before { - content: ""; -} - -.fa-info:before { - content: ""; -} - -.fa-exclamation:before { - content: ""; -} - -.fa-superscript:before { - content: ""; -} - -.fa-subscript:before { - content: ""; -} - -.fa-eraser:before { - content: ""; -} - -.fa-puzzle-piece:before { - content: ""; -} - -.fa-microphone:before { - content: ""; -} - -.fa-microphone-slash:before { - content: ""; -} - -.fa-shield:before { - content: ""; -} - -.fa-calendar-o:before { - content: ""; -} - -.fa-fire-extinguisher:before { - content: ""; -} - -.fa-rocket:before { - content: ""; -} - -.fa-maxcdn:before { - content: ""; -} - -.fa-chevron-circle-left:before { - content: ""; -} - -.fa-chevron-circle-right:before { - content: ""; -} - -.fa-chevron-circle-up:before { - content: ""; -} - -.fa-chevron-circle-down:before { - content: ""; -} - -.fa-html5:before { - content: ""; -} - -.fa-css3:before { - content: ""; -} - -.fa-anchor:before { - content: ""; -} - -.fa-unlock-alt:before { - content: ""; -} - -.fa-bullseye:before { - content: ""; -} - -.fa-ellipsis-h:before { - content: ""; -} - -.fa-ellipsis-v:before { - content: ""; -} - -.fa-rss-square:before { - content: ""; -} - -.fa-play-circle:before { - content: ""; -} - -.fa-ticket:before { - content: ""; -} - -.fa-minus-square:before { - content: ""; -} - -.fa-minus-square-o:before, .wy-menu-vertical li.on a span.toctree-expand:before, .wy-menu-vertical li.current > a span.toctree-expand:before { - content: ""; -} - -.fa-level-up:before { - content: ""; -} - -.fa-level-down:before { - content: ""; -} - -.fa-check-square:before { - content: ""; -} - -.fa-pencil-square:before { - content: ""; -} - -.fa-external-link-square:before { - content: ""; -} - -.fa-share-square:before { - content: ""; -} - -.fa-compass:before { - content: ""; -} - -.fa-toggle-down:before, -.fa-caret-square-o-down:before { - content: ""; -} - -.fa-toggle-up:before, -.fa-caret-square-o-up:before { - content: ""; -} - -.fa-toggle-right:before, -.fa-caret-square-o-right:before { - content: ""; -} - -.fa-euro:before, -.fa-eur:before { - content: ""; -} - -.fa-gbp:before { - content: ""; -} - -.fa-dollar:before, -.fa-usd:before { - content: ""; -} - -.fa-rupee:before, -.fa-inr:before { - content: ""; -} - -.fa-cny:before, -.fa-rmb:before, -.fa-yen:before, -.fa-jpy:before { - content: ""; -} - -.fa-ruble:before, -.fa-rouble:before, -.fa-rub:before { - content: ""; -} - -.fa-won:before, -.fa-krw:before { - content: ""; -} - -.fa-bitcoin:before, -.fa-btc:before { - content: ""; -} - -.fa-file:before { - content: ""; -} - -.fa-file-text:before { - content: ""; -} - -.fa-sort-alpha-asc:before { - content: ""; -} - -.fa-sort-alpha-desc:before { - content: ""; -} - -.fa-sort-amount-asc:before { - content: ""; -} - -.fa-sort-amount-desc:before { - content: ""; -} - -.fa-sort-numeric-asc:before { - content: ""; -} - -.fa-sort-numeric-desc:before { - content: ""; -} - -.fa-thumbs-up:before { - content: ""; -} - -.fa-thumbs-down:before { - content: ""; -} - -.fa-youtube-square:before { - content: ""; -} - -.fa-youtube:before { - content: ""; -} - -.fa-xing:before { - content: ""; -} - -.fa-xing-square:before { - content: ""; -} - -.fa-youtube-play:before { - content: ""; -} - -.fa-dropbox:before { - content: ""; -} - -.fa-stack-overflow:before { - content: ""; -} - -.fa-instagram:before { - content: ""; -} - -.fa-flickr:before { - content: ""; -} - -.fa-adn:before { - content: ""; -} - -.fa-bitbucket:before, .icon-bitbucket:before { - content: ""; -} - -.fa-bitbucket-square:before { - content: ""; -} - -.fa-tumblr:before { - content: ""; -} - -.fa-tumblr-square:before { - content: ""; -} - -.fa-long-arrow-down:before { - content: ""; -} - -.fa-long-arrow-up:before { - content: ""; -} - -.fa-long-arrow-left:before { - content: ""; -} - -.fa-long-arrow-right:before { - content: ""; -} - -.fa-apple:before { - content: ""; -} - -.fa-windows:before { - content: ""; -} - -.fa-android:before { - content: ""; -} - -.fa-linux:before { - content: ""; -} - -.fa-dribbble:before { - content: ""; -} - -.fa-skype:before { - content: ""; -} - -.fa-foursquare:before { - content: ""; -} - -.fa-trello:before { - content: ""; -} - -.fa-female:before { - content: ""; -} - -.fa-male:before { - content: ""; -} - -.fa-gittip:before, -.fa-gratipay:before { - content: ""; -} - -.fa-sun-o:before { - content: ""; -} - -.fa-moon-o:before { - content: ""; -} - -.fa-archive:before { - content: ""; -} - -.fa-bug:before { - content: ""; -} - -.fa-vk:before { - content: ""; -} - -.fa-weibo:before { - content: ""; -} - -.fa-renren:before { - content: ""; -} - -.fa-pagelines:before { - content: ""; -} - -.fa-stack-exchange:before { - content: ""; -} - -.fa-arrow-circle-o-right:before { - content: ""; -} - -.fa-arrow-circle-o-left:before { - content: ""; -} - -.fa-toggle-left:before, -.fa-caret-square-o-left:before { - content: ""; -} - -.fa-dot-circle-o:before { - content: ""; -} - -.fa-wheelchair:before { - content: ""; -} - -.fa-vimeo-square:before { - content: ""; -} - -.fa-turkish-lira:before, -.fa-try:before { - content: ""; -} - -.fa-plus-square-o:before, .wy-menu-vertical li span.toctree-expand:before { - content: ""; -} - -.fa-space-shuttle:before { - content: ""; -} - -.fa-slack:before { - content: ""; -} - -.fa-envelope-square:before { - content: ""; -} - -.fa-wordpress:before { - content: ""; -} - -.fa-openid:before { - content: ""; -} - -.fa-institution:before, -.fa-bank:before, -.fa-university:before { - content: ""; -} - -.fa-mortar-board:before, -.fa-graduation-cap:before { - content: ""; -} - -.fa-yahoo:before { - content: ""; -} - -.fa-google:before { - content: ""; -} - -.fa-reddit:before { - content: ""; -} - -.fa-reddit-square:before { - content: ""; -} - -.fa-stumbleupon-circle:before { - content: ""; -} - -.fa-stumbleupon:before { - content: ""; -} - -.fa-delicious:before { - content: ""; -} - -.fa-digg:before { - content: ""; -} - -.fa-pied-piper-pp:before { - content: ""; -} - -.fa-pied-piper-alt:before { - content: ""; -} - -.fa-drupal:before { - content: ""; -} - -.fa-joomla:before { - content: ""; -} - -.fa-language:before { - content: ""; -} - -.fa-fax:before { - content: ""; -} - -.fa-building:before { - content: ""; -} - -.fa-child:before { - content: ""; -} - -.fa-paw:before { - content: ""; -} - -.fa-spoon:before { - content: ""; -} - -.fa-cube:before { - content: ""; -} - -.fa-cubes:before { - content: ""; -} - -.fa-behance:before { - content: ""; -} - -.fa-behance-square:before { - content: ""; -} - -.fa-steam:before { - content: ""; -} - -.fa-steam-square:before { - content: ""; -} - -.fa-recycle:before { - content: ""; -} - -.fa-automobile:before, -.fa-car:before { - content: ""; -} - -.fa-cab:before, -.fa-taxi:before { - content: ""; -} - -.fa-tree:before { - content: ""; -} - -.fa-spotify:before { - content: ""; -} - -.fa-deviantart:before { - content: ""; -} - -.fa-soundcloud:before { - content: ""; -} - -.fa-database:before { - content: ""; -} - -.fa-file-pdf-o:before { - content: ""; -} - -.fa-file-word-o:before { - content: ""; -} - -.fa-file-excel-o:before { - content: ""; -} - -.fa-file-powerpoint-o:before { - content: ""; -} - -.fa-file-photo-o:before, -.fa-file-picture-o:before, -.fa-file-image-o:before { - content: ""; -} - -.fa-file-zip-o:before, -.fa-file-archive-o:before { - content: ""; -} - -.fa-file-sound-o:before, -.fa-file-audio-o:before { - content: ""; -} - -.fa-file-movie-o:before, -.fa-file-video-o:before { - content: ""; -} - -.fa-file-code-o:before { - content: ""; -} - -.fa-vine:before { - content: ""; -} - -.fa-codepen:before { - content: ""; -} - -.fa-jsfiddle:before { - content: ""; -} - -.fa-life-bouy:before, -.fa-life-buoy:before, -.fa-life-saver:before, -.fa-support:before, -.fa-life-ring:before { - content: ""; -} - -.fa-circle-o-notch:before { - content: ""; -} - -.fa-ra:before, -.fa-resistance:before, -.fa-rebel:before { - content: ""; -} - -.fa-ge:before, -.fa-empire:before { - content: ""; -} - -.fa-git-square:before { - content: ""; -} - -.fa-git:before { - content: ""; -} - -.fa-y-combinator-square:before, -.fa-yc-square:before, -.fa-hacker-news:before { - content: ""; -} - -.fa-tencent-weibo:before { - content: ""; -} - -.fa-qq:before { - content: ""; -} - -.fa-wechat:before, -.fa-weixin:before { - content: ""; -} - -.fa-send:before, -.fa-paper-plane:before { - content: ""; -} - -.fa-send-o:before, -.fa-paper-plane-o:before { - content: ""; -} - -.fa-history:before { - content: ""; -} - -.fa-circle-thin:before { - content: ""; -} - -.fa-header:before { - content: ""; -} - -.fa-paragraph:before { - content: ""; -} - -.fa-sliders:before { - content: ""; -} - -.fa-share-alt:before { - content: ""; -} - -.fa-share-alt-square:before { - content: ""; -} - -.fa-bomb:before { - content: ""; -} - -.fa-soccer-ball-o:before, -.fa-futbol-o:before { - content: ""; -} - -.fa-tty:before { - content: ""; -} - -.fa-binoculars:before { - content: ""; -} - -.fa-plug:before { - content: ""; -} - -.fa-slideshare:before { - content: ""; -} - -.fa-twitch:before { - content: ""; -} - -.fa-yelp:before { - content: ""; -} - -.fa-newspaper-o:before { - content: ""; -} - -.fa-wifi:before { - content: ""; -} - -.fa-calculator:before { - content: ""; -} - -.fa-paypal:before { - content: ""; -} - -.fa-google-wallet:before { - content: ""; -} - -.fa-cc-visa:before { - content: ""; -} - -.fa-cc-mastercard:before { - content: ""; -} - -.fa-cc-discover:before { - content: ""; -} - -.fa-cc-amex:before { - content: ""; -} - -.fa-cc-paypal:before { - content: ""; -} - -.fa-cc-stripe:before { - content: ""; -} - -.fa-bell-slash:before { - content: ""; -} - -.fa-bell-slash-o:before { - content: ""; -} - -.fa-trash:before { - content: ""; -} - -.fa-copyright:before { - content: ""; -} - -.fa-at:before { - content: ""; -} - -.fa-eyedropper:before { - content: ""; -} - -.fa-paint-brush:before { - content: ""; -} - -.fa-birthday-cake:before { - content: ""; -} - -.fa-area-chart:before { - content: ""; -} - -.fa-pie-chart:before { - content: ""; -} - -.fa-line-chart:before { - content: ""; -} - -.fa-lastfm:before { - content: ""; -} - -.fa-lastfm-square:before { - content: ""; -} - -.fa-toggle-off:before { - content: ""; -} - -.fa-toggle-on:before { - content: ""; -} - -.fa-bicycle:before { - content: ""; -} - -.fa-bus:before { - content: ""; -} - -.fa-ioxhost:before { - content: ""; -} - -.fa-angellist:before { - content: ""; -} - -.fa-cc:before { - content: ""; -} - -.fa-shekel:before, -.fa-sheqel:before, -.fa-ils:before { - content: ""; -} - -.fa-meanpath:before { - content: ""; -} - -.fa-buysellads:before { - content: ""; -} - -.fa-connectdevelop:before { - content: ""; -} - -.fa-dashcube:before { - content: ""; -} - -.fa-forumbee:before { - content: ""; -} - -.fa-leanpub:before { - content: ""; -} - -.fa-sellsy:before { - content: ""; -} - -.fa-shirtsinbulk:before { - content: ""; -} - -.fa-simplybuilt:before { - content: ""; -} - -.fa-skyatlas:before { - content: ""; -} - -.fa-cart-plus:before { - content: ""; -} - -.fa-cart-arrow-down:before { - content: ""; -} - -.fa-diamond:before { - content: ""; -} - -.fa-ship:before { - content: ""; -} - -.fa-user-secret:before { - content: ""; -} - -.fa-motorcycle:before { - content: ""; -} - -.fa-street-view:before { - content: ""; -} - -.fa-heartbeat:before { - content: ""; -} - -.fa-venus:before { - content: ""; -} - -.fa-mars:before { - content: ""; -} - -.fa-mercury:before { - content: ""; -} - -.fa-intersex:before, -.fa-transgender:before { - content: ""; -} - -.fa-transgender-alt:before { - content: ""; -} - -.fa-venus-double:before { - content: ""; -} - -.fa-mars-double:before { - content: ""; -} - -.fa-venus-mars:before { - content: ""; -} - -.fa-mars-stroke:before { - content: ""; -} - -.fa-mars-stroke-v:before { - content: ""; -} - -.fa-mars-stroke-h:before { - content: ""; -} - -.fa-neuter:before { - content: ""; -} - -.fa-genderless:before { - content: ""; -} - -.fa-facebook-official:before { - content: ""; -} - -.fa-pinterest-p:before { - content: ""; -} - -.fa-whatsapp:before { - content: ""; -} - -.fa-server:before { - content: ""; -} - -.fa-user-plus:before { - content: ""; -} - -.fa-user-times:before { - content: ""; -} - -.fa-hotel:before, -.fa-bed:before { - content: ""; -} - -.fa-viacoin:before { - content: ""; -} - -.fa-train:before { - content: ""; -} - -.fa-subway:before { - content: ""; -} - -.fa-medium:before { - content: ""; -} - -.fa-yc:before, -.fa-y-combinator:before { - content: ""; -} - -.fa-optin-monster:before { - content: ""; -} - -.fa-opencart:before { - content: ""; -} - -.fa-expeditedssl:before { - content: ""; -} - -.fa-battery-4:before, -.fa-battery:before, -.fa-battery-full:before { - content: ""; -} - -.fa-battery-3:before, -.fa-battery-three-quarters:before { - content: ""; -} - -.fa-battery-2:before, -.fa-battery-half:before { - content: ""; -} - -.fa-battery-1:before, -.fa-battery-quarter:before { - content: ""; -} - -.fa-battery-0:before, -.fa-battery-empty:before { - content: ""; -} - -.fa-mouse-pointer:before { - content: ""; -} - -.fa-i-cursor:before { - content: ""; -} - -.fa-object-group:before { - content: ""; -} - -.fa-object-ungroup:before { - content: ""; -} - -.fa-sticky-note:before { - content: ""; -} - -.fa-sticky-note-o:before { - content: ""; -} - -.fa-cc-jcb:before { - content: ""; -} - -.fa-cc-diners-club:before { - content: ""; -} - -.fa-clone:before { - content: ""; -} - -.fa-balance-scale:before { - content: ""; -} - -.fa-hourglass-o:before { - content: ""; -} - -.fa-hourglass-1:before, -.fa-hourglass-start:before { - content: ""; -} - -.fa-hourglass-2:before, -.fa-hourglass-half:before { - content: ""; -} - -.fa-hourglass-3:before, -.fa-hourglass-end:before { - content: ""; -} - -.fa-hourglass:before { - content: ""; -} - -.fa-hand-grab-o:before, -.fa-hand-rock-o:before { - content: ""; -} - -.fa-hand-stop-o:before, -.fa-hand-paper-o:before { - content: ""; -} - -.fa-hand-scissors-o:before { - content: ""; -} - -.fa-hand-lizard-o:before { - content: ""; -} - -.fa-hand-spock-o:before { - content: ""; -} - -.fa-hand-pointer-o:before { - content: ""; -} - -.fa-hand-peace-o:before { - content: ""; -} - -.fa-trademark:before { - content: ""; -} - -.fa-registered:before { - content: ""; -} - -.fa-creative-commons:before { - content: ""; -} - -.fa-gg:before { - content: ""; -} - -.fa-gg-circle:before { - content: ""; -} - -.fa-tripadvisor:before { - content: ""; -} - -.fa-odnoklassniki:before { - content: ""; -} - -.fa-odnoklassniki-square:before { - content: ""; -} - -.fa-get-pocket:before { - content: ""; -} - -.fa-wikipedia-w:before { - content: ""; -} - -.fa-safari:before { - content: ""; -} - -.fa-chrome:before { - content: ""; -} - -.fa-firefox:before { - content: ""; -} - -.fa-opera:before { - content: ""; -} - -.fa-internet-explorer:before { - content: ""; -} - -.fa-tv:before, -.fa-television:before { - content: ""; -} - -.fa-contao:before { - content: ""; -} - -.fa-500px:before { - content: ""; -} - -.fa-amazon:before { - content: ""; -} - -.fa-calendar-plus-o:before { - content: ""; -} - -.fa-calendar-minus-o:before { - content: ""; -} - -.fa-calendar-times-o:before { - content: ""; -} - -.fa-calendar-check-o:before { - content: ""; -} - -.fa-industry:before { - content: ""; -} - -.fa-map-pin:before { - content: ""; -} - -.fa-map-signs:before { - content: ""; -} - -.fa-map-o:before { - content: ""; -} - -.fa-map:before { - content: ""; -} - -.fa-commenting:before { - content: ""; -} - -.fa-commenting-o:before { - content: ""; -} - -.fa-houzz:before { - content: ""; -} - -.fa-vimeo:before { - content: ""; -} - -.fa-black-tie:before { - content: ""; -} - -.fa-fonticons:before { - content: ""; -} - -.fa-reddit-alien:before { - content: ""; -} - -.fa-edge:before { - content: ""; -} - -.fa-credit-card-alt:before { - content: ""; -} - -.fa-codiepie:before { - content: ""; -} - -.fa-modx:before { - content: ""; -} - -.fa-fort-awesome:before { - content: ""; -} - -.fa-usb:before { - content: ""; -} - -.fa-product-hunt:before { - content: ""; -} - -.fa-mixcloud:before { - content: ""; -} - -.fa-scribd:before { - content: ""; -} - -.fa-pause-circle:before { - content: ""; -} - -.fa-pause-circle-o:before { - content: ""; -} - -.fa-stop-circle:before { - content: ""; -} - -.fa-stop-circle-o:before { - content: ""; -} - -.fa-shopping-bag:before { - content: ""; -} - -.fa-shopping-basket:before { - content: ""; -} - -.fa-hashtag:before { - content: ""; -} - -.fa-bluetooth:before { - content: ""; -} - -.fa-bluetooth-b:before { - content: ""; -} - -.fa-percent:before { - content: ""; -} - -.fa-gitlab:before, .icon-gitlab:before { - content: ""; -} - -.fa-wpbeginner:before { - content: ""; -} - -.fa-wpforms:before { - content: ""; -} - -.fa-envira:before { - content: ""; -} - -.fa-universal-access:before { - content: ""; -} - -.fa-wheelchair-alt:before { - content: ""; -} - -.fa-question-circle-o:before { - content: ""; -} - -.fa-blind:before { - content: ""; -} - -.fa-audio-description:before { - content: ""; -} - -.fa-volume-control-phone:before { - content: ""; -} - -.fa-braille:before { - content: ""; -} - -.fa-assistive-listening-systems:before { - content: ""; -} - -.fa-asl-interpreting:before, -.fa-american-sign-language-interpreting:before { - content: ""; -} - -.fa-deafness:before, -.fa-hard-of-hearing:before, -.fa-deaf:before { - content: ""; -} - -.fa-glide:before { - content: ""; -} - -.fa-glide-g:before { - content: ""; -} - -.fa-signing:before, -.fa-sign-language:before { - content: ""; -} - -.fa-low-vision:before { - content: ""; -} - -.fa-viadeo:before { - content: ""; -} - -.fa-viadeo-square:before { - content: ""; -} - -.fa-snapchat:before { - content: ""; -} - -.fa-snapchat-ghost:before { - content: ""; -} - -.fa-snapchat-square:before { - content: ""; -} - -.fa-pied-piper:before { - content: ""; -} - -.fa-first-order:before { - content: ""; -} - -.fa-yoast:before { - content: ""; -} - -.fa-themeisle:before { - content: ""; -} - -.fa-google-plus-circle:before, -.fa-google-plus-official:before { - content: ""; -} - -.fa-fa:before, -.fa-font-awesome:before { - content: ""; -} - -.fa-handshake-o:before { - content: ""; -} - -.fa-envelope-open:before { - content: ""; -} - -.fa-envelope-open-o:before { - content: ""; -} - -.fa-linode:before { - content: ""; -} - -.fa-address-book:before { - content: ""; -} - -.fa-address-book-o:before { - content: ""; -} - -.fa-vcard:before, -.fa-address-card:before { - content: ""; -} - -.fa-vcard-o:before, -.fa-address-card-o:before { - content: ""; -} - -.fa-user-circle:before { - content: ""; -} - -.fa-user-circle-o:before { - content: ""; -} - -.fa-user-o:before { - content: ""; -} - -.fa-id-badge:before { - content: ""; -} - -.fa-drivers-license:before, -.fa-id-card:before { - content: ""; -} - -.fa-drivers-license-o:before, -.fa-id-card-o:before { - content: ""; -} - -.fa-quora:before { - content: ""; -} - -.fa-free-code-camp:before { - content: ""; -} - -.fa-telegram:before { - content: ""; -} - -.fa-thermometer-4:before, -.fa-thermometer:before, -.fa-thermometer-full:before { - content: ""; -} - -.fa-thermometer-3:before, -.fa-thermometer-three-quarters:before { - content: ""; -} - -.fa-thermometer-2:before, -.fa-thermometer-half:before { - content: ""; -} - -.fa-thermometer-1:before, -.fa-thermometer-quarter:before { - content: ""; -} - -.fa-thermometer-0:before, -.fa-thermometer-empty:before { - content: ""; -} - -.fa-shower:before { - content: ""; -} - -.fa-bathtub:before, -.fa-s15:before, -.fa-bath:before { - content: ""; -} - -.fa-podcast:before { - content: ""; -} - -.fa-window-maximize:before { - content: ""; -} - -.fa-window-minimize:before { - content: ""; -} - -.fa-window-restore:before { - content: ""; -} - -.fa-times-rectangle:before, -.fa-window-close:before { - content: ""; -} - -.fa-times-rectangle-o:before, -.fa-window-close-o:before { - content: ""; -} - -.fa-bandcamp:before { - content: ""; -} - -.fa-grav:before { - content: ""; -} - -.fa-etsy:before { - content: ""; -} - -.fa-imdb:before { - content: ""; -} - -.fa-ravelry:before { - content: ""; -} - -.fa-eercast:before { - content: ""; -} - -.fa-microchip:before { - content: ""; -} - -.fa-snowflake-o:before { - content: ""; -} - -.fa-superpowers:before { - content: ""; -} - -.fa-wpexplorer:before { - content: ""; -} - -.fa-meetup:before { - content: ""; -} - -.sr-only { - position: absolute; - width: 1px; - height: 1px; - padding: 0; - margin: -1px; - overflow: hidden; - clip: rect(0, 0, 0, 0); - border: 0; -} - -.sr-only-focusable:active, .sr-only-focusable:focus { - position: static; - width: auto; - height: auto; - margin: 0; - overflow: visible; - clip: auto; -} - -.fa, .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand, .rst-content .admonition-title, .rst-content h1 .headerlink, .rst-content h2 .headerlink, .rst-content h3 .headerlink, .rst-content h4 .headerlink, .rst-content h5 .headerlink, .rst-content h6 .headerlink, .rst-content dl dt .headerlink, .rst-content p.caption .headerlink, .rst-content table > caption .headerlink, .rst-content tt.download span:first-child, .rst-content code.download span:first-child, .icon, .wy-dropdown .caret, .wy-inline-validate.wy-inline-validate-success .wy-input-context, .wy-inline-validate.wy-inline-validate-danger .wy-input-context, .wy-inline-validate.wy-inline-validate-warning .wy-input-context, .wy-inline-validate.wy-inline-validate-info .wy-input-context { - font-family: inherit; -} -.fa:before, .wy-menu-vertical li span.toctree-expand:before, .wy-menu-vertical li.on a span.toctree-expand:before, .wy-menu-vertical li.current > a span.toctree-expand:before, .rst-content .admonition-title:before, .rst-content h1 .headerlink:before, .rst-content h2 .headerlink:before, .rst-content h3 .headerlink:before, .rst-content h4 .headerlink:before, .rst-content h5 .headerlink:before, .rst-content h6 .headerlink:before, .rst-content dl dt .headerlink:before, .rst-content p.caption .headerlink:before, .rst-content table > caption .headerlink:before, .rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before, .icon:before, .wy-dropdown .caret:before, .wy-inline-validate.wy-inline-validate-success .wy-input-context:before, .wy-inline-validate.wy-inline-validate-danger .wy-input-context:before, .wy-inline-validate.wy-inline-validate-warning .wy-input-context:before, .wy-inline-validate.wy-inline-validate-info .wy-input-context:before { - font-family: "FontAwesome"; - display: inline-block; - font-style: normal; - font-weight: normal; - line-height: 1; - text-decoration: inherit; -} - -a .fa, a .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li a span.toctree-expand, .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand, a .rst-content .admonition-title, .rst-content a .admonition-title, a .rst-content h1 .headerlink, .rst-content h1 a .headerlink, a .rst-content h2 .headerlink, .rst-content h2 a .headerlink, a .rst-content h3 .headerlink, .rst-content h3 a .headerlink, a .rst-content h4 .headerlink, .rst-content h4 a .headerlink, a .rst-content h5 .headerlink, .rst-content h5 a .headerlink, a .rst-content h6 .headerlink, .rst-content h6 a .headerlink, a .rst-content dl dt .headerlink, .rst-content dl dt a .headerlink, a .rst-content p.caption .headerlink, .rst-content p.caption a .headerlink, a .rst-content table > caption .headerlink, .rst-content table > caption a .headerlink, a .rst-content tt.download span:first-child, .rst-content tt.download a span:first-child, a .rst-content code.download span:first-child, .rst-content code.download a span:first-child, a .icon { - display: inline-block; - text-decoration: inherit; -} - -.btn .fa, .btn .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .btn span.toctree-expand, .btn .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.on a .btn span.toctree-expand, .btn .wy-menu-vertical li.current > a span.toctree-expand, .wy-menu-vertical li.current > a .btn span.toctree-expand, .btn .rst-content .admonition-title, .rst-content .btn .admonition-title, .btn .rst-content h1 .headerlink, .rst-content h1 .btn .headerlink, .btn .rst-content h2 .headerlink, .rst-content h2 .btn .headerlink, .btn .rst-content h3 .headerlink, .rst-content h3 .btn .headerlink, .btn .rst-content h4 .headerlink, .rst-content h4 .btn .headerlink, .btn .rst-content h5 .headerlink, .rst-content h5 .btn .headerlink, .btn .rst-content h6 .headerlink, .rst-content h6 .btn .headerlink, .btn .rst-content dl dt .headerlink, .rst-content dl dt .btn .headerlink, .btn .rst-content p.caption .headerlink, .rst-content p.caption .btn .headerlink, .btn .rst-content table > caption .headerlink, .rst-content table > caption .btn .headerlink, .btn .rst-content tt.download span:first-child, .rst-content tt.download .btn span:first-child, .btn .rst-content code.download span:first-child, .rst-content code.download .btn span:first-child, .btn .icon, .nav .fa, .nav .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .nav span.toctree-expand, .nav .wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.on a .nav span.toctree-expand, .nav .wy-menu-vertical li.current > a span.toctree-expand, .wy-menu-vertical li.current > a .nav span.toctree-expand, .nav .rst-content .admonition-title, .rst-content .nav .admonition-title, .nav .rst-content h1 .headerlink, .rst-content h1 .nav .headerlink, .nav .rst-content h2 .headerlink, .rst-content h2 .nav .headerlink, .nav .rst-content h3 .headerlink, .rst-content h3 .nav .headerlink, .nav .rst-content h4 .headerlink, .rst-content h4 .nav .headerlink, .nav .rst-content h5 .headerlink, .rst-content h5 .nav .headerlink, .nav .rst-content h6 .headerlink, .rst-content h6 .nav .headerlink, .nav .rst-content dl dt .headerlink, .rst-content dl dt .nav .headerlink, .nav .rst-content p.caption .headerlink, .rst-content p.caption .nav .headerlink, .nav .rst-content table > caption .headerlink, .rst-content table > caption .nav .headerlink, .nav .rst-content tt.download span:first-child, .rst-content tt.download .nav span:first-child, .nav .rst-content code.download span:first-child, .rst-content code.download .nav span:first-child, .nav .icon { - display: inline; -} -.btn .fa.fa-large, .btn .wy-menu-vertical li span.fa-large.toctree-expand, .wy-menu-vertical li .btn span.fa-large.toctree-expand, .btn .rst-content .fa-large.admonition-title, .rst-content .btn .fa-large.admonition-title, .btn .rst-content h1 .fa-large.headerlink, .rst-content h1 .btn .fa-large.headerlink, .btn .rst-content h2 .fa-large.headerlink, .rst-content h2 .btn .fa-large.headerlink, .btn .rst-content h3 .fa-large.headerlink, .rst-content h3 .btn .fa-large.headerlink, .btn .rst-content h4 .fa-large.headerlink, .rst-content h4 .btn .fa-large.headerlink, .btn .rst-content h5 .fa-large.headerlink, .rst-content h5 .btn .fa-large.headerlink, .btn .rst-content h6 .fa-large.headerlink, .rst-content h6 .btn .fa-large.headerlink, .btn .rst-content dl dt .fa-large.headerlink, .rst-content dl dt .btn .fa-large.headerlink, .btn .rst-content p.caption .fa-large.headerlink, .rst-content p.caption .btn .fa-large.headerlink, .btn .rst-content table > caption .fa-large.headerlink, .rst-content table > caption .btn .fa-large.headerlink, .btn .rst-content tt.download span.fa-large:first-child, .rst-content tt.download .btn span.fa-large:first-child, .btn .rst-content code.download span.fa-large:first-child, .rst-content code.download .btn span.fa-large:first-child, .btn .fa-large.icon, .nav .fa.fa-large, .nav .wy-menu-vertical li span.fa-large.toctree-expand, .wy-menu-vertical li .nav span.fa-large.toctree-expand, .nav .rst-content .fa-large.admonition-title, .rst-content .nav .fa-large.admonition-title, .nav .rst-content h1 .fa-large.headerlink, .rst-content h1 .nav .fa-large.headerlink, .nav .rst-content h2 .fa-large.headerlink, .rst-content h2 .nav .fa-large.headerlink, .nav .rst-content h3 .fa-large.headerlink, .rst-content h3 .nav .fa-large.headerlink, .nav .rst-content h4 .fa-large.headerlink, .rst-content h4 .nav .fa-large.headerlink, .nav .rst-content h5 .fa-large.headerlink, .rst-content h5 .nav .fa-large.headerlink, .nav .rst-content h6 .fa-large.headerlink, .rst-content h6 .nav .fa-large.headerlink, .nav .rst-content dl dt .fa-large.headerlink, .rst-content dl dt .nav .fa-large.headerlink, .nav .rst-content p.caption .fa-large.headerlink, .rst-content p.caption .nav .fa-large.headerlink, .nav .rst-content table > caption .fa-large.headerlink, .rst-content table > caption .nav .fa-large.headerlink, .nav .rst-content tt.download span.fa-large:first-child, .rst-content tt.download .nav span.fa-large:first-child, .nav .rst-content code.download span.fa-large:first-child, .rst-content code.download .nav span.fa-large:first-child, .nav .fa-large.icon { - line-height: 0.9em; -} -.btn .fa.fa-spin, .btn .wy-menu-vertical li span.fa-spin.toctree-expand, .wy-menu-vertical li .btn span.fa-spin.toctree-expand, .btn .rst-content .fa-spin.admonition-title, .rst-content .btn .fa-spin.admonition-title, .btn .rst-content h1 .fa-spin.headerlink, .rst-content h1 .btn .fa-spin.headerlink, .btn .rst-content h2 .fa-spin.headerlink, .rst-content h2 .btn .fa-spin.headerlink, .btn .rst-content h3 .fa-spin.headerlink, .rst-content h3 .btn .fa-spin.headerlink, .btn .rst-content h4 .fa-spin.headerlink, .rst-content h4 .btn .fa-spin.headerlink, .btn .rst-content h5 .fa-spin.headerlink, .rst-content h5 .btn .fa-spin.headerlink, .btn .rst-content h6 .fa-spin.headerlink, .rst-content h6 .btn .fa-spin.headerlink, .btn .rst-content dl dt .fa-spin.headerlink, .rst-content dl dt .btn .fa-spin.headerlink, .btn .rst-content p.caption .fa-spin.headerlink, .rst-content p.caption .btn .fa-spin.headerlink, .btn .rst-content table > caption .fa-spin.headerlink, .rst-content table > caption .btn .fa-spin.headerlink, .btn .rst-content tt.download span.fa-spin:first-child, .rst-content tt.download .btn span.fa-spin:first-child, .btn .rst-content code.download span.fa-spin:first-child, .rst-content code.download .btn span.fa-spin:first-child, .btn .fa-spin.icon, .nav .fa.fa-spin, .nav .wy-menu-vertical li span.fa-spin.toctree-expand, .wy-menu-vertical li .nav span.fa-spin.toctree-expand, .nav .rst-content .fa-spin.admonition-title, .rst-content .nav .fa-spin.admonition-title, .nav .rst-content h1 .fa-spin.headerlink, .rst-content h1 .nav .fa-spin.headerlink, .nav .rst-content h2 .fa-spin.headerlink, .rst-content h2 .nav .fa-spin.headerlink, .nav .rst-content h3 .fa-spin.headerlink, .rst-content h3 .nav .fa-spin.headerlink, .nav .rst-content h4 .fa-spin.headerlink, .rst-content h4 .nav .fa-spin.headerlink, .nav .rst-content h5 .fa-spin.headerlink, .rst-content h5 .nav .fa-spin.headerlink, .nav .rst-content h6 .fa-spin.headerlink, .rst-content h6 .nav .fa-spin.headerlink, .nav .rst-content dl dt .fa-spin.headerlink, .rst-content dl dt .nav .fa-spin.headerlink, .nav .rst-content p.caption .fa-spin.headerlink, .rst-content p.caption .nav .fa-spin.headerlink, .nav .rst-content table > caption .fa-spin.headerlink, .rst-content table > caption .nav .fa-spin.headerlink, .nav .rst-content tt.download span.fa-spin:first-child, .rst-content tt.download .nav span.fa-spin:first-child, .nav .rst-content code.download span.fa-spin:first-child, .rst-content code.download .nav span.fa-spin:first-child, .nav .fa-spin.icon { - display: inline-block; -} - -.btn.fa:before, .wy-menu-vertical li span.btn.toctree-expand:before, .rst-content .btn.admonition-title:before, .rst-content h1 .btn.headerlink:before, .rst-content h2 .btn.headerlink:before, .rst-content h3 .btn.headerlink:before, .rst-content h4 .btn.headerlink:before, .rst-content h5 .btn.headerlink:before, .rst-content h6 .btn.headerlink:before, .rst-content dl dt .btn.headerlink:before, .rst-content p.caption .btn.headerlink:before, .rst-content table > caption .btn.headerlink:before, .rst-content tt.download span.btn:first-child:before, .rst-content code.download span.btn:first-child:before, .btn.icon:before { - opacity: 0.5; - -webkit-transition: opacity 0.05s ease-in; - -moz-transition: opacity 0.05s ease-in; - transition: opacity 0.05s ease-in; -} - -.btn.fa:hover:before, .wy-menu-vertical li span.btn.toctree-expand:hover:before, .rst-content .btn.admonition-title:hover:before, .rst-content h1 .btn.headerlink:hover:before, .rst-content h2 .btn.headerlink:hover:before, .rst-content h3 .btn.headerlink:hover:before, .rst-content h4 .btn.headerlink:hover:before, .rst-content h5 .btn.headerlink:hover:before, .rst-content h6 .btn.headerlink:hover:before, .rst-content dl dt .btn.headerlink:hover:before, .rst-content p.caption .btn.headerlink:hover:before, .rst-content table > caption .btn.headerlink:hover:before, .rst-content tt.download span.btn:first-child:hover:before, .rst-content code.download span.btn:first-child:hover:before, .btn.icon:hover:before { - opacity: 1; -} - -.btn-mini .fa:before, .btn-mini .wy-menu-vertical li span.toctree-expand:before, .wy-menu-vertical li .btn-mini span.toctree-expand:before, .btn-mini .rst-content .admonition-title:before, .rst-content .btn-mini .admonition-title:before, .btn-mini .rst-content h1 .headerlink:before, .rst-content h1 .btn-mini .headerlink:before, .btn-mini .rst-content h2 .headerlink:before, .rst-content h2 .btn-mini .headerlink:before, .btn-mini .rst-content h3 .headerlink:before, .rst-content h3 .btn-mini .headerlink:before, .btn-mini .rst-content h4 .headerlink:before, .rst-content h4 .btn-mini .headerlink:before, .btn-mini .rst-content h5 .headerlink:before, .rst-content h5 .btn-mini .headerlink:before, .btn-mini .rst-content h6 .headerlink:before, .rst-content h6 .btn-mini .headerlink:before, .btn-mini .rst-content dl dt .headerlink:before, .rst-content dl dt .btn-mini .headerlink:before, .btn-mini .rst-content p.caption .headerlink:before, .rst-content p.caption .btn-mini .headerlink:before, .btn-mini .rst-content table > caption .headerlink:before, .rst-content table > caption .btn-mini .headerlink:before, .btn-mini .rst-content tt.download span:first-child:before, .rst-content tt.download .btn-mini span:first-child:before, .btn-mini .rst-content code.download span:first-child:before, .rst-content code.download .btn-mini span:first-child:before, .btn-mini .icon:before { - font-size: 14px; - vertical-align: -15%; -} - -.wy-alert, .rst-content .note, .rst-content .attention, .rst-content .caution, .rst-content .danger, .rst-content .error, .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .warning, .rst-content .seealso, .rst-content .admonition-todo, .rst-content .admonition { - padding: 12px; - line-height: 24px; - margin-bottom: 24px; - background: #e7f2fa; -} - -.wy-alert-title, .rst-content .admonition-title { - color: #fff; - font-weight: bold; - display: block; - color: #fff; - background: #6ab0de; - margin: -12px; - padding: 6px 12px; - margin-bottom: 12px; -} - -.wy-alert.wy-alert-danger, .rst-content .wy-alert-danger.note, .rst-content .wy-alert-danger.attention, .rst-content .wy-alert-danger.caution, .rst-content .danger, .rst-content .error, .rst-content .wy-alert-danger.hint, .rst-content .wy-alert-danger.important, .rst-content .wy-alert-danger.tip, .rst-content .wy-alert-danger.warning, .rst-content .wy-alert-danger.seealso, .rst-content .wy-alert-danger.admonition-todo, .rst-content .wy-alert-danger.admonition { - background: #fdf3f2; -} -.wy-alert.wy-alert-danger .wy-alert-title, .rst-content .wy-alert-danger.note .wy-alert-title, .rst-content .wy-alert-danger.attention .wy-alert-title, .rst-content .wy-alert-danger.caution .wy-alert-title, .rst-content .danger .wy-alert-title, .rst-content .error .wy-alert-title, .rst-content .wy-alert-danger.hint .wy-alert-title, .rst-content .wy-alert-danger.important .wy-alert-title, .rst-content .wy-alert-danger.tip .wy-alert-title, .rst-content .wy-alert-danger.warning .wy-alert-title, .rst-content .wy-alert-danger.seealso .wy-alert-title, .rst-content .wy-alert-danger.admonition-todo .wy-alert-title, .rst-content .wy-alert-danger.admonition .wy-alert-title, .wy-alert.wy-alert-danger .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-danger .admonition-title, .rst-content .wy-alert-danger.note .admonition-title, .rst-content .wy-alert-danger.attention .admonition-title, .rst-content .wy-alert-danger.caution .admonition-title, .rst-content .danger .admonition-title, .rst-content .error .admonition-title, .rst-content .wy-alert-danger.hint .admonition-title, .rst-content .wy-alert-danger.important .admonition-title, .rst-content .wy-alert-danger.tip .admonition-title, .rst-content .wy-alert-danger.warning .admonition-title, .rst-content .wy-alert-danger.seealso .admonition-title, .rst-content .wy-alert-danger.admonition-todo .admonition-title, .rst-content .wy-alert-danger.admonition .admonition-title { - background: #f29f97; -} - -.wy-alert.wy-alert-warning, .rst-content .wy-alert-warning.note, .rst-content .attention, .rst-content .caution, .rst-content .wy-alert-warning.danger, .rst-content .wy-alert-warning.error, .rst-content .wy-alert-warning.hint, .rst-content .wy-alert-warning.important, .rst-content .wy-alert-warning.tip, .rst-content .warning, .rst-content .wy-alert-warning.seealso, .rst-content .admonition-todo, .rst-content .wy-alert-warning.admonition { - background: #ffedcc; -} -.wy-alert.wy-alert-warning .wy-alert-title, .rst-content .wy-alert-warning.note .wy-alert-title, .rst-content .attention .wy-alert-title, .rst-content .caution .wy-alert-title, .rst-content .wy-alert-warning.danger .wy-alert-title, .rst-content .wy-alert-warning.error .wy-alert-title, .rst-content .wy-alert-warning.hint .wy-alert-title, .rst-content .wy-alert-warning.important .wy-alert-title, .rst-content .wy-alert-warning.tip .wy-alert-title, .rst-content .warning .wy-alert-title, .rst-content .wy-alert-warning.seealso .wy-alert-title, .rst-content .admonition-todo .wy-alert-title, .rst-content .wy-alert-warning.admonition .wy-alert-title, .wy-alert.wy-alert-warning .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-warning .admonition-title, .rst-content .wy-alert-warning.note .admonition-title, .rst-content .attention .admonition-title, .rst-content .caution .admonition-title, .rst-content .wy-alert-warning.danger .admonition-title, .rst-content .wy-alert-warning.error .admonition-title, .rst-content .wy-alert-warning.hint .admonition-title, .rst-content .wy-alert-warning.important .admonition-title, .rst-content .wy-alert-warning.tip .admonition-title, .rst-content .warning .admonition-title, .rst-content .wy-alert-warning.seealso .admonition-title, .rst-content .admonition-todo .admonition-title, .rst-content .wy-alert-warning.admonition .admonition-title { - background: #f0b37e; -} - -.wy-alert.wy-alert-info, .rst-content .note, .rst-content .wy-alert-info.attention, .rst-content .wy-alert-info.caution, .rst-content .wy-alert-info.danger, .rst-content .wy-alert-info.error, .rst-content .wy-alert-info.hint, .rst-content .wy-alert-info.important, .rst-content .wy-alert-info.tip, .rst-content .wy-alert-info.warning, .rst-content .seealso, .rst-content .wy-alert-info.admonition-todo, .rst-content .wy-alert-info.admonition { - background: #e7f2fa; -} -.wy-alert.wy-alert-info .wy-alert-title, .rst-content .note .wy-alert-title, .rst-content .wy-alert-info.attention .wy-alert-title, .rst-content .wy-alert-info.caution .wy-alert-title, .rst-content .wy-alert-info.danger .wy-alert-title, .rst-content .wy-alert-info.error .wy-alert-title, .rst-content .wy-alert-info.hint .wy-alert-title, .rst-content .wy-alert-info.important .wy-alert-title, .rst-content .wy-alert-info.tip .wy-alert-title, .rst-content .wy-alert-info.warning .wy-alert-title, .rst-content .seealso .wy-alert-title, .rst-content .wy-alert-info.admonition-todo .wy-alert-title, .rst-content .wy-alert-info.admonition .wy-alert-title, .wy-alert.wy-alert-info .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-info .admonition-title, .rst-content .note .admonition-title, .rst-content .wy-alert-info.attention .admonition-title, .rst-content .wy-alert-info.caution .admonition-title, .rst-content .wy-alert-info.danger .admonition-title, .rst-content .wy-alert-info.error .admonition-title, .rst-content .wy-alert-info.hint .admonition-title, .rst-content .wy-alert-info.important .admonition-title, .rst-content .wy-alert-info.tip .admonition-title, .rst-content .wy-alert-info.warning .admonition-title, .rst-content .seealso .admonition-title, .rst-content .wy-alert-info.admonition-todo .admonition-title, .rst-content .wy-alert-info.admonition .admonition-title { - background: #6ab0de; -} - -.wy-alert.wy-alert-success, .rst-content .wy-alert-success.note, .rst-content .wy-alert-success.attention, .rst-content .wy-alert-success.caution, .rst-content .wy-alert-success.danger, .rst-content .wy-alert-success.error, .rst-content .hint, .rst-content .important, .rst-content .tip, .rst-content .wy-alert-success.warning, .rst-content .wy-alert-success.seealso, .rst-content .wy-alert-success.admonition-todo, .rst-content .wy-alert-success.admonition { - background: #dbfaf4; -} -.wy-alert.wy-alert-success .wy-alert-title, .rst-content .wy-alert-success.note .wy-alert-title, .rst-content .wy-alert-success.attention .wy-alert-title, .rst-content .wy-alert-success.caution .wy-alert-title, .rst-content .wy-alert-success.danger .wy-alert-title, .rst-content .wy-alert-success.error .wy-alert-title, .rst-content .hint .wy-alert-title, .rst-content .important .wy-alert-title, .rst-content .tip .wy-alert-title, .rst-content .wy-alert-success.warning .wy-alert-title, .rst-content .wy-alert-success.seealso .wy-alert-title, .rst-content .wy-alert-success.admonition-todo .wy-alert-title, .rst-content .wy-alert-success.admonition .wy-alert-title, .wy-alert.wy-alert-success .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-success .admonition-title, .rst-content .wy-alert-success.note .admonition-title, .rst-content .wy-alert-success.attention .admonition-title, .rst-content .wy-alert-success.caution .admonition-title, .rst-content .wy-alert-success.danger .admonition-title, .rst-content .wy-alert-success.error .admonition-title, .rst-content .hint .admonition-title, .rst-content .important .admonition-title, .rst-content .tip .admonition-title, .rst-content .wy-alert-success.warning .admonition-title, .rst-content .wy-alert-success.seealso .admonition-title, .rst-content .wy-alert-success.admonition-todo .admonition-title, .rst-content .wy-alert-success.admonition .admonition-title { - background: #1abc9c; -} - -.wy-alert.wy-alert-neutral, .rst-content .wy-alert-neutral.note, .rst-content .wy-alert-neutral.attention, .rst-content .wy-alert-neutral.caution, .rst-content .wy-alert-neutral.danger, .rst-content .wy-alert-neutral.error, .rst-content .wy-alert-neutral.hint, .rst-content .wy-alert-neutral.important, .rst-content .wy-alert-neutral.tip, .rst-content .wy-alert-neutral.warning, .rst-content .wy-alert-neutral.seealso, .rst-content .wy-alert-neutral.admonition-todo, .rst-content .wy-alert-neutral.admonition { - background: #f3f6f6; -} -.wy-alert.wy-alert-neutral .wy-alert-title, .rst-content .wy-alert-neutral.note .wy-alert-title, .rst-content .wy-alert-neutral.attention .wy-alert-title, .rst-content .wy-alert-neutral.caution .wy-alert-title, .rst-content .wy-alert-neutral.danger .wy-alert-title, .rst-content .wy-alert-neutral.error .wy-alert-title, .rst-content .wy-alert-neutral.hint .wy-alert-title, .rst-content .wy-alert-neutral.important .wy-alert-title, .rst-content .wy-alert-neutral.tip .wy-alert-title, .rst-content .wy-alert-neutral.warning .wy-alert-title, .rst-content .wy-alert-neutral.seealso .wy-alert-title, .rst-content .wy-alert-neutral.admonition-todo .wy-alert-title, .rst-content .wy-alert-neutral.admonition .wy-alert-title, .wy-alert.wy-alert-neutral .rst-content .admonition-title, .rst-content .wy-alert.wy-alert-neutral .admonition-title, .rst-content .wy-alert-neutral.note .admonition-title, .rst-content .wy-alert-neutral.attention .admonition-title, .rst-content .wy-alert-neutral.caution .admonition-title, .rst-content .wy-alert-neutral.danger .admonition-title, .rst-content .wy-alert-neutral.error .admonition-title, .rst-content .wy-alert-neutral.hint .admonition-title, .rst-content .wy-alert-neutral.important .admonition-title, .rst-content .wy-alert-neutral.tip .admonition-title, .rst-content .wy-alert-neutral.warning .admonition-title, .rst-content .wy-alert-neutral.seealso .admonition-title, .rst-content .wy-alert-neutral.admonition-todo .admonition-title, .rst-content .wy-alert-neutral.admonition .admonition-title { - color: #404040; - background: #e1e4e5; -} -.wy-alert.wy-alert-neutral a, .rst-content .wy-alert-neutral.note a, .rst-content .wy-alert-neutral.attention a, .rst-content .wy-alert-neutral.caution a, .rst-content .wy-alert-neutral.danger a, .rst-content .wy-alert-neutral.error a, .rst-content .wy-alert-neutral.hint a, .rst-content .wy-alert-neutral.important a, .rst-content .wy-alert-neutral.tip a, .rst-content .wy-alert-neutral.warning a, .rst-content .wy-alert-neutral.seealso a, .rst-content .wy-alert-neutral.admonition-todo a, .rst-content .wy-alert-neutral.admonition a { - color: #60c557; -} - -.wy-alert p:last-child, .rst-content .note p:last-child, .rst-content .attention p:last-child, .rst-content .caution p:last-child, .rst-content .danger p:last-child, .rst-content .error p:last-child, .rst-content .hint p:last-child, .rst-content .important p:last-child, .rst-content .tip p:last-child, .rst-content .warning p:last-child, .rst-content .seealso p:last-child, .rst-content .admonition-todo p:last-child, .rst-content .admonition p:last-child { - margin-bottom: 0; -} - -.wy-tray-container { - position: fixed; - bottom: 0px; - left: 0; - z-index: 600; -} -.wy-tray-container li { - display: block; - width: 300px; - background: transparent; - color: #fff; - text-align: center; - box-shadow: 0 5px 5px 0 rgba(0, 0, 0, 0.1); - padding: 0 24px; - min-width: 20%; - opacity: 0; - height: 0; - line-height: 56px; - overflow: hidden; - -webkit-transition: all 0.3s ease-in; - -moz-transition: all 0.3s ease-in; - transition: all 0.3s ease-in; -} -.wy-tray-container li.wy-tray-item-success { - background: #84d27d; -} -.wy-tray-container li.wy-tray-item-info { - background: #2980B9; -} -.wy-tray-container li.wy-tray-item-warning { - background: #E67E22; -} -.wy-tray-container li.wy-tray-item-danger { - background: #E74C3C; -} -.wy-tray-container li.on { - opacity: 1; - height: 56px; -} - -@media screen and (max-width: 768px) { - .wy-tray-container { - bottom: auto; - top: 0; - width: 100%; - } - .wy-tray-container li { - width: 100%; - } -} -button { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; - cursor: pointer; - line-height: normal; - -webkit-appearance: button; - *overflow: visible; -} - -button::-moz-focus-inner, input::-moz-focus-inner { - border: 0; - padding: 0; -} - -button[disabled] { - cursor: default; -} - -.btn { - /* Structure */ - display: inline-block; - border-radius: 2px; - line-height: normal; - white-space: nowrap; - text-align: center; - cursor: pointer; - font-size: 100%; - padding: 6px 12px 8px 12px; - color: #fff; - border: 1px solid rgba(0, 0, 0, 0.1); - background-color: #27AE60; - text-decoration: none; - font-weight: normal; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - box-shadow: 0px 1px 2px -1px rgba(255, 255, 255, 0.5) inset, 0px -2px 0px 0px rgba(0, 0, 0, 0.1) inset; - outline-none: false; - vertical-align: middle; - *display: inline; - zoom: 1; - -webkit-user-drag: none; - -webkit-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - -webkit-transition: all 0.1s linear; - -moz-transition: all 0.1s linear; - transition: all 0.1s linear; -} - -.btn-hover { - background: #72cb6a; - color: #fff; -} - -.btn:hover { - background: #2cc36b; - color: #fff; -} -.btn:focus { - background: #2cc36b; - outline: 0; -} -.btn:active { - box-shadow: 0px -1px 0px 0px rgba(0, 0, 0, 0.05) inset, 0px 2px 0px 0px rgba(0, 0, 0, 0.1) inset; - padding: 8px 12px 6px 12px; -} -.btn:visited { - color: #fff; -} -.btn:disabled { - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - opacity: 0.4; - cursor: not-allowed; - box-shadow: none; -} - -.btn-disabled { - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - opacity: 0.4; - cursor: not-allowed; - box-shadow: none; -} -.btn-disabled:hover, .btn-disabled:focus, .btn-disabled:active { - background-image: none; - filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); - filter: alpha(opacity=40); - opacity: 0.4; - cursor: not-allowed; - box-shadow: none; -} - -.btn::-moz-focus-inner { - padding: 0; - border: 0; -} - -.btn-small { - font-size: 80%; -} - -.btn-info { - background-color: #2980B9 !important; -} -.btn-info:hover { - background-color: #2e8ece !important; -} - -.btn-neutral { - background-color: #f3f6f6 !important; - color: #404040 !important; -} -.btn-neutral:hover { - background-color: #e5ebeb !important; - color: #404040; -} -.btn-neutral:visited { - color: #404040 !important; -} - -.btn-success { - background-color: #84d27d !important; -} -.btn-success:hover { - background-color: #72cb6a !important; -} - -.btn-danger { - background-color: #E74C3C !important; -} -.btn-danger:hover { - background-color: #ea6153 !important; -} - -.btn-warning { - background-color: #E67E22 !important; -} -.btn-warning:hover { - background-color: #e98b39 !important; -} - -.btn-invert { - background-color: #222; -} -.btn-invert:hover { - background-color: #2f2f2f !important; -} - -.btn-link { - background-color: transparent !important; - color: #60c557; - box-shadow: none; - border-color: transparent !important; -} -.btn-link:hover { - background-color: transparent !important; - color: #84d27d !important; - box-shadow: none; -} -.btn-link:active { - background-color: transparent !important; - color: #84d27d !important; - box-shadow: none; -} -.btn-link:visited { - color: #36872f; -} - -.wy-btn-group .btn, .wy-control .btn { - vertical-align: middle; -} - -.wy-btn-group { - margin-bottom: 24px; - *zoom: 1; -} -.wy-btn-group:before, .wy-btn-group:after { - display: table; - content: ""; -} -.wy-btn-group:after { - clear: both; -} - -.wy-dropdown { - position: relative; - display: inline-block; -} - -.wy-dropdown-active .wy-dropdown-menu { - display: block; -} - -.wy-dropdown-menu { - position: absolute; - left: 0; - display: none; - float: left; - top: 100%; - min-width: 100%; - background: #fcfcfc; - z-index: 100; - border: solid 1px #cfd7dd; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.1); - padding: 12px; -} -.wy-dropdown-menu > dd > a { - display: block; - clear: both; - color: #404040; - white-space: nowrap; - font-size: 90%; - padding: 0 12px; - cursor: pointer; -} -.wy-dropdown-menu > dd > a:hover { - background: #60c557; - color: #fff; -} -.wy-dropdown-menu > dd.divider { - border-top: solid 1px #cfd7dd; - margin: 6px 0; -} -.wy-dropdown-menu > dd.search { - padding-bottom: 12px; -} -.wy-dropdown-menu > dd.search input[type="search"] { - width: 100%; -} -.wy-dropdown-menu > dd.call-to-action { - background: #e3e3e3; - text-transform: uppercase; - font-weight: 500; - font-size: 80%; -} -.wy-dropdown-menu > dd.call-to-action:hover { - background: #e3e3e3; -} -.wy-dropdown-menu > dd.call-to-action .btn { - color: #fff; -} - -.wy-dropdown.wy-dropdown-up .wy-dropdown-menu { - bottom: 100%; - top: auto; - left: auto; - right: 0; -} - -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu { - background: #fcfcfc; - margin-top: 2px; -} -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a { - padding: 6px 12px; -} -.wy-dropdown.wy-dropdown-bubble .wy-dropdown-menu a:hover { - background: #60c557; - color: #fff; -} - -.wy-dropdown.wy-dropdown-left .wy-dropdown-menu { - right: 0; - left: auto; - text-align: right; -} - -.wy-dropdown-arrow:before { - content: " "; - border-bottom: 5px solid whitesmoke; - border-left: 5px solid transparent; - border-right: 5px solid transparent; - position: absolute; - display: block; - top: -4px; - left: 50%; - margin-left: -3px; -} -.wy-dropdown-arrow.wy-dropdown-arrow-left:before { - left: 11px; -} - -.wy-form-stacked select { - display: block; -} - -.wy-form-aligned input, .wy-form-aligned textarea, .wy-form-aligned select, .wy-form-aligned .wy-help-inline, .wy-form-aligned label { - display: inline-block; - *display: inline; - *zoom: 1; - vertical-align: middle; -} - -.wy-form-aligned .wy-control-group > label { - display: inline-block; - vertical-align: middle; - width: 10em; - margin: 6px 12px 0 0; - float: left; -} -.wy-form-aligned .wy-control { - float: left; -} -.wy-form-aligned .wy-control label { - display: block; -} -.wy-form-aligned .wy-control select { - margin-top: 6px; -} - -fieldset { - border: 0; - margin: 0; - padding: 0; -} - -legend { - display: block; - width: 100%; - border: 0; - padding: 0; - white-space: normal; - margin-bottom: 24px; - font-size: 150%; - *margin-left: -7px; -} - -label { - display: block; - margin: 0 0 0.3125em 0; - color: #333; - font-size: 90%; -} - -input, select, textarea { - font-size: 100%; - margin: 0; - vertical-align: baseline; - *vertical-align: middle; -} - -.wy-control-group { - margin-bottom: 24px; - *zoom: 1; - max-width: 68em; - margin-left: auto; - margin-right: auto; - *zoom: 1; -} -.wy-control-group:before, .wy-control-group:after { - display: table; - content: ""; -} -.wy-control-group:after { - clear: both; -} -.wy-control-group:before, .wy-control-group:after { - display: table; - content: ""; -} -.wy-control-group:after { - clear: both; -} - -.wy-control-group.wy-control-group-required > label:after { - content: " *"; - color: #E74C3C; -} - -.wy-control-group .wy-form-full, .wy-control-group .wy-form-halves, .wy-control-group .wy-form-thirds { - padding-bottom: 12px; -} -.wy-control-group .wy-form-full select, .wy-control-group .wy-form-halves select, .wy-control-group .wy-form-thirds select { - width: 100%; -} -.wy-control-group .wy-form-full input[type="text"], .wy-control-group .wy-form-full input[type="password"], .wy-control-group .wy-form-full input[type="email"], .wy-control-group .wy-form-full input[type="url"], .wy-control-group .wy-form-full input[type="date"], .wy-control-group .wy-form-full input[type="month"], .wy-control-group .wy-form-full input[type="time"], .wy-control-group .wy-form-full input[type="datetime"], .wy-control-group .wy-form-full input[type="datetime-local"], .wy-control-group .wy-form-full input[type="week"], .wy-control-group .wy-form-full input[type="number"], .wy-control-group .wy-form-full input[type="search"], .wy-control-group .wy-form-full input[type="tel"], .wy-control-group .wy-form-full input[type="color"], .wy-control-group .wy-form-halves input[type="text"], .wy-control-group .wy-form-halves input[type="password"], .wy-control-group .wy-form-halves input[type="email"], .wy-control-group .wy-form-halves input[type="url"], .wy-control-group .wy-form-halves input[type="date"], .wy-control-group .wy-form-halves input[type="month"], .wy-control-group .wy-form-halves input[type="time"], .wy-control-group .wy-form-halves input[type="datetime"], .wy-control-group .wy-form-halves input[type="datetime-local"], .wy-control-group .wy-form-halves input[type="week"], .wy-control-group .wy-form-halves input[type="number"], .wy-control-group .wy-form-halves input[type="search"], .wy-control-group .wy-form-halves input[type="tel"], .wy-control-group .wy-form-halves input[type="color"], .wy-control-group .wy-form-thirds input[type="text"], .wy-control-group .wy-form-thirds input[type="password"], .wy-control-group .wy-form-thirds input[type="email"], .wy-control-group .wy-form-thirds input[type="url"], .wy-control-group .wy-form-thirds input[type="date"], .wy-control-group .wy-form-thirds input[type="month"], .wy-control-group .wy-form-thirds input[type="time"], .wy-control-group .wy-form-thirds input[type="datetime"], .wy-control-group .wy-form-thirds input[type="datetime-local"], .wy-control-group .wy-form-thirds input[type="week"], .wy-control-group .wy-form-thirds input[type="number"], .wy-control-group .wy-form-thirds input[type="search"], .wy-control-group .wy-form-thirds input[type="tel"], .wy-control-group .wy-form-thirds input[type="color"] { - width: 100%; -} - -.wy-control-group .wy-form-full { - float: left; - display: block; - margin-right: 2.3576515979%; - width: 100%; - margin-right: 0; -} -.wy-control-group .wy-form-full:last-child { - margin-right: 0; -} - -.wy-control-group .wy-form-halves { - float: left; - display: block; - margin-right: 2.3576515979%; - width: 48.821174201%; -} -.wy-control-group .wy-form-halves:last-child { - margin-right: 0; -} -.wy-control-group .wy-form-halves:nth-of-type(2n) { - margin-right: 0; -} -.wy-control-group .wy-form-halves:nth-of-type(2n+1) { - clear: left; -} - -.wy-control-group .wy-form-thirds { - float: left; - display: block; - margin-right: 2.3576515979%; - width: 31.7615656014%; -} -.wy-control-group .wy-form-thirds:last-child { - margin-right: 0; -} -.wy-control-group .wy-form-thirds:nth-of-type(3n) { - margin-right: 0; -} -.wy-control-group .wy-form-thirds:nth-of-type(3n+1) { - clear: left; -} - -.wy-control-group.wy-control-group-no-input .wy-control { - margin: 6px 0 0 0; - font-size: 90%; -} - -.wy-control-no-input { - display: inline-block; - margin: 6px 0 0 0; - font-size: 90%; -} - -.wy-control-group.fluid-input input[type="text"], .wy-control-group.fluid-input input[type="password"], .wy-control-group.fluid-input input[type="email"], .wy-control-group.fluid-input input[type="url"], .wy-control-group.fluid-input input[type="date"], .wy-control-group.fluid-input input[type="month"], .wy-control-group.fluid-input input[type="time"], .wy-control-group.fluid-input input[type="datetime"], .wy-control-group.fluid-input input[type="datetime-local"], .wy-control-group.fluid-input input[type="week"], .wy-control-group.fluid-input input[type="number"], .wy-control-group.fluid-input input[type="search"], .wy-control-group.fluid-input input[type="tel"], .wy-control-group.fluid-input input[type="color"] { - width: 100%; -} - -.wy-form-message-inline { - display: inline-block; - padding-left: 0.3em; - color: #666; - vertical-align: middle; - font-size: 90%; -} - -.wy-form-message { - display: block; - color: #999; - font-size: 70%; - margin-top: 0.3125em; - font-style: italic; -} -.wy-form-message p { - font-size: inherit; - font-style: italic; - margin-bottom: 6px; -} -.wy-form-message p:last-child { - margin-bottom: 0; -} - -input { - line-height: normal; -} - -input[type="button"], input[type="reset"], input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - *overflow: visible; -} -input[type="text"], input[type="password"], input[type="email"], input[type="url"], input[type="date"], input[type="month"], input[type="time"], input[type="datetime"], input[type="datetime-local"], input[type="week"], input[type="number"], input[type="search"], input[type="tel"], input[type="color"] { - -webkit-appearance: none; - padding: 6px; - display: inline-block; - border: 1px solid #ccc; - font-size: 80%; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - box-shadow: inset 0 1px 3px #ddd; - border-radius: 0; - -webkit-transition: border 0.3s linear; - -moz-transition: border 0.3s linear; - transition: border 0.3s linear; -} -input[type="datetime-local"] { - padding: 0.34375em 0.625em; -} -input[disabled] { - cursor: default; -} -input[type="checkbox"], input[type="radio"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; - margin-right: 0.3125em; - *height: 13px; - *width: 13px; -} -input[type="search"] { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} -input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} -input[type="text"]:focus, input[type="password"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus { - outline: 0; - outline: thin dotted \9; - border-color: #333; -} -input.no-focus:focus { - border-color: #ccc !important; -} -input[type="file"]:focus, input[type="radio"]:focus, input[type="checkbox"]:focus { - outline: thin dotted #333; - outline: 1px auto #129FEA; -} -input[type="text"][disabled], input[type="password"][disabled], input[type="email"][disabled], input[type="url"][disabled], input[type="date"][disabled], input[type="month"][disabled], input[type="time"][disabled], input[type="datetime"][disabled], input[type="datetime-local"][disabled], input[type="week"][disabled], input[type="number"][disabled], input[type="search"][disabled], input[type="tel"][disabled], input[type="color"][disabled] { - cursor: not-allowed; - background-color: #fafafa; -} - -input:focus:invalid, textarea:focus:invalid, select:focus:invalid { - color: #E74C3C; - border: 1px solid #E74C3C; -} - -input:focus:invalid:focus, textarea:focus:invalid:focus, select:focus:invalid:focus { - border-color: #E74C3C; -} - -input[type="file"]:focus:invalid:focus, input[type="radio"]:focus:invalid:focus, input[type="checkbox"]:focus:invalid:focus { - outline-color: #E74C3C; -} - -input.wy-input-large { - padding: 12px; - font-size: 100%; -} - -textarea { - overflow: auto; - vertical-align: top; - width: 100%; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; -} - -select, textarea { - padding: 0.5em 0.625em; - display: inline-block; - border: 1px solid #ccc; - font-size: 80%; - box-shadow: inset 0 1px 3px #ddd; - -webkit-transition: border 0.3s linear; - -moz-transition: border 0.3s linear; - transition: border 0.3s linear; -} - -select { - border: 1px solid #ccc; - background-color: #fff; -} -select[multiple] { - height: auto; -} - -select:focus, textarea:focus { - outline: 0; -} - -select[disabled], textarea[disabled], input[readonly], select[readonly], textarea[readonly] { - cursor: not-allowed; - background-color: #fafafa; -} - -input[type="radio"][disabled], input[type="checkbox"][disabled] { - cursor: not-allowed; -} - -.wy-checkbox, .wy-radio { - margin: 6px 0; - color: #404040; - display: block; -} -.wy-checkbox input, .wy-radio input { - vertical-align: baseline; -} - -.wy-form-message-inline { - display: inline-block; - *display: inline; - *zoom: 1; - vertical-align: middle; -} - -.wy-input-prefix, .wy-input-suffix { - white-space: nowrap; - padding: 6px; -} -.wy-input-prefix .wy-input-context, .wy-input-suffix .wy-input-context { - line-height: 27px; - padding: 0 8px; - display: inline-block; - font-size: 80%; - background-color: #f3f6f6; - border: solid 1px #ccc; - color: #999; -} - -.wy-input-suffix .wy-input-context { - border-left: 0; -} - -.wy-input-prefix .wy-input-context { - border-right: 0; -} - -.wy-switch { - position: relative; - display: block; - height: 24px; - margin-top: 12px; - cursor: pointer; -} -.wy-switch:before { - position: absolute; - content: ""; - display: block; - left: 0; - top: 0; - width: 36px; - height: 12px; - border-radius: 4px; - background: #ccc; - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} -.wy-switch:after { - position: absolute; - content: ""; - display: block; - width: 18px; - height: 18px; - border-radius: 4px; - background: #999; - left: -3px; - top: -3px; - -webkit-transition: all 0.2s ease-in-out; - -moz-transition: all 0.2s ease-in-out; - transition: all 0.2s ease-in-out; -} -.wy-switch span { - position: absolute; - left: 48px; - display: block; - font-size: 12px; - color: #ccc; - line-height: 1; -} - -.wy-switch.active:before { - background: #60c557; -} -.wy-switch.active:after { - left: 24px; - background: #84d27d; -} - -.wy-switch.disabled { - cursor: not-allowed; - opacity: 0.8; -} - -.wy-control-group.wy-control-group-error .wy-form-message, .wy-control-group.wy-control-group-error > label { - color: #E74C3C; -} -.wy-control-group.wy-control-group-error input[type="text"], .wy-control-group.wy-control-group-error input[type="password"], .wy-control-group.wy-control-group-error input[type="email"], .wy-control-group.wy-control-group-error input[type="url"], .wy-control-group.wy-control-group-error input[type="date"], .wy-control-group.wy-control-group-error input[type="month"], .wy-control-group.wy-control-group-error input[type="time"], .wy-control-group.wy-control-group-error input[type="datetime"], .wy-control-group.wy-control-group-error input[type="datetime-local"], .wy-control-group.wy-control-group-error input[type="week"], .wy-control-group.wy-control-group-error input[type="number"], .wy-control-group.wy-control-group-error input[type="search"], .wy-control-group.wy-control-group-error input[type="tel"], .wy-control-group.wy-control-group-error input[type="color"] { - border: solid 1px #E74C3C; -} -.wy-control-group.wy-control-group-error textarea { - border: solid 1px #E74C3C; -} - -.wy-inline-validate { - white-space: nowrap; -} -.wy-inline-validate .wy-input-context { - padding: 0.5em 0.625em; - display: inline-block; - font-size: 80%; -} - -.wy-inline-validate.wy-inline-validate-success .wy-input-context { - color: #84d27d; -} - -.wy-inline-validate.wy-inline-validate-danger .wy-input-context { - color: #E74C3C; -} - -.wy-inline-validate.wy-inline-validate-warning .wy-input-context { - color: #E67E22; -} - -.wy-inline-validate.wy-inline-validate-info .wy-input-context { - color: #2980B9; -} - -.rotate-90 { - -webkit-transform: rotate(90deg); - -moz-transform: rotate(90deg); - -ms-transform: rotate(90deg); - -o-transform: rotate(90deg); - transform: rotate(90deg); -} - -.rotate-180 { - -webkit-transform: rotate(180deg); - -moz-transform: rotate(180deg); - -ms-transform: rotate(180deg); - -o-transform: rotate(180deg); - transform: rotate(180deg); -} - -.rotate-270 { - -webkit-transform: rotate(270deg); - -moz-transform: rotate(270deg); - -ms-transform: rotate(270deg); - -o-transform: rotate(270deg); - transform: rotate(270deg); -} - -.mirror { - -webkit-transform: scaleX(-1); - -moz-transform: scaleX(-1); - -ms-transform: scaleX(-1); - -o-transform: scaleX(-1); - transform: scaleX(-1); -} -.mirror.rotate-90 { - -webkit-transform: scaleX(-1) rotate(90deg); - -moz-transform: scaleX(-1) rotate(90deg); - -ms-transform: scaleX(-1) rotate(90deg); - -o-transform: scaleX(-1) rotate(90deg); - transform: scaleX(-1) rotate(90deg); -} -.mirror.rotate-180 { - -webkit-transform: scaleX(-1) rotate(180deg); - -moz-transform: scaleX(-1) rotate(180deg); - -ms-transform: scaleX(-1) rotate(180deg); - -o-transform: scaleX(-1) rotate(180deg); - transform: scaleX(-1) rotate(180deg); -} -.mirror.rotate-270 { - -webkit-transform: scaleX(-1) rotate(270deg); - -moz-transform: scaleX(-1) rotate(270deg); - -ms-transform: scaleX(-1) rotate(270deg); - -o-transform: scaleX(-1) rotate(270deg); - transform: scaleX(-1) rotate(270deg); -} - -@media only screen and (max-width: 480px) { - .wy-form button[type="submit"] { - margin: 0.7em 0 0; - } - .wy-form input[type="text"], .wy-form input[type="password"], .wy-form input[type="email"], .wy-form input[type="url"], .wy-form input[type="date"], .wy-form input[type="month"], .wy-form input[type="time"], .wy-form input[type="datetime"], .wy-form input[type="datetime-local"], .wy-form input[type="week"], .wy-form input[type="number"], .wy-form input[type="search"], .wy-form input[type="tel"], .wy-form input[type="color"] { - margin-bottom: 0.3em; - display: block; - } - .wy-form label { - margin-bottom: 0.3em; - display: block; - } - - .wy-form input[type="password"], .wy-form input[type="email"], .wy-form input[type="url"], .wy-form input[type="date"], .wy-form input[type="month"], .wy-form input[type="time"], .wy-form input[type="datetime"], .wy-form input[type="datetime-local"], .wy-form input[type="week"], .wy-form input[type="number"], .wy-form input[type="search"], .wy-form input[type="tel"], .wy-form input[type="color"] { - margin-bottom: 0; - } - - .wy-form-aligned .wy-control-group label { - margin-bottom: 0.3em; - text-align: left; - display: block; - width: 100%; - } - .wy-form-aligned .wy-control { - margin: 1.5em 0 0 0; - } - - .wy-form .wy-help-inline, .wy-form-message-inline, .wy-form-message { - display: block; - font-size: 80%; - padding: 6px 0; - } -} -@media screen and (max-width: 768px) { - .tablet-hide { - display: none; - } -} - -@media screen and (max-width: 480px) { - .mobile-hide { - display: none; - } -} - -.float-left { - float: left; -} - -.float-right { - float: right; -} - -.full-width { - width: 100%; -} - -.wy-table, .rst-content table.docutils, .rst-content table.field-list { - border-collapse: collapse; - border-spacing: 0; - empty-cells: show; - margin-bottom: 24px; -} -.wy-table caption, .rst-content table.docutils caption, .rst-content table.field-list caption { - color: #000; - font: italic 85%/1 arial, sans-serif; - padding: 1em 0; - text-align: center; -} -.wy-table td, .rst-content table.docutils td, .rst-content table.field-list td, .wy-table th, .rst-content table.docutils th, .rst-content table.field-list th { - font-size: 90%; - margin: 0; - overflow: visible; - padding: 8px 16px; -} -.wy-table td:first-child, .rst-content table.docutils td:first-child, .rst-content table.field-list td:first-child, .wy-table th:first-child, .rst-content table.docutils th:first-child, .rst-content table.field-list th:first-child { - border-left-width: 0; -} -.wy-table thead, .rst-content table.docutils thead, .rst-content table.field-list thead { - color: #000; - text-align: left; - vertical-align: bottom; - white-space: nowrap; -} -.wy-table thead th, .rst-content table.docutils thead th, .rst-content table.field-list thead th { - font-weight: bold; - border-bottom: solid 2px #e1e4e5; -} -.wy-table td, .rst-content table.docutils td, .rst-content table.field-list td { - background-color: transparent; - vertical-align: middle; -} - -.wy-table td p, .rst-content table.docutils td p, .rst-content table.field-list td p { - line-height: 18px; -} -.wy-table td p:last-child, .rst-content table.docutils td p:last-child, .rst-content table.field-list td p:last-child { - margin-bottom: 0; -} - -.wy-table .wy-table-cell-min, .rst-content table.docutils .wy-table-cell-min, .rst-content table.field-list .wy-table-cell-min { - width: 1%; - padding-right: 0; -} -.wy-table .wy-table-cell-min input[type=checkbox], .rst-content table.docutils .wy-table-cell-min input[type=checkbox], .rst-content table.field-list .wy-table-cell-min input[type=checkbox], .wy-table .wy-table-cell-min input[type=checkbox], .rst-content table.docutils .wy-table-cell-min input[type=checkbox], .rst-content table.field-list .wy-table-cell-min input[type=checkbox] { - margin: 0; -} - -.wy-table-secondary { - color: gray; - font-size: 90%; -} - -.wy-table-tertiary { - color: gray; - font-size: 80%; -} - -.wy-table-odd td, .wy-table-striped tr:nth-child(2n-1) td, .rst-content table.docutils:not(.field-list) tr:nth-child(2n-1) td { - background-color: #f3f6f6; -} - -.wy-table-backed { - background-color: #f3f6f6; -} - -/* BORDERED TABLES */ -.wy-table-bordered-all, .rst-content table.docutils { - border: 1px solid #e1e4e5; -} -.wy-table-bordered-all td, .rst-content table.docutils td { - border-bottom: 1px solid #e1e4e5; - border-left: 1px solid #e1e4e5; -} -.wy-table-bordered-all tbody > tr:last-child td, .rst-content table.docutils tbody > tr:last-child td { - border-bottom-width: 0; -} - -.wy-table-bordered { - border: 1px solid #e1e4e5; -} - -.wy-table-bordered-rows td { - border-bottom: 1px solid #e1e4e5; -} -.wy-table-bordered-rows tbody > tr:last-child td { - border-bottom-width: 0; -} - -.wy-table-horizontal tbody > tr:last-child td { - border-bottom-width: 0; -} -.wy-table-horizontal td, .wy-table-horizontal th { - border-width: 0 0 1px 0; - border-bottom: 1px solid #e1e4e5; -} -.wy-table-horizontal tbody > tr:last-child td { - border-bottom-width: 0; -} - -/* RESPONSIVE TABLES */ -.wy-table-responsive { - margin-bottom: 24px; - max-width: 100%; - overflow: auto; -} -.wy-table-responsive table { - margin-bottom: 0 !important; -} -.wy-table-responsive table td, .wy-table-responsive table th { - white-space: nowrap; -} - -a { - color: #60c557; - text-decoration: none; - cursor: pointer; -} -a:hover { - color: #84d27d; -} -a:visited { - color: #36872f; -} - -html { - height: 100%; - overflow-x: hidden; -} - -body { - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - font-weight: normal; - color: #404040; - min-height: 100%; - overflow-x: hidden; - background: #edf0f2; -} - -.wy-text-left { - text-align: left; -} - -.wy-text-center { - text-align: center; -} - -.wy-text-right { - text-align: right; -} - -.wy-text-large { - font-size: 120%; -} - -.wy-text-normal { - font-size: 100%; -} - -.wy-text-small, small { - font-size: 80%; -} - -.wy-text-strike { - text-decoration: line-through; -} - -.wy-text-warning { - color: #E67E22 !important; -} - -a.wy-text-warning:hover { - color: #eb9950 !important; -} - -.wy-text-info { - color: #2980B9 !important; -} - -a.wy-text-info:hover { - color: #409ad5 !important; -} - -.wy-text-success { - color: #84d27d !important; -} - -a.wy-text-success:hover { - color: #a8dfa3 !important; -} - -.wy-text-danger { - color: #E74C3C !important; -} - -a.wy-text-danger:hover { - color: #ed7669 !important; -} - -.wy-text-neutral { - color: #404040 !important; -} - -a.wy-text-neutral:hover { - color: #595959 !important; -} - -h1, h2, .rst-content .toctree-wrapper p.caption, h3, h4, h5, h6, legend { - margin-top: 0; - font-weight: 700; - font-family: "Roboto Slab", "ff-tisa-web-pro", "Georgia", Arial, sans-serif; -} - -p { - line-height: 24px; - margin: 0; - font-size: 16px; - margin-bottom: 24px; -} - -h1 { - font-size: 175%; -} - -h2, .rst-content .toctree-wrapper p.caption { - font-size: 150%; -} - -h3 { - font-size: 125%; -} - -h4 { - font-size: 115%; -} - -h5 { - font-size: 110%; -} - -h6 { - font-size: 100%; -} - -hr { - display: block; - height: 1px; - border: 0; - border-top: 1px solid #e1e4e5; - margin: 24px 0; - padding: 0; -} - -code, .rst-content tt, .rst-content code { - white-space: nowrap; - max-width: 100%; - background: #fff; - border: solid 1px #e1e4e5; - font-size: 75%; - padding: 0 5px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; - color: #E74C3C; - overflow-x: auto; -} -code.code-large, .rst-content tt.code-large { - font-size: 90%; -} - -.wy-plain-list-disc, .rst-content .section ul, .rst-content .toctree-wrapper ul, article ul { - list-style: disc; - line-height: 24px; - margin-bottom: 24px; -} -.wy-plain-list-disc li, .rst-content .section ul li, .rst-content .toctree-wrapper ul li, article ul li { - list-style: disc; - margin-left: 24px; -} -.wy-plain-list-disc li p:last-child, .rst-content .section ul li p:last-child, .rst-content .toctree-wrapper ul li p:last-child, article ul li p:last-child { - margin-bottom: 0; -} -.wy-plain-list-disc li ul, .rst-content .section ul li ul, .rst-content .toctree-wrapper ul li ul, article ul li ul { - margin-bottom: 0; -} -.wy-plain-list-disc li li, .rst-content .section ul li li, .rst-content .toctree-wrapper ul li li, article ul li li { - list-style: circle; -} -.wy-plain-list-disc li li li, .rst-content .section ul li li li, .rst-content .toctree-wrapper ul li li li, article ul li li li { - list-style: square; -} -.wy-plain-list-disc li ol li, .rst-content .section ul li ol li, .rst-content .toctree-wrapper ul li ol li, article ul li ol li { - list-style: decimal; -} - -.wy-plain-list-decimal, .rst-content .section ol, .rst-content ol.arabic, article ol { - list-style: decimal; - line-height: 24px; - margin-bottom: 24px; -} -.wy-plain-list-decimal li, .rst-content .section ol li, .rst-content ol.arabic li, article ol li { - list-style: decimal; - margin-left: 24px; -} -.wy-plain-list-decimal li p:last-child, .rst-content .section ol li p:last-child, .rst-content ol.arabic li p:last-child, article ol li p:last-child { - margin-bottom: 0; -} -.wy-plain-list-decimal li ul, .rst-content .section ol li ul, .rst-content ol.arabic li ul, article ol li ul { - margin-bottom: 0; -} -.wy-plain-list-decimal li ul li, .rst-content .section ol li ul li, .rst-content ol.arabic li ul li, article ol li ul li { - list-style: disc; -} - -.wy-breadcrumbs { - *zoom: 1; -} -.wy-breadcrumbs:before, .wy-breadcrumbs:after { - display: table; - content: ""; -} -.wy-breadcrumbs:after { - clear: both; -} - -.wy-breadcrumbs li { - display: inline-block; -} -.wy-breadcrumbs li.wy-breadcrumbs-aside { - float: right; -} -.wy-breadcrumbs li a { - display: inline-block; - padding: 5px; -} -.wy-breadcrumbs li a:first-child { - padding-left: 0; -} -.wy-breadcrumbs li code, .wy-breadcrumbs li .rst-content tt, .rst-content .wy-breadcrumbs li tt { - padding: 5px; - border: none; - background: none; -} -.wy-breadcrumbs li code.literal, .wy-breadcrumbs li .rst-content tt.literal, .rst-content .wy-breadcrumbs li tt.literal { - color: #404040; -} - -.wy-breadcrumbs-extra { - margin-bottom: 0; - color: #b3b3b3; - font-size: 80%; - display: inline-block; -} - -@media screen and (max-width: 480px) { - .wy-breadcrumbs-extra { - display: none; - } - - .wy-breadcrumbs li.wy-breadcrumbs-aside { - display: none; - } -} -@media print { - .wy-breadcrumbs li.wy-breadcrumbs-aside { - display: none; - } -} -.wy-affix { - position: fixed; - top: 1.618em; -} - -.wy-menu a:hover { - text-decoration: none; -} - -.wy-menu-horiz { - *zoom: 1; -} -.wy-menu-horiz:before, .wy-menu-horiz:after { - display: table; - content: ""; -} -.wy-menu-horiz:after { - clear: both; -} -.wy-menu-horiz ul, .wy-menu-horiz li { - display: inline-block; -} -.wy-menu-horiz li:hover { - background: rgba(255, 255, 255, 0.1); -} -.wy-menu-horiz li.divide-left { - border-left: solid 1px #404040; -} -.wy-menu-horiz li.divide-right { - border-right: solid 1px #404040; -} -.wy-menu-horiz a { - height: 32px; - display: inline-block; - line-height: 32px; - padding: 0 16px; -} - -.wy-menu-vertical { - width: 300px; -} -.wy-menu-vertical header, .wy-menu-vertical p.caption { - height: 32px; - display: inline-block; - line-height: 32px; - padding: 0 1.618em; - margin-bottom: 0; - display: block; - font-weight: bold; - text-transform: uppercase; - font-size: 80%; - color: #6f6f6f; - white-space: nowrap; -} -.wy-menu-vertical ul { - margin-bottom: 0; -} -.wy-menu-vertical li.divide-top { - border-top: solid 1px #404040; -} -.wy-menu-vertical li.divide-bottom { - border-bottom: solid 1px #404040; -} -.wy-menu-vertical li.current { - background: #e3e3e3; -} -.wy-menu-vertical li.current a { - color: gray; - border-right: solid 1px #c9c9c9; - padding: 0.4045em 2.427em; -} -.wy-menu-vertical li.current a:hover { - background: #d6d6d6; -} -.wy-menu-vertical li code, .wy-menu-vertical li .rst-content tt, .rst-content .wy-menu-vertical li tt { - border: none; - background: inherit; - color: inherit; - padding-left: 0; - padding-right: 0; -} -.wy-menu-vertical li span.toctree-expand { - display: block; - float: left; - margin-left: -1.2em; - font-size: 0.8em; - line-height: 1.6em; - color: #4d4d4d; -} -.wy-menu-vertical li.on a, .wy-menu-vertical li.current > a { - color: #404040; - padding: 0.4045em 1.618em; - font-weight: bold; - position: relative; - background: #fcfcfc; - border: none; - padding-left: 1.618em -4px; -} -.wy-menu-vertical li.on a:hover, .wy-menu-vertical li.current > a:hover { - background: #fcfcfc; -} -.wy-menu-vertical li.on a:hover span.toctree-expand, .wy-menu-vertical li.current > a:hover span.toctree-expand { - color: gray; -} -.wy-menu-vertical li.on a span.toctree-expand, .wy-menu-vertical li.current > a span.toctree-expand { - display: block; - font-size: 0.8em; - line-height: 1.6em; - color: #333333; -} -.wy-menu-vertical li.toctree-l1.current > a { - border-bottom: solid 1px #c9c9c9; - border-top: solid 1px #c9c9c9; -} -.wy-menu-vertical li.toctree-l1.current li.toctree-l2 > ul, .wy-menu-vertical li.toctree-l2.current li.toctree-l3 > ul { - display: none; -} -.wy-menu-vertical li.toctree-l1.current li.toctree-l2.current > ul, .wy-menu-vertical li.toctree-l2.current li.toctree-l3.current > ul { - display: block; -} -.wy-menu-vertical li.toctree-l2.current > a { - background: #c9c9c9; - padding: 0.4045em 2.427em; -} -.wy-menu-vertical li.toctree-l2.current li.toctree-l3 > a { - display: block; - background: #c9c9c9; - padding: 0.4045em 4.045em; -} -.wy-menu-vertical li.toctree-l2 a:hover span.toctree-expand { - color: gray; -} -.wy-menu-vertical li.toctree-l2 span.toctree-expand { - color: #a3a3a3; -} -.wy-menu-vertical li.toctree-l3 { - font-size: 0.9em; -} -.wy-menu-vertical li.toctree-l3.current > a { - background: #bdbdbd; - padding: 0.4045em 4.045em; -} -.wy-menu-vertical li.toctree-l3.current li.toctree-l4 > a { - display: block; - background: #bdbdbd; - padding: 0.4045em 5.663em; -} -.wy-menu-vertical li.toctree-l3 a:hover span.toctree-expand { - color: gray; -} -.wy-menu-vertical li.toctree-l3 span.toctree-expand { - color: #969696; -} -.wy-menu-vertical li.toctree-l4 { - font-size: 0.9em; -} -.wy-menu-vertical li.current ul { - display: block; -} -.wy-menu-vertical li ul { - margin-bottom: 0; - display: none; -} -.wy-menu-vertical .local-toc li ul { - display: block; -} -.wy-menu-vertical li ul li a { - margin-bottom: 0; - color: #b3b3b3; - font-weight: normal; -} -.wy-menu-vertical a { - display: inline-block; - line-height: 18px; - padding: 0.4045em 1.618em; - display: block; - position: relative; - font-size: 90%; - color: #b3b3b3; -} -.wy-menu-vertical a:hover { - background-color: #4e4a4a; - cursor: pointer; -} -.wy-menu-vertical a:hover span.toctree-expand { - color: #b3b3b3; -} -.wy-menu-vertical a:active { - background-color: #2980B9; - cursor: pointer; - color: #fff; -} -.wy-menu-vertical a:active span.toctree-expand { - color: #fff; -} - -.wy-side-nav-search { - display: block; - width: 300px; - padding: 0.809em; - margin-bottom: 0.809em; - z-index: 200; - background-color: #484848; - text-align: center; - padding: 0.809em; - display: block; - color: #fcfcfc; - margin-bottom: 0.809em; -} -.wy-side-nav-search input[type=text] { - width: 100%; - border-radius: 50px; - padding: 6px 12px; - border-color: #4ebe44; -} -.wy-side-nav-search img { - display: block; - margin: auto auto 0.809em auto; - height: 45px; - width: 45px; - background-color: #2980B9; - padding: 5px; - border-radius: 100%; -} -.wy-side-nav-search > a, .wy-side-nav-search .wy-dropdown > a { - color: #fcfcfc; - font-size: 100%; - font-weight: bold; - display: inline-block; - padding: 4px 6px; - margin-bottom: 0.809em; -} -.wy-side-nav-search > a:hover, .wy-side-nav-search .wy-dropdown > a:hover { - background: rgba(255, 255, 255, 0.1); -} -.wy-side-nav-search > a img.logo, .wy-side-nav-search .wy-dropdown > a img.logo { - display: block; - margin: 0 auto; - height: auto; - width: auto; - border-radius: 0; - max-width: 100%; - background: rgba(0, 0, 0, 0); -} -.wy-side-nav-search > a.icon img.logo, .wy-side-nav-search .wy-dropdown > a.icon img.logo { - margin-top: 0.85em; -} -.wy-side-nav-search > div.version { - margin-top: -0.4045em; - margin-bottom: 0.809em; - font-weight: normal; - color: rgba(255, 255, 255, 0.3); -} - -.wy-nav .wy-menu-vertical header { - color: #60c557; -} -.wy-nav .wy-menu-vertical a { - color: #b3b3b3; -} -.wy-nav .wy-menu-vertical a:hover { - background-color: #60c557; - color: #fff; -} - -[data-menu-wrap] { - -webkit-transition: all 0.2s ease-in; - -moz-transition: all 0.2s ease-in; - transition: all 0.2s ease-in; - position: absolute; - opacity: 1; - width: 100%; - opacity: 0; -} -[data-menu-wrap].move-center { - left: 0; - right: auto; - opacity: 1; -} -[data-menu-wrap].move-left { - right: auto; - left: -100%; - opacity: 0; -} -[data-menu-wrap].move-right { - right: -100%; - left: auto; - opacity: 0; -} - -.wy-body-for-nav { - background: #fcfcfc; -} - -.wy-grid-for-nav { - position: absolute; - width: 100%; - height: 100%; -} - -.wy-nav-side { - position: fixed; - top: 0; - bottom: 0; - left: 0; - padding-bottom: 2em; - width: 300px; - overflow-x: hidden; - overflow-y: hidden; - min-height: 100%; - background: #343131; - z-index: 200; -} - -.wy-side-scroll { - width: 320px; - position: relative; - overflow-x: hidden; - overflow-y: scroll; - height: 100%; -} - -.wy-nav-top { - display: none; - background: #60c557; - color: #fff; - padding: 0.4045em 0.809em; - position: relative; - line-height: 50px; - text-align: center; - font-size: 100%; - *zoom: 1; -} -.wy-nav-top:before, .wy-nav-top:after { - display: table; - content: ""; -} -.wy-nav-top:after { - clear: both; -} -.wy-nav-top a { - color: #fff; - font-weight: bold; -} -.wy-nav-top img { - margin-right: 12px; - height: 45px; - width: 45px; - background-color: #2980B9; - padding: 5px; - border-radius: 100%; -} -.wy-nav-top i { - font-size: 30px; - float: left; - cursor: pointer; - padding-top: inherit; -} - -.wy-nav-content-wrap { - margin-left: 300px; - background: #fcfcfc; - min-height: 100%; -} - -.wy-nav-content { - padding: 1.618em 3.236em; - height: 100%; - max-width: 800px; - margin: auto; -} - -.wy-body-mask { - position: fixed; - width: 100%; - height: 100%; - background: rgba(0, 0, 0, 0.2); - display: none; - z-index: 499; -} -.wy-body-mask.on { - display: block; -} - -footer { - color: gray; -} -footer p { - margin-bottom: 12px; -} -footer span.commit code, footer span.commit .rst-content tt, .rst-content footer span.commit tt { - padding: 0px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; - font-size: 1em; - background: none; - border: none; - color: gray; -} - -.rst-footer-buttons { - *zoom: 1; -} -.rst-footer-buttons:before, .rst-footer-buttons:after { - width: 100%; -} -.rst-footer-buttons:before, .rst-footer-buttons:after { - display: table; - content: ""; -} -.rst-footer-buttons:after { - clear: both; -} - -.rst-breadcrumbs-buttons { - margin-top: 12px; - *zoom: 1; -} -.rst-breadcrumbs-buttons:before, .rst-breadcrumbs-buttons:after { - display: table; - content: ""; -} -.rst-breadcrumbs-buttons:after { - clear: both; -} - -#search-results .search li { - margin-bottom: 24px; - border-bottom: solid 1px #e1e4e5; - padding-bottom: 24px; -} -#search-results .search li:first-child { - border-top: solid 1px #e1e4e5; - padding-top: 24px; -} -#search-results .search li a { - font-size: 120%; - margin-bottom: 12px; - display: inline-block; -} -#search-results .context { - color: gray; - font-size: 90%; -} - -@media screen and (max-width: 768px) { - .wy-body-for-nav { - background: #fcfcfc; - } - - .wy-nav-top { - display: block; - } - - .wy-nav-side { - left: -300px; - } - .wy-nav-side.shift { - width: 85%; - left: 0; - } - - .wy-side-scroll { - width: auto; - } - - .wy-side-nav-search { - width: auto; - } - - .wy-menu.wy-menu-vertical { - width: auto; - } - - .wy-nav-content-wrap { - margin-left: 0; - } - .wy-nav-content-wrap .wy-nav-content { - padding: 1.618em; - } - .wy-nav-content-wrap.shift { - position: fixed; - min-width: 100%; - left: 85%; - top: 0; - height: 100%; - overflow: hidden; - } -} -@media screen and (min-width: 1100px) { - .wy-nav-content-wrap { - background: rgba(0, 0, 0, 0.05); - } - - .wy-nav-content { - margin: 0; - background: #fcfcfc; - } -} -@media print { - .rst-versions, footer, .wy-nav-side { - display: none; - } - - .wy-nav-content-wrap { - margin-left: 0; - } -} -.rst-versions { - position: fixed; - bottom: 0; - left: 0; - overflow-y: scroll; - width: 300px; - color: #fcfcfc; - background: #1f1d1d; - font-family: "Lato", "proxima-nova", "Helvetica Neue", Arial, sans-serif; - z-index: 400; -} -.rst-versions a { - color: #60c557; - text-decoration: none; -} -.rst-versions .rst-badge-small { - display: none; -} -.rst-versions .rst-current-version { - padding: 12px; - background-color: #272525; - display: block; - text-align: right; - font-size: 90%; - cursor: pointer; - color: #84d27d; - *zoom: 1; -} -.rst-versions .rst-current-version:before, .rst-versions .rst-current-version:after { - display: table; - content: ""; -} -.rst-versions .rst-current-version:after { - clear: both; -} -.rst-versions .rst-current-version .fa, .rst-versions .rst-current-version .wy-menu-vertical li span.toctree-expand, .wy-menu-vertical li .rst-versions .rst-current-version span.toctree-expand, .rst-versions .rst-current-version .rst-content .admonition-title, .rst-content .rst-versions .rst-current-version .admonition-title, .rst-versions .rst-current-version .rst-content h1 .headerlink, .rst-content h1 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h2 .headerlink, .rst-content h2 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h3 .headerlink, .rst-content h3 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h4 .headerlink, .rst-content h4 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h5 .headerlink, .rst-content h5 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content h6 .headerlink, .rst-content h6 .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content dl dt .headerlink, .rst-content dl dt .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content p.caption .headerlink, .rst-content p.caption .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content table > caption .headerlink, .rst-content table > caption .rst-versions .rst-current-version .headerlink, .rst-versions .rst-current-version .rst-content tt.download span:first-child, .rst-content tt.download .rst-versions .rst-current-version span:first-child, .rst-versions .rst-current-version .rst-content code.download span:first-child, .rst-content code.download .rst-versions .rst-current-version span:first-child, .rst-versions .rst-current-version .icon { - color: #fcfcfc; -} -.rst-versions .rst-current-version .fa-book, .rst-versions .rst-current-version .icon-book { - float: left; -} -.rst-versions .rst-current-version .icon-book { - float: left; -} -.rst-versions .rst-current-version.rst-out-of-date { - background-color: #E74C3C; - color: #fff; -} -.rst-versions .rst-current-version.rst-active-old-version { - background-color: #F1C40F; - color: #000; -} -.rst-versions.shift-up { - max-height: 100%; -} -.rst-versions.shift-up .rst-other-versions { - display: block; -} -.rst-versions .rst-other-versions { - font-size: 90%; - padding: 12px; - color: gray; - display: none; -} -.rst-versions .rst-other-versions hr { - display: block; - height: 1px; - border: 0; - margin: 20px 0; - padding: 0; - border-top: solid 1px #413d3d; -} -.rst-versions .rst-other-versions dd { - display: inline-block; - margin: 0; -} -.rst-versions .rst-other-versions dd a { - display: inline-block; - padding: 6px; - color: #fcfcfc; -} -.rst-versions.rst-badge { - width: auto; - bottom: 20px; - right: 20px; - left: auto; - border: none; - max-width: 300px; -} -.rst-versions.rst-badge .icon-book { - float: none; -} -.rst-versions.rst-badge .fa-book, .rst-versions.rst-badge .icon-book { - float: none; -} -.rst-versions.rst-badge.shift-up .rst-current-version { - text-align: right; -} -.rst-versions.rst-badge.shift-up .rst-current-version .fa-book, .rst-versions.rst-badge.shift-up .rst-current-version .icon-book { - float: left; -} -.rst-versions.rst-badge.shift-up .rst-current-version .icon-book { - float: left; -} -.rst-versions.rst-badge .rst-current-version { - width: auto; - height: 30px; - line-height: 30px; - padding: 0 6px; - display: block; - text-align: center; -} - -@media screen and (max-width: 768px) { - .rst-versions { - width: 85%; - display: none; - } - .rst-versions.shift { - display: block; - } -} -.rst-content img { - max-width: 100%; - height: auto; -} -.rst-content div.figure { - margin-bottom: 24px; -} -.rst-content div.figure p.caption { - font-style: italic; -} -.rst-content div.figure p:last-child.caption { - margin-bottom: 0px; -} -.rst-content div.figure.align-center { - text-align: center; -} -.rst-content .section > img, .rst-content .section > a > img { - margin-bottom: 24px; -} -.rst-content abbr[title] { - text-decoration: none; -} -.rst-content.style-external-links a.reference.external:after { - font-family: FontAwesome; - content: ""; - color: #b3b3b3; - vertical-align: super; - font-size: 60%; - margin: 0 0.2em; -} -.rst-content blockquote { - margin-left: 24px; - line-height: 24px; - margin-bottom: 24px; -} -.rst-content pre.literal-block, .rst-content div[class^='highlight'] { - border: 1px solid #e1e4e5; - padding: 0px; - overflow-x: auto; - margin: 1px 0 24px 0; -} -.rst-content pre.literal-block div[class^='highlight'], .rst-content div[class^='highlight'] div[class^='highlight'] { - border: none; - margin: 0; -} -.rst-content div[class^='highlight'] td.code { - width: 100%; -} -.rst-content .linenodiv pre { - border-right: solid 1px #e6e9ea; - margin: 0; - padding: 12px 12px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; -} -.rst-content div[class^='highlight'] pre { - white-space: pre; - margin: 0; - padding: 12px 12px; - font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; - display: block; - overflow: auto; -} -.rst-content pre.literal-block, .rst-content div[class^='highlight'] pre, .rst-content .linenodiv pre { - font-size: 12px; - line-height: normal; -} -@media print { - .rst-content .codeblock, .rst-content div[class^='highlight'], .rst-content div[class^='highlight'] pre { - white-space: pre-wrap; - } -} -.rst-content .note .last, .rst-content .attention .last, .rst-content .caution .last, .rst-content .danger .last, .rst-content .error .last, .rst-content .hint .last, .rst-content .important .last, .rst-content .tip .last, .rst-content .warning .last, .rst-content .seealso .last, .rst-content .admonition-todo .last, .rst-content .admonition .last { - margin-bottom: 0; -} -.rst-content .admonition-title:before { - margin-right: 4px; -} -.rst-content .admonition table { - border-color: rgba(0, 0, 0, 0.1); -} -.rst-content .admonition table td, .rst-content .admonition table th { - background: transparent !important; - border-color: rgba(0, 0, 0, 0.1) !important; -} -.rst-content .section ol.loweralpha, .rst-content .section ol.loweralpha li { - list-style: lower-alpha; -} -.rst-content .section ol.upperalpha, .rst-content .section ol.upperalpha li { - list-style: upper-alpha; -} -.rst-content .section ol p, .rst-content .section ul p { - margin-bottom: 12px; -} -.rst-content .line-block { - margin-left: 0px; - margin-bottom: 24px; -} -.rst-content .line-block .line-block { - margin-left: 24px; - margin-bottom: 0px; -} -.rst-content .topic-title { - font-weight: bold; - margin-bottom: 12px; -} -.rst-content .toc-backref { - color: #404040; -} -.rst-content .align-right { - float: right; - margin: 0px 0px 24px 24px; -} -.rst-content .align-left { - float: left; - margin: 0px 24px 24px 0px; -} -.rst-content .align-center { - margin: auto; - display: block; -} -.rst-content h1 .headerlink, .rst-content h2 .headerlink, .rst-content .toctree-wrapper p.caption .headerlink, .rst-content h3 .headerlink, .rst-content h4 .headerlink, .rst-content h5 .headerlink, .rst-content h6 .headerlink, .rst-content dl dt .headerlink, .rst-content p.caption .headerlink, .rst-content table > caption .headerlink { - visibility: hidden; - font-size: 14px; -} -.rst-content h1 .headerlink:after, .rst-content h2 .headerlink:after, .rst-content .toctree-wrapper p.caption .headerlink:after, .rst-content h3 .headerlink:after, .rst-content h4 .headerlink:after, .rst-content h5 .headerlink:after, .rst-content h6 .headerlink:after, .rst-content dl dt .headerlink:after, .rst-content p.caption .headerlink:after, .rst-content table > caption .headerlink:after { - content: ""; - font-family: FontAwesome; -} -.rst-content h1:hover .headerlink:after, .rst-content h2:hover .headerlink:after, .rst-content .toctree-wrapper p.caption:hover .headerlink:after, .rst-content h3:hover .headerlink:after, .rst-content h4:hover .headerlink:after, .rst-content h5:hover .headerlink:after, .rst-content h6:hover .headerlink:after, .rst-content dl dt:hover .headerlink:after, .rst-content p.caption:hover .headerlink:after, .rst-content table > caption:hover .headerlink:after { - visibility: visible; -} -.rst-content table > caption .headerlink:after { - font-size: 12px; -} -.rst-content .centered { - text-align: center; -} -.rst-content .sidebar { - float: right; - width: 40%; - display: block; - margin: 0 0 24px 24px; - padding: 24px; - background: #f3f6f6; - border: solid 1px #e1e4e5; -} -.rst-content .sidebar p, .rst-content .sidebar ul, .rst-content .sidebar dl { - font-size: 90%; -} -.rst-content .sidebar .last { - margin-bottom: 0; -} -.rst-content .sidebar .sidebar-title { - display: block; - font-family: "Roboto Slab", "ff-tisa-web-pro", "Georgia", Arial, sans-serif; - font-weight: bold; - background: #e1e4e5; - padding: 6px 12px; - margin: -24px; - margin-bottom: 24px; - font-size: 100%; -} -.rst-content .highlighted { - background: #F1C40F; - display: inline-block; - font-weight: bold; - padding: 0 6px; -} -.rst-content .footnote-reference, .rst-content .citation-reference { - vertical-align: baseline; - position: relative; - top: -0.4em; - line-height: 0; - font-size: 90%; -} -.rst-content table.docutils.citation, .rst-content table.docutils.footnote { - background: none; - border: none; - color: gray; -} -.rst-content table.docutils.citation td, .rst-content table.docutils.citation tr, .rst-content table.docutils.footnote td, .rst-content table.docutils.footnote tr { - border: none; - background-color: transparent !important; - white-space: normal; -} -.rst-content table.docutils.citation td.label, .rst-content table.docutils.footnote td.label { - padding-left: 0; - padding-right: 0; - vertical-align: top; -} -.rst-content table.docutils.citation tt, .rst-content table.docutils.citation code, .rst-content table.docutils.footnote tt, .rst-content table.docutils.footnote code { - color: #555; -} -.rst-content .wy-table-responsive.citation, .rst-content .wy-table-responsive.footnote { - margin-bottom: 0; -} -.rst-content .wy-table-responsive.citation + :not(.citation), -.rst-content .wy-table-responsive.footnote + :not(.footnote) { - margin-top: 24px; -} -.rst-content .wy-table-responsive.citation:last-child, .rst-content .wy-table-responsive.footnote:last-child { - margin-bottom: 24px; -} -.rst-content table.field-list { - border: none; -} -.rst-content table.field-list td { - border: none; -} -.rst-content table.field-list td > strong { - display: inline-block; -} -.rst-content table.field-list .field-name { - padding-right: 10px; - text-align: left; - white-space: nowrap; -} -.rst-content table.field-list .field-body { - text-align: left; -} -.rst-content tt, .rst-content tt, .rst-content code { - color: #000; - padding: 2px 5px; -} -.rst-content tt big, .rst-content tt em, .rst-content tt big, .rst-content code big, .rst-content tt em, .rst-content code em { - font-size: 100% !important; - line-height: normal; -} -.rst-content tt.literal, .rst-content tt.literal, .rst-content code.literal { - color: #404040; -} -.rst-content tt.xref, a .rst-content tt, .rst-content tt.xref, .rst-content code.xref, a .rst-content tt, a .rst-content code { - font-weight: bold; - color: #36872f; -} -.rst-content a tt, .rst-content a tt, .rst-content a code { - color: #60c557; -} -.rst-content dl { - margin-bottom: 24px; -} -.rst-content dl dt { - font-weight: bold; -} -.rst-content dl p, .rst-content dl table, .rst-content dl ul, .rst-content dl ol { - margin-bottom: 12px !important; -} -.rst-content dl dd { - margin: 0 0 12px 24px; -} -.rst-content dl:not(.docutils) { - margin-bottom: 24px; -} -.rst-content dl:not(.docutils) dt { - display: table; - margin: 6px 0; - font-size: 90%; - line-height: normal; - background: #c8c8c8; - color: #484848; - border-top: solid 3px #7b7b7b; - padding: 6px; - position: relative; -} -.rst-content dl:not(.docutils) dt:before { - color: #7b7b7b; -} -.rst-content dl:not(.docutils) dt .headerlink { - color: #404040; - font-size: 100% !important; -} -.rst-content dl:not(.docutils) dl dt { - margin-bottom: 6px; - border: none; - border-left: solid 3px #cccccc; - background: #f0f0f0; - color: #555; -} -.rst-content dl:not(.docutils) dl dt .headerlink { - color: #404040; - font-size: 100% !important; -} -.rst-content dl:not(.docutils) dt:first-child { - margin-top: 0; -} -.rst-content dl:not(.docutils) tt, .rst-content dl:not(.docutils) tt, .rst-content dl:not(.docutils) code { - font-weight: bold; -} -.rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) tt.descclassname, .rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) code.descname, .rst-content dl:not(.docutils) tt.descclassname, .rst-content dl:not(.docutils) code.descclassname { - background-color: transparent; - border: none; - padding: 0; - font-size: 100% !important; -} -.rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) tt.descname, .rst-content dl:not(.docutils) code.descname { - font-weight: bold; -} -.rst-content dl:not(.docutils) .optional { - display: inline-block; - padding: 0 4px; - color: #000; - font-weight: bold; -} -.rst-content dl:not(.docutils) .property { - display: inline-block; - padding-right: 8px; -} -.rst-content .viewcode-link, .rst-content .viewcode-back { - display: inline-block; - color: #404040; - font-size: 80%; - padding-left: 24px; -} -.rst-content .viewcode-back { - display: block; - float: right; -} -.rst-content p.rubric { - margin-bottom: 12px; - font-weight: bold; -} -.rst-content tt.download, .rst-content code.download { - background: inherit; - padding: inherit; - font-weight: normal; - font-family: inherit; - font-size: inherit; - color: inherit; - border: inherit; - white-space: inherit; -} -.rst-content tt.download span:first-child, .rst-content code.download span:first-child { - -webkit-font-smoothing: subpixel-antialiased; -} -.rst-content tt.download span:first-child:before, .rst-content code.download span:first-child:before { - margin-right: 4px; -} -.rst-content .guilabel { - border: 1px solid #888888; - background: #c8c8c8; - font-size: 80%; - font-weight: 700; - border-radius: 4px; - padding: 2.4px 6px; - margin: auto 2px; -} -.rst-content .versionmodified { - font-style: italic; -} - -@media screen and (max-width: 480px) { - .rst-content .sidebar { - width: 100%; - } -} -span[id*='MathJax-Span'] { - color: #404040; -} - -.math { - text-align: center; -} - -@font-face { - font-family: "Inconsolata"; - font-style: normal; - font-weight: 400; - src: local("Inconsolata"), local("Inconsolata-Regular"), url(../fonts/Inconsolata-Regular.ttf) format("truetype"); -} -@font-face { - font-family: "Inconsolata"; - font-style: normal; - font-weight: 700; - src: local("Inconsolata Bold"), local("Inconsolata-Bold"), url(../fonts/Inconsolata-Bold.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: normal; - font-weight: 400; - src: local("Lato Regular"), local("Lato-Regular"), url(../fonts/Lato-Regular.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: normal; - font-weight: 700; - src: local("Lato Bold"), local("Lato-Bold"), url(../fonts/Lato-Bold.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: italic; - font-weight: 400; - src: local("Lato Italic"), local("Lato-Italic"), url(../fonts/Lato-Italic.ttf) format("truetype"); -} -@font-face { - font-family: "Lato"; - font-style: italic; - font-weight: 700; - src: local("Lato Bold Italic"), local("Lato-BoldItalic"), url(../fonts/Lato-BoldItalic.ttf) format("truetype"); -} -@font-face { - font-family: "Roboto Slab"; - font-style: normal; - font-weight: 400; - src: local("Roboto Slab Regular"), local("RobotoSlab-Regular"), url(../fonts/RobotoSlab-Regular.ttf) format("truetype"); -} -@font-face { - font-family: "Roboto Slab"; - font-style: normal; - font-weight: 700; - src: local("Roboto Slab Bold"), local("RobotoSlab-Bold"), url(../fonts/RobotoSlab-Bold.ttf) format("truetype"); -} - -/*# sourceMappingURL=theme.css.map */ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/css/theme.css.map b/docs/build/_themes/sphinx_rtd_theme/static/css/theme.css.map deleted file mode 100644 index f0d1df4d..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/static/css/theme.css.map +++ /dev/null @@ -1,7 +0,0 @@ -{ -"version": 3, -"mappings": ";AACE,CAAE;ECQI,kBAAoB,EDPJ,UAAU;ECY1B,eAAiB,EDZD,UAAU;EC2B1B,UAAY,ED3BI,UAAU;;;AEFlC,iFAAiF;EAC/E,OAAO,EAAE,KAAK;;;AAEhB,oBAAoB;EAClB,OAAO,EAAE,YAAY;EACrB,QAAQ,EAAE,MAAM;EAChB,KAAK,EAAE,CAAC;;;AAEV,qBAAqB;EACnB,OAAO,EAAE,IAAI;;;AAEf,QAAQ;EACN,OAAO,EAAE,IAAI;;;AAEf,CAAC;EDLO,kBAAoB,ECMd,UAAU;EDDhB,eAAiB,ECCX,UAAU;EDchB,UAAY,ECdN,UAAU;;;AAExB,IAAI;EACF,SAAS,EAAE,IAAI;EACf,wBAAwB,EAAE,IAAI;EAC9B,oBAAoB,EAAE,IAAI;;;AAE5B,IAAI;EACF,MAAM,EAAE,CAAC;;;AAEX,iBAAiB;EACf,OAAO,EAAE,CAAC;;;AAEZ,WAAW;EACT,aAAa,EAAE,UAAU;;;AAE3B,SAAS;EACP,WAAW,EAAE,IAAI;;;AAEnB,UAAU;EACR,MAAM,EAAE,CAAC;;;AAEX,GAAG;EACD,UAAU,EAAE,MAAM;;;AAGpB,GAAG;EACD,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,IAAI;EACX,eAAe,EAAE,IAAI;;;AAEvB,IAAI;EACF,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,IAAI;;;AAEnB,wDAAoB;EAClB,WAAW,EAAE,gBAAgB;EAC7B,YAAY,EAAE,wBAAwB;EACtC,SAAS,EAAE,GAAG;;;AAEhB,GAAG;EACD,WAAW,EAAE,GAAG;;;AAElB,CAAC;EACC,MAAM,EAAE,IAAI;;;AAEd,iBAAiB;EACf,OAAO,EAAE,EAAE;EACX,OAAO,EAAE,IAAI;;;AAEf,KAAK;EACH,SAAS,EAAE,GAAG;;;AAEhB,QAAQ;EACN,SAAS,EAAE,GAAG;EACd,WAAW,EAAE,CAAC;EACd,QAAQ,EAAE,QAAQ;EAClB,cAAc,EAAE,QAAQ;;;AAE1B,GAAG;EACD,GAAG,EAAE,MAAM;;;AAEb,GAAG;EACD,MAAM,EAAE,OAAO;;;AAEjB,UAAU;EACR,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,IAAI;EAChB,gBAAgB,EAAE,IAAI;;;AAExB,EAAE;EACA,UAAU,EAAE,IAAI;;;AAElB,EAAE;EACA,MAAM,EAAE,CAAC;;;AAEX,GAAG;EACD,MAAM,EAAE,CAAC;EACT,sBAAsB,EAAE,OAAO;EAC/B,cAAc,EAAE,MAAM;EACtB,SAAS,EAAE,IAAI;;;AAEjB,cAAc;EACZ,QAAQ,EAAE,MAAM;;;AAElB,MAAM;EACJ,MAAM,EAAE,CAAC;;;AAEX,IAAI;EACF,MAAM,EAAE,CAAC;;;AAEX,QAAQ;EACN,MAAM,EAAE,CAAC;EACT,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;;AAEZ,KAAK;EACH,MAAM,EAAE,OAAO;;;AAEjB,MAAM;EACJ,MAAM,EAAE,CAAC;EACT,YAAY,EAAE,IAAI;EAClB,OAAO,EAAE,CAAC;EACV,WAAW,EAAE,MAAM;;;AAErB,+BAA+B;EAC7B,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,CAAC;EACT,cAAc,EAAE,QAAQ;EACxB,eAAe,EAAE,MAAM;;;AAEzB,aAAa;EACX,WAAW,EAAE,MAAM;;;AAErB,uEAAuE;EACrE,MAAM,EAAE,OAAO;EACf,kBAAkB,EAAE,MAAM;EAC1B,SAAS,EAAE,OAAO;;;AAEpB,iCAAiC;EAC/B,MAAM,EAAE,OAAO;;;AAEjB,2CAA2C;EACzC,UAAU,EAAE,UAAU;EACtB,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,IAAI;;;AAEf,oBAAoB;EAClB,kBAAkB,EAAE,SAAS;EAC7B,eAAe,EAAE,WAAW;EAC5B,kBAAkB,EAAE,WAAW;EAC/B,UAAU,EAAE,WAAW;;;AAEzB,mGAAmG;EACjG,kBAAkB,EAAE,IAAI;;;AAE1B,iDAAiD;EAC/C,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;;AAEZ,QAAQ;EACN,QAAQ,EAAE,IAAI;EACd,cAAc,EAAE,GAAG;EACnB,MAAM,EAAE,QAAQ;;;AAElB,KAAK;EACH,eAAe,EAAE,QAAQ;EACzB,cAAc,EAAE,CAAC;;;AAEnB,EAAE;EACA,cAAc,EAAE,GAAG;;;AAErB,YAAY;EACV,MAAM,EAAE,OAAO;EACf,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,KAAK;EACZ,OAAO,EAAE,OAAO;;;AAElB,GAAG;EACD,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,CAAC;EACT,WAAW,EAAE,MAAM;EACnB,QAAQ,EAAE,MAAM;EAChB,gBAAgB,EAAE,WAAW;EAC7B,iBAAiB,EAAE,SAAS;EAC5B,UAAU,EAAE,IAAI;EAChB,SAAS,EAAE,GAAG;EACd,YAAY,EAAE,CAAC;;;AAEjB,MAAM;EACJ,OAAO,EAAE,IAAI;;;AAEf,OAAO;EACL,OAAO,EAAE,eAAe;EACxB,UAAU,EAAE,MAAM;;;AAEpB,eAAe;EACb,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,aAAa;EACnB,MAAM,EAAE,GAAG;EACX,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,MAAM;EAChB,OAAO,EAAE,CAAC;EACV,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,GAAG;;;AAEZ,iEAAiE;EAC/D,IAAI,EAAE,IAAI;EACV,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,CAAC;EACT,QAAQ,EAAE,OAAO;EACjB,QAAQ,EAAE,MAAM;EAChB,KAAK,EAAE,IAAI;;;AAEb,UAAU;EACR,UAAU,EAAE,MAAM;;;AAEpB,SAAS;EACP,QAAQ,EAAE,QAAQ;;;AAEpB,UAAU;EACR,SAAS,EAAE,IAAI;;;AAEjB,YAAY;EACV,mBAAmB;IACjB,UAAU,EAAE,eAAe;;;EAC7B,CAAC;IACC,UAAU,EAAE,eAAe;IAC3B,WAAW,EAAE,eAAe;IAC5B,MAAM,EAAE,eAAe;IACvB,UAAU,EAAE,eAAe;;;EAC7B,YAAY;IACV,eAAe,EAAE,SAAS;;;EAC5B,6DAA6D;IAC3D,OAAO,EAAE,EAAE;;;EACb,eAAe;IACb,iBAAiB,EAAE,KAAK;;;EAC1B,KAAK;IACH,OAAO,EAAE,kBAAkB;;;EAC7B,OAAO;IACL,iBAAiB,EAAE,KAAK;;;EAC1B,GAAG;IACD,SAAS,EAAE,eAAe;;;;IAE1B,MAAM,EAAE,KAAK;;EAEf,kDAAS;IACP,OAAO,EAAE,CAAC;IACV,MAAM,EAAE,CAAC;;;EACX,+CAAM;IACJ,gBAAgB,EAAE,KAAK;;;AChM3B,mtDAAY;EACV,sBAAsB,EAAE,WAAW;;;AAqDrC,SAAS;EARP,KAAK,EAAE,CAAC;;AACR,iCAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,eAAO;EACL,KAAK,EAAE,IAAI;;;AC7Gf;;;GAGG;ACHH;gCACgC;AAEhC,UAWC;EAVC,WAAW,EAAE,aAAa;EAC1B,GAAG,EAAE,+CAAgE;EACrE,GAAG,EAAE,4WAI8F;EAEnG,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;;ACVpB,6iBAAmB;EACjB,OAAO,EAAE,YAAY;EACrB,IAAI,EAAE,uCAA8E;EACpF,SAAS,EAAE,OAAO;EAClB,cAAc,EAAE,IAAI;EACpB,sBAAsB,EAAE,WAAW;EACnC,uBAAuB,EAAE,SAAS;;;ACNpC,8DAA8D;AAC9D,MAAsB;EACpB,SAAS,EAAE,cAAS;EACpB,WAAW,EAAE,MAAS;EACtB,cAAc,EAAE,IAAI;;;AAEtB,MAAsB;EAAE,SAAS,EAAE,GAAG;;;AACtC,MAAsB;EAAE,SAAS,EAAE,GAAG;;;AACtC,MAAsB;EAAE,SAAS,EAAE,GAAG;;;AACtC,MAAsB;EAAE,SAAS,EAAE,GAAG;;;ACVtC,MAAsB;EACpB,KAAK,EAAE,cAAW;EAClB,UAAU,EAAE,MAAM;;;ACDpB,MAAsB;EACpB,YAAY,EAAE,CAAC;EACf,WAAW,ECMU,cAAS;EDL9B,eAAe,EAAE,IAAI;;AACrB,WAAK;EAAE,QAAQ,EAAE,QAAQ;;;AAE3B,MAAsB;EACpB,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,eAAa;EACnB,KAAK,ECDgB,cAAS;EDE9B,GAAG,EAAE,cAAU;EACf,UAAU,EAAE,MAAM;;AAClB,YAAuB;EACrB,IAAI,EAAE,eAA0B;;;AEbpC,UAA0B;EACxB,OAAO,EAAE,gBAAgB;EACzB,MAAM,EAAE,iBAA4B;EACpC,aAAa,EAAE,IAAI;;;AAGrB,aAA6B;EAAE,KAAK,EAAE,IAAI;;;AAC1C,cAA8B;EAAE,KAAK,EAAE,KAAK;;;AAG1C,0wBAA8B;EAAE,YAAY,EAAE,IAAI;;AAClD,2xBAA+B;EAAE,WAAW,EAAE,IAAI;;;AAGpD,4BAA4B;AAC5B,WAAY;EAAE,KAAK,EAAE,KAAK;;;AAC1B,UAAW;EAAE,KAAK,EAAE,IAAI;;;AAGtB,utBAAY;EAAE,YAAY,EAAE,IAAI;;AAChC,wuBAAa;EAAE,WAAW,EAAE,IAAI;;;ACpBlC,QAAwB;EACtB,iBAAiB,EAAE,0BAA0B;EACrC,SAAS,EAAE,0BAA0B;;;AAG/C,SAAyB;EACvB,iBAAiB,EAAE,4BAA4B;EACvC,SAAS,EAAE,4BAA4B;;;AAGjD,0BASC;EARC,EAAG;IACD,iBAAiB,EAAE,YAAY;IACvB,SAAS,EAAE,YAAY;;EAEjC,IAAK;IACH,iBAAiB,EAAE,cAAc;IACzB,SAAS,EAAE,cAAc;;;AAIrC,kBASC;EARC,EAAG;IACD,iBAAiB,EAAE,YAAY;IACvB,SAAS,EAAE,YAAY;;EAEjC,IAAK;IACH,iBAAiB,EAAE,cAAc;IACzB,SAAS,EAAE,cAAc;;;AC5BrC,aAA8B;ECW5B,UAAU,EAAE,0DAAqE;EACjF,iBAAiB,EAAE,aAAgB;EAC/B,aAAa,EAAE,aAAgB;EAC3B,SAAS,EAAE,aAAgB;;;ADbrC,cAA8B;ECU5B,UAAU,EAAE,0DAAqE;EACjF,iBAAiB,EAAE,cAAgB;EAC/B,aAAa,EAAE,cAAgB;EAC3B,SAAS,EAAE,cAAgB;;;ADZrC,cAA8B;ECS5B,UAAU,EAAE,0DAAqE;EACjF,iBAAiB,EAAE,cAAgB;EAC/B,aAAa,EAAE,cAAgB;EAC3B,SAAS,EAAE,cAAgB;;;ADVrC,mBAAmC;ECcjC,UAAU,EAAE,oEAA+E;EAC3F,iBAAiB,EAAE,YAAoB;EACnC,aAAa,EAAE,YAAoB;EAC/B,SAAS,EAAE,YAAoB;;;ADhBzC,iBAAmC;ECajC,UAAU,EAAE,oEAA+E;EAC3F,iBAAiB,EAAE,YAAoB;EACnC,aAAa,EAAE,YAAoB;EAC/B,SAAS,EAAE,YAAoB;;;ADXzC;;;;uBAIuC;EACrC,MAAM,EAAE,IAAI;;;AEfd,SAAyB;EACvB,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,YAAY;EACrB,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,GAAG;EACX,WAAW,EAAE,GAAG;EAChB,cAAc,EAAE,MAAM;;;AAExB,0BAAyD;EACvD,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,CAAC;EACP,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,MAAM;;;AAEpB,YAA4B;EAAE,WAAW,EAAE,OAAO;;;AAClD,YAA4B;EAAE,SAAS,EAAE,GAAG;;;AAC5C,WAA2B;EAAE,KAAK,ELTZ,IAAI;;;AMV1B;oEACoE;AAEpE,gBAAgC;EAAE,OAAO,ENwU1B,GAAO;;;AMvUtB,gBAAgC;EAAE,OAAO,EN2d1B,GAAO;;;AM1dtB,sCAAiC;EAAE,OAAO,EN0jB1B,GAAO;;;AMzjBvB,qBAAqC;EAAE,OAAO,ENsO1B,GAAO;;;AMrO3B,gBAAgC;EAAE,OAAO,ENuW1B,GAAO;;;AMtWtB,eAA+B;EAAE,OAAO,ENknB1B,GAAO;;;AMjnBrB,iBAAiC;EAAE,OAAO,ENsnB1B,GAAO;;;AMrnBvB,eAA+B;EAAE,OAAO,ENytB1B,GAAO;;;AMxtBrB,eAA+B;EAAE,OAAO,ENmR1B,GAAO;;;AMlRrB,mBAAmC;EAAE,OAAO,ENupB1B,GAAO;;;AMtpBzB,aAA6B;EAAE,OAAO,ENqpB1B,GAAO;;;AMppBnB,kBAAkC;EAAE,OAAO,ENspB1B,GAAO;;;AMrpBxB,gBAAgC;EAAE,OAAO,ENyI1B,GAAO;;;AMxItB;;gBAEgC;EAAE,OAAO,ENqqB1B,GAAO;;;AMpqBtB,sBAAsC;EAAE,OAAO,EN8iB1B,GAAO;;;AM7iB5B,uBAAuC;EAAE,OAAO,EN4iB1B,GAAO;;;AM3iB7B,oBAAoC;EAAE,OAAO,EN4f1B,GAAO;;;AM3f1B,iBAAiC;EAAE,OAAO,ENikB1B,GAAO;;;AMhkBvB;cAC8B;EAAE,OAAO,ENgK1B,GAAO;;;AM/JpB,kBAAkC;EAAE,OAAO,EN+qB1B,GAAO;;;AM9qBxB,kCAA+B;EAAE,OAAO,ENwV1B,GAAO;;;AMvVrB,iBAAiC;EAAE,OAAO,ENuP1B,GAAO;;;AMtPvB,kBAAkC;EAAE,OAAO,ENgJ1B,GAAO;;;AM/IxB,eAA+B;EAAE,OAAO,ENmhB1B,GAAO;;;AMlhBrB,yHAAmC;EAAE,OAAO,ENgM1B,GAAO;;;AM/LzB,8BAA8C;EAAE,OAAO,ENY1B,GAAO;;;AMXpC,4BAA4C;EAAE,OAAO,ENc1B,GAAO;;;AMblC,gBAAgC;EAAE,OAAO,ENqW1B,GAAO;;;AMpWtB,wBAAwC;EAAE,OAAO,ENwe1B,GAAO;;;AMve9B;iBACiC;EAAE,OAAO,ENsgB1B,GAAO;;;AMrgBvB,kBAAkC;EAAE,OAAO,ENggB1B,GAAO;;;AM/fxB,mBAAmC;EAAE,OAAO,ENwY1B,GAAO;;;AMvYzB,eAA+B;EAAE,OAAO,EN2Y1B,GAAO;;;AM1YrB,eAA+B;EAAE,OAAO,EN4P1B,GAAO;;;AM3PrB,qBAAqC;EAAE,OAAO,ENoU1B,GAAO;;;AMnU3B,qBAAqC;EAAE,OAAO,ENitB1B,GAAO;;;AMhtB3B,sBAAsC;EAAE,OAAO,EN+sB1B,GAAO;;;AM9sB5B,oBAAoC;EAAE,OAAO,ENgtB1B,GAAO;;;AM/sB1B,iBAAiC;EAAE,OAAO,ENye1B,GAAO;;;AMxevB,kBAAkC;EAAE,OAAO,ENwB1B,GAAO;;;AMvBxB,cAA8B;EAAE,OAAO,ENymB1B,GAAO;;;AMxmBpB,eAA+B;EAAE,OAAO,ENymB1B,GAAO;;;AMxmBrB,kCAA+B;EAAE,OAAO,ENyD1B,GAAO;;;AMxDrB,mBAAmC;EAAE,OAAO,ENyD1B,GAAO;;;AMxDzB,gBAAgC;EAAE,OAAO,EN+d1B,GAAO;;;AM9dtB,iBAAiC;EAAE,OAAO,EN2E1B,GAAO;;;AM1EvB,eAA+B;EAAE,OAAO,EN0P1B,GAAO;;;AMzPrB,eAA+B;EAAE,OAAO,ENiD1B,GAAO;;;AMhDrB,iBAAiC;EAAE,OAAO,EN0V1B,GAAO;;;AMzVvB,sBAAsC;EAAE,OAAO,ENwmB1B,GAAO;;;AMvmB5B,qBAAqC;EAAE,OAAO,ENwmB1B,GAAO;;;AMvmB3B,qBAAqC;EAAE,OAAO,ENpC1B,GAAO;;;AMqC3B,uBAAuC;EAAE,OAAO,ENvC1B,GAAO;;;AMwC7B,sBAAsC;EAAE,OAAO,ENrC1B,GAAO;;;AMsC5B,wBAAwC;EAAE,OAAO,ENxC1B,GAAO;;;AMyC9B,eAA+B;EAAE,OAAO,EN+W1B,GAAO;;;AM9WrB;kBACkC;EAAE,OAAO,EN2a1B,GAAO;;;AM1axB,iBAAiC;EAAE,OAAO,ENsU1B,GAAO;;;AMrUvB,uBAAuC;EAAE,OAAO,ENkrB1B,GAAO;;;AMjrB7B;;oBAEoC;EAAE,OAAO,EN0b1B,GAAO;;;AMzb1B,iBAAiC;EAAE,OAAO,ENkb1B,GAAO;;;AMjbvB,qBAAqC;EAAE,OAAO,ENwX1B,GAAO;;;AMvX3B,iBAAiC;EAAE,OAAO,ENtD1B,GAAO;;;AMuDvB,eAA+B;EAAE,OAAO,ENmnB1B,GAAO;;;AMlnBrB;0BAC0C;EAAE,OAAO,EN+a1B,GAAO;;;AM9ahC,yBAAyC;EAAE,OAAO,EN8f1B,GAAO;;;AM7f/B,yBAAyC;EAAE,OAAO,EN+E1B,GAAO;;;AM9E/B,iBAAiC;EAAE,OAAO,ENzB1B,GAAO;;;AM0BvB,wBAAwC;EAAE,OAAO,ENmjB1B,GAAO;;;AMljB9B,wBAAwC;EAAE,OAAO,ENqL1B,GAAO;;;AMpL9B,mBAAmC;EAAE,OAAO,ENlB1B,GAAO;;;AMmBzB,eAA+B;EAAE,OAAO,ENsb1B,GAAO;;;AMrbrB,gBAAgC;EAAE,OAAO,ENga1B,GAAO;;;AM/ZtB,eAA+B;EAAE,OAAO,ENmjB1B,GAAO;;;AMljBrB,kBAAkC;EAAE,OAAO,EN+N1B,GAAO;;;AM9NxB,uBAAuC;EAAE,OAAO,ENgL1B,GAAO;;;AM/K7B,uBAAuC;EAAE,OAAO,EN4iB1B,GAAO;;;AM3iB7B,gBAAgC;EAAE,OAAO,EN+I1B,GAAO;;;AM9ItB,uBAAuC;EAAE,OAAO,ENyE1B,GAAO;;;AMxE7B,wBAAwC;EAAE,OAAO,ENyE1B,GAAO;;;AMxE9B,sBAAsC;EAAE,OAAO,ENkb1B,GAAO;;;AMjb5B,uBAAuC;EAAE,OAAO,ENuX1B,GAAO;;;AMtX7B,+FAAuC;EAAE,OAAO,EN2lB1B,GAAO;;;AM1lB7B,gGAAuC;EAAE,OAAO,EN2D1B,GAAO;;;AM1D7B,0BAA0C;EAAE,OAAO,ENyb1B,GAAO;;;AMxbhC,sBAAsC;EAAE,OAAO,EN0S1B,GAAO;;;AMzS5B,qBAAqC;EAAE,OAAO,EN0G1B,GAAO;;;AMzG3B,yBAAyC;EAAE,OAAO,ENulB1B,GAAO;;;AMtlB/B,yBAAyC;EAAE,OAAO,ENuD1B,GAAO;;;AMtD/B,cAA8B;EAAE,OAAO,ENnC1B,GAAO;;;AMoCpB,qBAAqC;EAAE,OAAO,ENnD1B,GAAO;;;AMoD3B,sBAAsC;EAAE,OAAO,ENnD1B,GAAO;;;AMoD5B,mBAAmC;EAAE,OAAO,ENnD1B,GAAO;;;AMoDzB,qBAAqC;EAAE,OAAO,ENvD1B,GAAO;;;AMwD3B;gBACgC;EAAE,OAAO,EN4d1B,GAAO;;;AM3dtB,iBAAiC;EAAE,OAAO,EN8I1B,GAAO;;;AM7IvB,mBAAmC;EAAE,OAAO,ENsF1B,GAAO;;;AMrFzB,eAA+B;EAAE,OAAO,EN+Z1B,GAAO;;;AM9ZrB,gBAAgC;EAAE,OAAO,ENoW1B,GAAO;;;AMnWtB,mBAAmC;EAAE,OAAO,ENpD1B,GAAO;;;AMqDzB,mNAA6C;EAAE,OAAO,ENuI1B,GAAO;;;AMtInC,eAA+B;EAAE,OAAO,ENkN1B,GAAO;;;AMjNrB,eAA+B;EAAE,OAAO,EN0S1B,GAAO;;;AMzSrB,kCAA+B;EAAE,OAAO,EN6K1B,GAAO;;;AM5KrB,cAA8B;EAAE,OAAO,ENyI1B,GAAO;;;AMxIpB,oBAAoC;EAAE,OAAO,ENyI1B,GAAO;;;AMxI1B;+BAC+C;EAAE,OAAO,ENiI1B,GAAO;;;AMhIrC,gBAAgC;EAAE,OAAO,EN+Y1B,GAAO;;;AM9YtB,mBAAmC;EAAE,OAAO,ENA1B,GAAO;;;AMCzB,iBAAiC;EAAE,OAAO,ENoa1B,GAAO;;;AMnavB,kBAAkC;EAAE,OAAO,ENgE1B,GAAO;;;AM/DxB,iBAAiC;EAAE,OAAO,EN6T1B,GAAO;;;AM5TvB,qBAAqC;EAAE,OAAO,ENuC1B,GAAO;;;AMtC3B,uBAAuC;EAAE,OAAO,ENmC1B,GAAO;;;AMlC7B,kBAAkC;EAAE,OAAO,EN+a1B,GAAO;;;AM9axB,wBAAwC;EAAE,OAAO,ENkd1B,GAAO;;;AMjd9B,iBAAiC;EAAE,OAAO,EN0K1B,GAAO;;;AMzKvB,sBAAsC;EAAE,OAAO,EN2K1B,GAAO;;;AM1K5B,mBAAmC;EAAE,OAAO,EN3E1B,GAAO;;;AM4EzB,mBAAmC;EAAE,OAAO,EN7E1B,GAAO;;;AM8EzB;oBACoC;EAAE,OAAO,ENlE1B,GAAO;;;AMmE1B,yBAAyC;EAAE,OAAO,EN+kB1B,GAAO;;;AM9kB/B,0BAA0C;EAAE,OAAO,EN4H1B,GAAO;;;AM3HhC,uBAAuC;EAAE,OAAO,ENT1B,GAAO;;;AMU7B,cAA8B;EAAE,OAAO,EN2Q1B,GAAO;;;AM1QpB;eAC+B;EAAE,OAAO,EN6C1B,GAAO;;;AM5CrB,mBAAmC;EAAE,OAAO,ENkD1B,GAAO;;;AMjDzB,sBAAsC;EAAE,OAAO,ENsiB1B,GAAO;;;AMriB5B,wBAAwC;EAAE,OAAO,ENoiB1B,GAAO;;;AMniB9B,oBAAoC;EAAE,OAAO,EN2e1B,GAAO;;;AM1e1B,kBAAkC;EAAE,OAAO,EN8N1B,GAAO;;;AM7NxB,mBAAmC;EAAE,OAAO,ENoc1B,GAAO;;;AMnczB,0BAA0C;EAAE,OAAO,ENuR1B,GAAO;;;AMtRhC,qBAAqC;EAAE,OAAO,EN6hB1B,GAAO;;;AM5hB3B,wBAAwC;EAAE,OAAO,ENsG1B,GAAO;;;AMrG9B,kBAAkC;EAAE,OAAO,EN8b1B,GAAO;;;AM7bxB,iBAAiC;EAAE,OAAO,ENqjB1B,GAAO;;;AMpjBvB,wBAAwC;EAAE,OAAO,ENgL1B,GAAO;;;AM/K9B,iBAAiC;EAAE,OAAO,ENukB1B,GAAO;;;AMtkBvB,kBAAkC;EAAE,OAAO,ENqQ1B,GAAO;;;AMpQxB,gBAAgC;EAAE,OAAO,ENiW1B,GAAO;;;AMhWtB,mBAAmC;EAAE,OAAO,EN2d1B,GAAO;;;AM1dzB,qBAAqC;EAAE,OAAO,ENjD1B,GAAO;;;AMkD3B,uBAAuC;EAAE,OAAO,EN+V1B,GAAO;;;AM9V7B,kBAAkC;EAAE,OAAO,ENsjB1B,GAAO;;;AMrjBxB;mBACmC;EAAE,OAAO,ENgG1B,GAAO;;;AM/FzB,sCAAiC;EAAE,OAAO,ENoK1B,GAAO;;;AMnKvB,iBAAiC;EAAE,OAAO,EN0jB1B,GAAO;;;AMzjBvB,sBAAsC;EAAE,OAAO,ENoC1B,GAAO;;;AMnC5B;cAC8B;EAAE,OAAO,EN+Y1B,GAAO;;;AM9YpB,gBAAgC;EAAE,OAAO,ENoM1B,GAAO;;;AMnMtB,mBAAmC;EAAE,OAAO,ENrD1B,GAAO;;;AMsDzB,eAA+B;EAAE,OAAO,ENhF1B,GAAO;;;AMiFrB,sBAAsC;EAAE,OAAO,ENrB1B,GAAO;;;AMsB5B,uBAAuC;EAAE,OAAO,ENoL1B,GAAO;;;AMnL7B,sBAAsC;EAAE,OAAO,ENkL1B,GAAO;;;AMjL5B,oBAAoC;EAAE,OAAO,ENmL1B,GAAO;;;AMlL1B,sBAAsC;EAAE,OAAO,EN+K1B,GAAO;;;AM9K5B,4DAA4C;EAAE,OAAO,ENrI1B,GAAO;;;AMsIlC,8DAA6C;EAAE,OAAO,ENjI1B,GAAO;;;AMkInC,0BAA0C;EAAE,OAAO,ENjI1B,GAAO;;;AMkIhC,4BAA4C;EAAE,OAAO,ENzI1B,GAAO;;;AM0IlC,gBAAgC;EAAE,OAAO,EN2J1B,GAAO;;;AM1JtB,iBAAiC;EAAE,OAAO,EN6lB1B,GAAO;;;AM5lBvB,gBAAgC;EAAE,OAAO,ENqe1B,GAAO;;;AMpetB,iBAAiC;EAAE,OAAO,ENyG1B,GAAO;;;AMxGvB,oBAAoC;EAAE,OAAO,ENzE1B,GAAO;;;AM0E1B,qBAAqC;EAAE,OAAO,ENlI1B,GAAO;;;AMmI3B;gBACgC;EAAE,OAAO,ENijB1B,GAAO;;;AMhjBtB;;iBAC+B;EAAE,OAAO,EN4O1B,GAAO;;;AM3OrB,gBAAgC;EAAE,OAAO,ENd1B,GAAO;;;AMetB,gBAAgC;EAAE,OAAO,EN0G1B,GAAO;;;AMzGtB;mBACmC;EAAE,OAAO,EN6X1B,GAAO;;;AM5XzB;kBACkC;EAAE,OAAO,EN2F1B,GAAO;;;AM1FxB,oBAAoC;EAAE,OAAO,EN6S1B,GAAO;;;AM5S1B;mBACmC;EAAE,OAAO,ENqG1B,GAAO;;;AMpGzB,iBAAiC;EAAE,OAAO,ENgb1B,GAAO;;;AM/avB;;eAE+B;EAAE,OAAO,ENlI1B,GAAO;;;AMmIrB,kBAAkC;EAAE,OAAO,ENsO1B,GAAO;;;AMrOxB,kBAAkC;EAAE,OAAO,ENoO1B,GAAO;;;AMnOxB,wBAAwC;EAAE,OAAO,EN+b1B,GAAO;;;AM9b9B,oBAAoC;EAAE,OAAO,EN2gB1B,GAAO;;;AM1gB1B,gBAAgC;EAAE,OAAO,ENuc1B,GAAO;;;AMtctB,gBAAgC;EAAE,OAAO,ENyO1B,GAAO;;;AMxOtB,gBAAgC;EAAE,OAAO,EN6f1B,GAAO;;;AM5ftB,oBAAoC;EAAE,OAAO,ENmT1B,GAAO;;;AMlT1B,2BAA2C;EAAE,OAAO,ENoT1B,GAAO;;;AMnTjC,6BAA6C;EAAE,OAAO,ENgI1B,GAAO;;;AM/HnC,sBAAsC;EAAE,OAAO,EN4H1B,GAAO;;;AM3H5B,gBAAgC;EAAE,OAAO,ENqQ1B,GAAO;;;AMpQtB,0EAAqC;EAAE,OAAO,ENpF1B,GAAO;;;AMqF3B,mBAAmC;EAAE,OAAO,EN9E1B,GAAO;;;AM+EzB,qBAAqC;EAAE,OAAO,ENrF1B,GAAO;;;AMsF3B,sBAAsC;EAAE,OAAO,ENrF1B,GAAO;;;AMsF5B,kBAAkC;EAAE,OAAO,ENhC1B,GAAO;;;AMiCxB;eAC+B;EAAE,OAAO,EN0Y1B,GAAO;;;AMzYrB;oBACoC;EAAE,OAAO,EN8Y1B,GAAO;;;AM7Y1B;mBACmC;EAAE,OAAO,EN2Y1B,GAAO;;;AM1YzB,mBAAmC;EAAE,OAAO,ENU1B,GAAO;;;AMTzB,mBAAmC;EAAE,OAAO,ENuM1B,GAAO;;;AMtMzB;eAC+B;EAAE,OAAO,ENqf1B,GAAO;;;AMpfrB;gBACgC;EAAE,OAAO,ENoF1B,GAAO;;;AMnFtB;qBACqC;EAAE,OAAO,EN+a1B,GAAO;;;AM9a3B,oBAAoC;EAAE,OAAO,EN7C1B,GAAO;;;AM8C1B,qBAAqC;EAAE,OAAO,EN1C1B,GAAO;;;AM2C3B;eAC+B;EAAE,OAAO,ENpI1B,GAAO;;;AMqIrB,kBAAkC;EAAE,OAAO,EN6W1B,GAAO;;;AM5WxB,mBAAmC;EAAE,OAAO,ENye1B,GAAO;;;AMxezB;oBACoC;EAAE,OAAO,ENrE1B,GAAO;;;AMsE1B,sBAAsC;EAAE,OAAO,ENqL1B,GAAO;;;AMpL5B,mBAAmC;EAAE,OAAO,ENG1B,GAAO;;;AMFzB,yBAAyC;EAAE,OAAO,ENnE1B,GAAO;;;AMoE/B,uBAAuC;EAAE,OAAO,ENnE1B,GAAO;;;AMoE7B,kBAAkC;EAAE,OAAO,ENif1B,GAAO;;;AMhfxB,sBAAsC;EAAE,OAAO,EN8Y1B,GAAO;;;AM7Y5B,mBAAmC;EAAE,OAAO,ENyZ1B,GAAO;;;AMxZzB,iBAAiC;EAAE,OAAO,EN9J1B,GAAO;;;AM+JvB,iBAAiC;EAAE,OAAO,ENlE1B,GAAO;;;AMmEvB,kBAAkC;EAAE,OAAO,EN1C1B,GAAO;;;AM2CxB,sBAAsC;EAAE,OAAO,EN8B1B,GAAO;;;AM7B5B,qBAAqC;EAAE,OAAO,EN1I1B,GAAO;;;AM2I3B,qBAAqC;EAAE,OAAO,ENsH1B,GAAO;;;AMrH3B,oBAAoC;EAAE,OAAO,ENrO1B,GAAO;;;AMsO1B,iBAAiC;EAAE,OAAO,EN4M1B,GAAO;;;AM3MvB,sBAAsC;EAAE,OAAO,ENU1B,GAAO;;;AMT5B,eAA+B;EAAE,OAAO,EN3K1B,GAAO;;;AM4KrB,mBAAmC;EAAE,OAAO,ENuF1B,GAAO;;;AMtFzB,sBAAsC;EAAE,OAAO,EN2Q1B,GAAO;;;AM1Q5B,4BAA4C;EAAE,OAAO,ENrO1B,GAAO;;;AMsOlC,6BAA6C;EAAE,OAAO,ENrO1B,GAAO;;;AMsOnC,0BAA0C;EAAE,OAAO,ENrO1B,GAAO;;;AMsOhC,4BAA4C;EAAE,OAAO,ENzO1B,GAAO;;;AM0OlC,qBAAqC;EAAE,OAAO,ENrO1B,GAAO;;;AMsO3B,sBAAsC;EAAE,OAAO,ENrO1B,GAAO;;;AMsO5B,mBAAmC;EAAE,OAAO,ENrO1B,GAAO;;;AMsOzB,qBAAqC;EAAE,OAAO,ENzO1B,GAAO;;;AM0O3B,kBAAkC;EAAE,OAAO,ENpD1B,GAAO;;;AMqDxB,iBAAiC;EAAE,OAAO,EN4I1B,GAAO;;;AM3IvB,iBAAiC;EAAE,OAAO,ENwY1B,GAAO;;;AMvYvB;iBACiC;EAAE,OAAO,ENuM1B,GAAO;;;AMtMvB,mBAAmC;EAAE,OAAO,ENzG1B,GAAO;;;AM0GzB,qBAAqC;EAAE,OAAO,ENyQ1B,GAAO;;;AMxQ3B,sBAAsC;EAAE,OAAO,ENyQ1B,GAAO;;;AMxQ5B,kBAAkC;EAAE,OAAO,EN+V1B,GAAO;;;AM9VxB,iBAAiC;EAAE,OAAO,EN9G1B,GAAO;;;AM+GvB;gBACgC;EAAE,OAAO,ENoR1B,GAAO;;;AMnRtB,qBAAqC;EAAE,OAAO,EN+C1B,GAAO;;;AM9C3B,mBAAmC;EAAE,OAAO,ENmB1B,GAAO;;;AMlBzB,wBAAwC;EAAE,OAAO,ENoB1B,GAAO;;;AMnB9B,kBAAkC;EAAE,OAAO,ENqU1B,GAAO;;;AMpUxB,kBAAkC;EAAE,OAAO,EN2B1B,GAAO;;;AM1BxB,gBAAgC;EAAE,OAAO,ENgL1B,GAAO;;;AM/KtB,kBAAkC;EAAE,OAAO,EN2B1B,GAAO;;;AM1BxB,qBAAqC;EAAE,OAAO,ENuH1B,GAAO;;;AMtH3B,iBAAiC;EAAE,OAAO,ENM1B,GAAO;;;AMLvB,yBAAyC;EAAE,OAAO,ENI1B,GAAO;;;AMH/B,mBAAmC;EAAE,OAAO,EN6X1B,GAAO;;;AM5XzB,eAA+B;EAAE,OAAO,ENhH1B,GAAO;;;AMiHrB;oBACoC;EAAE,OAAO,ENuQ1B,GAAO;;;AMtQ1B;;sBAEsC;EAAE,OAAO,ENsV1B,GAAO;;;AMrV5B,yBAAyC;EAAE,OAAO,ENwI1B,GAAO;;;AMvI/B,eAA+B;EAAE,OAAO,ENhG1B,GAAO;;;AMiGrB,oBAAoC;EAAE,OAAO,ENvH1B,GAAO;;;AMwH1B;uBACuC;EAAE,OAAO,ENtJ1B,GAAO;;;AMuJ7B,mBAAmC;EAAE,OAAO,ENyO1B,GAAO;;;AMxOzB,eAA+B;EAAE,OAAO,EN0F1B,GAAO;;;AMzFrB,sBAAsC;EAAE,OAAO,EN1D1B,GAAO;;;AM2D5B,sBAAsC;EAAE,OAAO,ENkW1B,GAAO;;;AMjW5B,oBAAoC;EAAE,OAAO,EN4V1B,GAAO;;;AM3V1B,iBAAiC;EAAE,OAAO,ENlE1B,GAAO;;;AMmEvB,uBAAuC;EAAE,OAAO,ENgO1B,GAAO;;;AM/N7B,qBAAqC;EAAE,OAAO,EN2J1B,GAAO;;;AM1J3B,2BAA2C;EAAE,OAAO,EN2J1B,GAAO;;;AM1JjC,iBAAiC;EAAE,OAAO,ENsR1B,GAAO;;;AMrRvB,qBAAqC;EAAE,OAAO,EN5L1B,GAAO;;;AM6L3B,4BAA4C;EAAE,OAAO,ENxB1B,GAAO;;;AMyBlC,iBAAiC;EAAE,OAAO,ENuP1B,GAAO;;;AMtPvB,iBAAiC;EAAE,OAAO,EN6I1B,GAAO;;;AM5IvB,8BAA8C;EAAE,OAAO,EN9J1B,GAAO;;;AM+JpC,+BAA+C;EAAE,OAAO,EN9J1B,GAAO;;;AM+JrC,4BAA4C;EAAE,OAAO,EN9J1B,GAAO;;;AM+JlC,8BAA8C;EAAE,OAAO,ENlK1B,GAAO;;;AMmKpC,gBAAgC;EAAE,OAAO,EN8D1B,GAAO;;;AM7DtB,eAA+B;EAAE,OAAO,ENrH1B,GAAO;;;AMsHrB,iBAAiC;EAAE,OAAO,ENvS1B,GAAO;;;AMwSvB,qBAAqC;EAAE,OAAO,EN2Z1B,GAAO;;;AM1Z3B,mBAAmC;EAAE,OAAO,ENhN1B,GAAO;;;AMiNzB,qBAAqC;EAAE,OAAO,EN7F1B,GAAO;;;AM8F3B,qBAAqC;EAAE,OAAO,EN7F1B,GAAO;;;AM8F3B,qBAAqC;EAAE,OAAO,EN+O1B,GAAO;;;AM9O3B,sBAAsC;EAAE,OAAO,ENiM1B,GAAO;;;AMhM5B,iBAAiC;EAAE,OAAO,EN6W1B,GAAO;;;AM5WvB,uBAAuC;EAAE,OAAO,EN0I1B,GAAO;;;AMzI7B,4IAAyC;EAAE,OAAO,EN0I1B,GAAO;;;AMzI/B,mBAAmC;EAAE,OAAO,ENqF1B,GAAO;;;AMpFzB,qBAAqC;EAAE,OAAO,ENmF1B,GAAO;;;AMlF3B,uBAAuC;EAAE,OAAO,ENnL1B,GAAO;;;AMoL7B,wBAAwC;EAAE,OAAO,EN0K1B,GAAO;;;AMzK9B,+BAA+C;EAAE,OAAO,ENpF1B,GAAO;;;AMqFrC,uBAAuC;EAAE,OAAO,ENwP1B,GAAO;;;AMvP7B,kBAAkC;EAAE,OAAO,ENjJ1B,GAAO;;;AMkJxB;8BAC8C;EAAE,OAAO,EN/M1B,GAAO;;;AMgNpC;4BAC4C;EAAE,OAAO,EN9M1B,GAAO;;;AM+MlC;+BAC+C;EAAE,OAAO,ENjN1B,GAAO;;;AMkNrC;cAC8B;EAAE,OAAO,ENvG1B,GAAO;;;AMwGpB,cAA8B;EAAE,OAAO,ENhC1B,GAAO;;;AMiCpB;cAC8B;EAAE,OAAO,ENqY1B,GAAO;;;AMpYpB;cAC8B;EAAE,OAAO,EN4C1B,GAAO;;;AM3CpB;;;cAG8B;EAAE,OAAO,ENgD1B,GAAO;;;AM/CpB;;cAE8B;EAAE,OAAO,ENiN1B,GAAO;;;AMhNpB;cAC8B;EAAE,OAAO,EN+C1B,GAAO;;;AM9CpB;cAC8B;EAAE,OAAO,EN3P1B,GAAO;;;AM4PpB,eAA+B;EAAE,OAAO,ENhG1B,GAAO;;;AMiGrB,oBAAoC;EAAE,OAAO,ENpF1B,GAAO;;;AMqF1B,yBAAyC;EAAE,OAAO,EN0P1B,GAAO;;;AMzP/B,0BAA0C;EAAE,OAAO,EN0P1B,GAAO;;;AMzPhC,0BAA0C;EAAE,OAAO,EN0P1B,GAAO;;;AMzPhC,2BAA2C;EAAE,OAAO,EN0P1B,GAAO;;;AMzPjC,2BAA2C;EAAE,OAAO,EN6P1B,GAAO;;;AM5PjC,4BAA4C;EAAE,OAAO,EN6P1B,GAAO;;;AM5PlC,oBAAoC;EAAE,OAAO,ENkU1B,GAAO;;;AMjU1B,sBAAsC;EAAE,OAAO,EN8T1B,GAAO;;;AM7T5B,yBAAyC;EAAE,OAAO,ENya1B,GAAO;;;AMxa/B,kBAAkC;EAAE,OAAO,ENsa1B,GAAO;;;AMraxB,eAA+B;EAAE,OAAO,EN2Z1B,GAAO;;;AM1ZrB,sBAAsC;EAAE,OAAO,EN2Z1B,GAAO;;;AM1Z5B,uBAAuC;EAAE,OAAO,ENoa1B,GAAO;;;AMna7B,kBAAkC;EAAE,OAAO,ENxJ1B,GAAO;;;AMyJxB,yBAAyC;EAAE,OAAO,EN8P1B,GAAO;;;AM7P/B,oBAAoC;EAAE,OAAO,ENgB1B,GAAO;;;AMf1B,iBAAiC;EAAE,OAAO,ENpF1B,GAAO;;;AMqFvB,cAA8B;EAAE,OAAO,EN3W1B,GAAO;;;AM4WpB,4CAAoC;EAAE,OAAO,EN/R1B,GAAO;;;AMgS1B,2BAA2C;EAAE,OAAO,EN/R1B,GAAO;;;AMgSjC,iBAAiC;EAAE,OAAO,EN+U1B,GAAO;;;AM9UvB,wBAAwC;EAAE,OAAO,EN+U1B,GAAO;;;AM9U9B,0BAA0C;EAAE,OAAO,ENgD1B,GAAO;;;AM/ChC,wBAAwC;EAAE,OAAO,ENkD1B,GAAO;;;AMjD9B,0BAA0C;EAAE,OAAO,EN+C1B,GAAO;;;AM9ChC,2BAA2C;EAAE,OAAO,EN+C1B,GAAO;;;AM9CjC,gBAAgC;EAAE,OAAO,ENjW1B,GAAO;;;AMkWtB,kBAAkC;EAAE,OAAO,ENmY1B,GAAO;;;AMlYxB,kBAAkC;EAAE,OAAO,EN7W1B,GAAO;;;AM8WxB,gBAAgC;EAAE,OAAO,ENkC1B,GAAO;;;AMjCtB,mBAAmC;EAAE,OAAO,EN5K1B,GAAO;;;AM6KzB,gBAAgC;EAAE,OAAO,ENgN1B,GAAO;;;AM/MtB,qBAAqC;EAAE,OAAO,ENxF1B,GAAO;;;AMyF3B,iBAAiC;EAAE,OAAO,EN4T1B,GAAO;;;AM3TvB,iBAAiC;EAAE,OAAO,ENtI1B,GAAO;;;AMuIvB,eAA+B;EAAE,OAAO,EN6C1B,GAAO;;;AM5CrB;mBACmC;EAAE,OAAO,EN5D1B,GAAO;;;AM6DzB,gBAAgC;EAAE,OAAO,EN8P1B,GAAO;;;AM7PtB,iBAAiC;EAAE,OAAO,ENuE1B,GAAO;;;AMtEvB,kBAAkC;EAAE,OAAO,EN9W1B,GAAO;;;AM+WxB,cAA8B;EAAE,OAAO,ENtS1B,GAAO;;;AMuSpB,aAA6B;EAAE,OAAO,ENiW1B,GAAO;;;AMhWnB,gBAAgC;EAAE,OAAO,ENuW1B,GAAO;;;AMtWtB,iBAAiC;EAAE,OAAO,EN+I1B,GAAO;;;AM9IvB,oBAAoC;EAAE,OAAO,ENkF1B,GAAO;;;AMjF1B,yBAAyC;EAAE,OAAO,EN6N1B,GAAO;;;AM5N/B,+BAA+C;EAAE,OAAO,EN/W1B,GAAO;;;AMgXrC,8BAA8C;EAAE,OAAO,ENjX1B,GAAO;;;AMkXpC;8BAC8C;EAAE,OAAO,ENzR1B,GAAO;;;AM0RpC,uBAAuC;EAAE,OAAO,ENnM1B,GAAO;;;AMoM7B,qBAAqC;EAAE,OAAO,ENiW1B,GAAO;;;AMhW3B,uBAAuC;EAAE,OAAO,ENoV1B,GAAO;;;AMnV7B;cAC8B;EAAE,OAAO,EN0S1B,GAAO;;;AMzSpB,yEAAwC;EAAE,OAAO,EN0G1B,GAAO;;;AMzG9B,wBAAwC;EAAE,OAAO,EN4M1B,GAAO;;;AM3M9B,gBAAgC;EAAE,OAAO,ENsL1B,GAAO;;;AMrLtB,0BAA0C;EAAE,OAAO,ENzL1B,GAAO;;;AM0LhC,oBAAoC;EAAE,OAAO,ENoW1B,GAAO;;;AMnW1B,iBAAiC;EAAE,OAAO,EN8D1B,GAAO;;;AM7DvB;;qBAEqC;EAAE,OAAO,EN8S1B,GAAO;;;AM7S3B;yBACyC;EAAE,OAAO,EN1F1B,GAAO;;;AM2F/B,gBAAgC;EAAE,OAAO,ENsW1B,GAAO;;;AMrWtB,iBAAiC;EAAE,OAAO,ENlG1B,GAAO;;;AMmGvB,iBAAiC;EAAE,OAAO,ENgH1B,GAAO;;;AM/GvB,wBAAwC;EAAE,OAAO,ENiH1B,GAAO;;;AMhH9B,6BAA6C;EAAE,OAAO,ENyN1B,GAAO;;;AMxNnC,sBAAsC;EAAE,OAAO,ENuN1B,GAAO;;;AMtN5B,oBAAoC;EAAE,OAAO,EN/N1B,GAAO;;;AMgO1B,eAA+B;EAAE,OAAO,EN5N1B,GAAO;;;AM6NrB,wBAAwC;EAAE,OAAO,EN2E1B,GAAO;;;AM1E9B,yBAAyC;EAAE,OAAO,ENyE1B,GAAO;;;AMxE/B,iBAAiC;EAAE,OAAO,ENvN1B,GAAO;;;AMwNvB,iBAAiC;EAAE,OAAO,ENzC1B,GAAO;;;AM0CvB,mBAAmC;EAAE,OAAO,ENpC1B,GAAO;;;AMqCzB,cAA8B;EAAE,OAAO,ENtL1B,GAAO;;;AMuLpB,mBAAmC;EAAE,OAAO,EN7U1B,GAAO;;;AM8UzB,gBAAgC;EAAE,OAAO,EN1R1B,GAAO;;;AM2RtB,cAA8B;EAAE,OAAO,ENsD1B,GAAO;;;AMrDpB,gBAAgC;EAAE,OAAO,ENmL1B,GAAO;;;AMlLtB,eAA+B;EAAE,OAAO,ENrP1B,GAAO;;;AMsPrB,gBAAgC;EAAE,OAAO,ENrP1B,GAAO;;;AMsPtB,kBAAkC;EAAE,OAAO,EN7W1B,GAAO;;;AM8WxB,yBAAyC;EAAE,OAAO,EN7W1B,GAAO;;;AM8W/B,gBAAgC;EAAE,OAAO,EN0L1B,GAAO;;;AMzLtB,uBAAuC;EAAE,OAAO,EN0L1B,GAAO;;;AMzL7B,kBAAkC;EAAE,OAAO,ENyF1B,GAAO;;;AMxFxB;cAC8B;EAAE,OAAO,ENzU1B,GAAO;;;AM0UpB;eAC+B;EAAE,OAAO,EN+M1B,GAAO;;;AM9MrB,eAA+B;EAAE,OAAO,EN4P1B,GAAO;;;AM3PrB,kBAAkC;EAAE,OAAO,ENuK1B,GAAO;;;AMtKxB,qBAAqC;EAAE,OAAO,ENtP1B,GAAO;;;AMuP3B,qBAAqC;EAAE,OAAO,ENiK1B,GAAO;;;AMhK3B,mBAAmC;EAAE,OAAO,EN9P1B,GAAO;;;AM+PzB,qBAAqC;EAAE,OAAO,EN/L1B,GAAO;;;AMgM3B,sBAAsC;EAAE,OAAO,ENxL1B,GAAO;;;AMyL5B,uBAAuC;EAAE,OAAO,ENrM1B,GAAO;;;AMsM7B,4BAA4C;EAAE,OAAO,EN/L1B,GAAO;;;AMgMlC;;uBAEuC;EAAE,OAAO,ENxM1B,GAAO;;;AMyM7B;yBACyC;EAAE,OAAO,EN9M1B,GAAO;;;AM+M/B;uBACuC;EAAE,OAAO,EN/M1B,GAAO;;;AMgN7B;uBACuC;EAAE,OAAO,ENpM1B,GAAO;;;AMqM7B,sBAAsC;EAAE,OAAO,ENjN1B,GAAO;;;AMkN5B,eAA+B;EAAE,OAAO,ENuR1B,GAAO;;;AMtRrB,kBAAkC;EAAE,OAAO,EN5S1B,GAAO;;;AM6SxB,mBAAmC;EAAE,OAAO,EN9E1B,GAAO;;;AM+EzB;;;;oBAIoC;EAAE,OAAO,ENnE1B,GAAO;;;AMoE1B,yBAAyC;EAAE,OAAO,EN/T1B,GAAO;;;AMgU/B;;gBAEgC;EAAE,OAAO,ENqD1B,GAAO;;;AMpDtB;iBACiC;EAAE,OAAO,ENnQ1B,GAAO;;;AMoQvB,qBAAqC;EAAE,OAAO,ENzK1B,GAAO;;;AM0K3B,cAA8B;EAAE,OAAO,EN3K1B,GAAO;;;AM4KpB;;sBAEsC;EAAE,OAAO,ENxJ1B,GAAO;;;AMyJ5B,wBAAwC;EAAE,OAAO,EN2K1B,GAAO;;;AM1K9B,aAA6B;EAAE,OAAO,ENiC1B,GAAO;;;AMhCnB;iBACiC;EAAE,OAAO,EN0Q1B,GAAO;;;AMzQvB;sBACsC;EAAE,OAAO,ENV1B,GAAO;;;AMW5B;wBACwC;EAAE,OAAO,ENX1B,GAAO;;;AMY9B,kBAAkC;EAAE,OAAO,EN1I1B,GAAO;;;AM2IxB,sBAAsC;EAAE,OAAO,ENlV1B,GAAO;;;AMmV5B,iBAAiC;EAAE,OAAO,ENjJ1B,GAAO;;;AMkJvB,oBAAoC;EAAE,OAAO,ENb1B,GAAO;;;AMc1B,kBAAkC;EAAE,OAAO,EN+F1B,GAAO;;;AM9FxB,oBAAoC;EAAE,OAAO,ENuE1B,GAAO;;;AMtE1B,2BAA2C;EAAE,OAAO,ENuE1B,GAAO;;;AMtEjC,eAA+B;EAAE,OAAO,ENzZ1B,GAAO;;;AM0ZrB;mBACmC;EAAE,OAAO,EN5M1B,GAAO;;;AM6MzB,cAA8B;EAAE,OAAO,EN0M1B,GAAO;;;AMzMpB,qBAAqC;EAAE,OAAO,ENxa1B,GAAO;;;AMya3B,eAA+B;EAAE,OAAO,ENI1B,GAAO;;;AMHrB,qBAAqC;EAAE,OAAO,ENuF1B,GAAO;;;AMtF3B,iBAAiC;EAAE,OAAO,EN2M1B,GAAO;;;AM1MvB,eAA+B;EAAE,OAAO,EN+Q1B,GAAO;;;AM9QrB,sBAAsC;EAAE,OAAO,ENzC1B,GAAO;;;AM0C5B,eAA+B;EAAE,OAAO,ENwP1B,GAAO;;;AMvPrB,qBAAqC;EAAE,OAAO,ENrZ1B,GAAO;;;AMsZ3B,iBAAiC;EAAE,OAAO,ENvB1B,GAAO;;;AMwBvB,wBAAwC;EAAE,OAAO,EN3L1B,GAAO;;;AM4L9B,kBAAkC;EAAE,OAAO,EN5X1B,GAAO;;;AM6XxB,wBAAwC;EAAE,OAAO,ENhY1B,GAAO;;;AMiY9B,sBAAsC;EAAE,OAAO,ENnY1B,GAAO;;;AMoY5B,kBAAkC;EAAE,OAAO,ENtY1B,GAAO;;;AMuYxB,oBAAoC;EAAE,OAAO,ENlY1B,GAAO;;;AMmY1B,oBAAoC;EAAE,OAAO,ENlY1B,GAAO;;;AMmY1B,qBAAqC;EAAE,OAAO,EN3b1B,GAAO;;;AM4b3B,uBAAuC;EAAE,OAAO,EN3b1B,GAAO;;;AM4b7B,gBAAgC;EAAE,OAAO,EN+K1B,GAAO;;;AM9KtB,oBAAoC;EAAE,OAAO,ENnV1B,GAAO;;;AMoV1B,aAA6B;EAAE,OAAO,EN9d1B,GAAO;;;AM+dnB,qBAAqC;EAAE,OAAO,EN5R1B,GAAO;;;AM6R3B,sBAAsC;EAAE,OAAO,EN/C1B,GAAO;;;AMgD5B,wBAAwC;EAAE,OAAO,EN9b1B,GAAO;;;AM+b9B,qBAAqC;EAAE,OAAO,ENtf1B,GAAO;;;AMuf3B,oBAAoC;EAAE,OAAO,EN/B1B,GAAO;;;AMgC1B,qBAAqC;EAAE,OAAO,ENzH1B,GAAO;;;AM0H3B,iBAAiC;EAAE,OAAO,ENvI1B,GAAO;;;AMwIvB,wBAAwC;EAAE,OAAO,ENvI1B,GAAO;;;AMwI9B,qBAAqC;EAAE,OAAO,EN4J1B,GAAO;;;AM3J3B,oBAAoC;EAAE,OAAO,EN4J1B,GAAO;;;AM3J1B,kBAAkC;EAAE,OAAO,ENxc1B,GAAO;;;AMycxB,cAA8B;EAAE,OAAO,ENjb1B,GAAO;;;AMkbpB,kBAAkC;EAAE,OAAO,ENvJ1B,GAAO;;;AMwJxB,oBAAoC;EAAE,OAAO,EN3gB1B,GAAO;;;AM4gB1B,aAA6B;EAAE,OAAO,EN7Z1B,GAAO;;;AM8ZnB;;cAE8B;EAAE,OAAO,ENzK1B,GAAO;;;AM0KpB,mBAAmC;EAAE,OAAO,ENpG1B,GAAO;;;AMqGzB,qBAAqC;EAAE,OAAO,ENxb1B,GAAO;;;AMyb3B,yBAAyC;EAAE,OAAO,EN5W1B,GAAO;;;AM6W/B,mBAAmC;EAAE,OAAO,EN9V1B,GAAO;;;AM+VzB,mBAAmC;EAAE,OAAO,EN9P1B,GAAO;;;AM+PzB,kBAAkC;EAAE,OAAO,ENrJ1B,GAAO;;;AMsJxB,iBAAiC;EAAE,OAAO,ENe1B,GAAO;;;AMdvB,uBAAuC;EAAE,OAAO,EN2B1B,GAAO;;;AM1B7B,sBAAsC;EAAE,OAAO,ENoC1B,GAAO;;;AMnC5B,mBAAmC;EAAE,OAAO,ENqC1B,GAAO;;;AMpCzB,oBAAoC;EAAE,OAAO,EN5a1B,GAAO;;;AM6a1B,0BAA0C;EAAE,OAAO,EN9a1B,GAAO;;;AM+ahC,kBAAkC;EAAE,OAAO,EN/V1B,GAAO;;;AMgWxB,eAA+B;EAAE,OAAO,ENoB1B,GAAO;;;AMnBrB,sBAAsC;EAAE,OAAO,EN8K1B,GAAO;;;AM7K5B,qBAAqC;EAAE,OAAO,EN/F1B,GAAO;;;AMgG3B,sBAAsC;EAAE,OAAO,EN6E1B,GAAO;;;AM5E5B,oBAAoC;EAAE,OAAO,EN9M1B,GAAO;;;AM+M1B,gBAAgC;EAAE,OAAO,EN+K1B,GAAO;;;AM9KtB,eAA+B;EAAE,OAAO,EN7H1B,GAAO;;;AM8HrB,kBAAkC;EAAE,OAAO,ENnH1B,GAAO;;;AMoHxB;sBACsC;EAAE,OAAO,ENkI1B,GAAO;;;AMjI5B,0BAA0C;EAAE,OAAO,ENkI1B,GAAO;;;AMjIhC,uBAAuC;EAAE,OAAO,EN0K1B,GAAO;;;AMzK7B,sBAAsC;EAAE,OAAO,ENlI1B,GAAO;;;AMmI5B,qBAAqC;EAAE,OAAO,ENyK1B,GAAO;;;AMxK3B,sBAAsC;EAAE,OAAO,ENnI1B,GAAO;;;AMoI5B,wBAAwC;EAAE,OAAO,ENlI1B,GAAO;;;AMmI9B,wBAAwC;EAAE,OAAO,ENpI1B,GAAO;;;AMqI9B,iBAAiC;EAAE,OAAO,EN1G1B,GAAO;;;AM2GvB,qBAAqC;EAAE,OAAO,EN7Q1B,GAAO;;;AM8Q3B,4BAA4C;EAAE,OAAO,EN1U1B,GAAO;;;AM2UlC,sBAAsC;EAAE,OAAO,ENzE1B,GAAO;;;AM0E5B,mBAAmC;EAAE,OAAO,ENkL1B,GAAO;;;AMjLzB,iBAAiC;EAAE,OAAO,ENX1B,GAAO;;;AMYvB,oBAAoC;EAAE,OAAO,ENuJ1B,GAAO;;;AMtJ1B,qBAAqC;EAAE,OAAO,ENwJ1B,GAAO;;;AMvJ3B;cAC8B;EAAE,OAAO,EN/f1B,GAAO;;;AMggBpB,kBAAkC;EAAE,OAAO,EN4J1B,GAAO;;;AM3JxB,gBAAgC;EAAE,OAAO,EN8G1B,GAAO;;;AM7GtB,iBAAiC;EAAE,OAAO,ENwD1B,GAAO;;;AMvDvB,iBAAiC;EAAE,OAAO,EN9I1B,GAAO;;;AM+IvB;uBACuC;EAAE,OAAO,EN0L1B,GAAO;;;AMzL7B,wBAAwC;EAAE,OAAO,ENjH1B,GAAO;;;AMkH9B,mBAAmC;EAAE,OAAO,ENrH1B,GAAO;;;AMsHzB,uBAAuC;EAAE,OAAO,ENnW1B,GAAO;;;AMoW7B;;uBAEuC;EAAE,OAAO,EN/gB1B,GAAO;;;AMghB7B;iCACiD;EAAE,OAAO,EN9gB1B,GAAO;;;AM+gBvC;uBACuC;EAAE,OAAO,ENlhB1B,GAAO;;;AMmhB7B;0BAC0C;EAAE,OAAO,ENnhB1B,GAAO;;;AMohBhC;wBACwC;EAAE,OAAO,ENxhB1B,GAAO;;;AMyhB9B,wBAAwC;EAAE,OAAO,EN3I1B,GAAO;;;AM4I9B,mBAAmC;EAAE,OAAO,EN3O1B,GAAO;;;AM4OzB,uBAAuC;EAAE,OAAO,ENxI1B,GAAO;;;AMyI7B,yBAAyC;EAAE,OAAO,ENxI1B,GAAO;;;AMyI/B,sBAAsC;EAAE,OAAO,ENwB1B,GAAO;;;AMvB5B,wBAAwC;EAAE,OAAO,ENwB1B,GAAO;;;AMvB9B,iBAAiC;EAAE,OAAO,EN/d1B,GAAO;;;AMgevB,yBAAyC;EAAE,OAAO,ENle1B,GAAO;;;AMme/B,gBAAgC;EAAE,OAAO,ENpc1B,GAAO;;;AMqctB,wBAAwC;EAAE,OAAO,ENljB1B,GAAO;;;AMmjB9B,sBAAsC;EAAE,OAAO,ENxP1B,GAAO;;;AMyP5B;0BAC0C;EAAE,OAAO,ENzP1B,GAAO;;;AM0PhC;yBACyC;EAAE,OAAO,EN7P1B,GAAO;;;AM8P/B;wBACwC;EAAE,OAAO,ENhQ1B,GAAO;;;AMiQ9B,oBAAoC;EAAE,OAAO,ENrQ1B,GAAO;;;AMsQ1B;sBACsC;EAAE,OAAO,ENxR1B,GAAO;;;AMyR5B;uBACuC;EAAE,OAAO,EN7R1B,GAAO;;;AM8R7B,0BAA0C;EAAE,OAAO,EN1R1B,GAAO;;;AM2RhC,wBAAwC;EAAE,OAAO,ENpS1B,GAAO;;;AMqS9B,uBAAuC;EAAE,OAAO,EN3R1B,GAAO;;;AM4R7B,yBAAyC;EAAE,OAAO,EN/R1B,GAAO;;;AMgS/B,uBAAuC;EAAE,OAAO,ENjS1B,GAAO;;;AMkS7B,oBAAoC;EAAE,OAAO,EN+D1B,GAAO;;;AM9D1B,qBAAqC;EAAE,OAAO,EN/F1B,GAAO;;;AMgG3B,2BAA2C;EAAE,OAAO,EN/b1B,GAAO;;;AMgcjC,aAA6B;EAAE,OAAO,ENtU1B,GAAO;;;AMuUnB,oBAAoC;EAAE,OAAO,ENtU1B,GAAO;;;AMuU1B,sBAAsC;EAAE,OAAO,ENkE1B,GAAO;;;AMjE5B,wBAAwC;EAAE,OAAO,ENrK1B,GAAO;;;AMsK9B,+BAA+C;EAAE,OAAO,ENrK1B,GAAO;;;AMsKrC,qBAAqC;EAAE,OAAO,EN5U1B,GAAO;;;AM6U3B,sBAAsC;EAAE,OAAO,ENwH1B,GAAO;;;AMvH5B,iBAAiC;EAAE,OAAO,ENnF1B,GAAO;;;AMoFvB,iBAAiC;EAAE,OAAO,ENze1B,GAAO;;;AM0evB,kBAAkC;EAAE,OAAO,EN9W1B,GAAO;;;AM+WxB,gBAAgC;EAAE,OAAO,ENxK1B,GAAO;;;AMyKtB,4BAA4C;EAAE,OAAO,ENpQ1B,GAAO;;;AMqQlC;qBACqC;EAAE,OAAO,ENS1B,GAAO;;;AMR3B,iBAAiC;EAAE,OAAO,ENjd1B,GAAO;;;AMkdvB,gBAAgC;EAAE,OAAO,ENzoB1B,GAAO;;;AM0oBtB,iBAAiC;EAAE,OAAO,EN/nB1B,GAAO;;;AMgoBvB,0BAA0C;EAAE,OAAO,EN3hB1B,GAAO;;;AM4hBhC,2BAA2C;EAAE,OAAO,EN9hB1B,GAAO;;;AM+hBjC,2BAA2C;EAAE,OAAO,EN5hB1B,GAAO;;;AM6hBjC,2BAA2C;EAAE,OAAO,ENjiB1B,GAAO;;;AMkiBjC,mBAAmC;EAAE,OAAO,ENpR1B,GAAO;;;AMqRzB,kBAAkC;EAAE,OAAO,EN5N1B,GAAO;;;AM6NxB,oBAAoC;EAAE,OAAO,EN5N1B,GAAO;;;AM6N1B,gBAAgC;EAAE,OAAO,EN/N1B,GAAO;;;AMgOtB,cAA8B;EAAE,OAAO,ENlO1B,GAAO;;;AMmOpB,qBAAqC;EAAE,OAAO,ENpe1B,GAAO;;;AMqe3B,uBAAuC;EAAE,OAAO,ENpe1B,GAAO;;;AMqe7B,gBAAgC;EAAE,OAAO,ENtS1B,GAAO;;;AMuStB,gBAAgC;EAAE,OAAO,ENiF1B,GAAO;;;AMhFtB,oBAAoC;EAAE,OAAO,ENlkB1B,GAAO;;;AMmkB1B,oBAAoC;EAAE,OAAO,ENrX1B,GAAO;;;AMsX1B,uBAAuC;EAAE,OAAO,ENpI1B,GAAO;;;AMqI7B,eAA+B;EAAE,OAAO,ENpc1B,GAAO;;;AMqcrB,0BAA0C;EAAE,OAAO,ENhe1B,GAAO;;;AMiehC,mBAAmC;EAAE,OAAO,ENpf1B,GAAO;;;AMqfzB,eAA+B;EAAE,OAAO,ENlN1B,GAAO;;;AMmNrB,uBAAuC;EAAE,OAAO,EN1X1B,GAAO;;;AM2X7B,cAA8B;EAAE,OAAO,ENoD1B,GAAO;;;AMnDpB,uBAAuC;EAAE,OAAO,EN3J1B,GAAO;;;AM4J7B,mBAAmC;EAAE,OAAO,ENzN1B,GAAO;;;AM0NzB,iBAAiC;EAAE,OAAO,ENlH1B,GAAO;;;AMmHvB,uBAAuC;EAAE,OAAO,EN7L1B,GAAO;;;AM8L7B,yBAAyC;EAAE,OAAO,EN7L1B,GAAO;;;AM8L/B,sBAAsC;EAAE,OAAO,EN3C1B,GAAO;;;AM4C5B,wBAAwC;EAAE,OAAO,EN3C1B,GAAO;;;AM4C9B,uBAAuC;EAAE,OAAO,ENrG1B,GAAO;;;AMsG7B,0BAA0C;EAAE,OAAO,ENrG1B,GAAO;;;AMsGhC,kBAAkC;EAAE,OAAO,EN7U1B,GAAO;;;AM8UxB,oBAAoC;EAAE,OAAO,ENnlB1B,GAAO;;;AMolB1B,sBAAsC;EAAE,OAAO,ENnlB1B,GAAO;;;AMolB5B,kBAAkC;EAAE,OAAO,EN/L1B,GAAO;;;AMgMxB,sCAAiC;EAAE,OAAO,ENlX1B,GAAO;;;AMmXvB,qBAAqC;EAAE,OAAO,ENkF1B,GAAO;;;AMjF3B,kBAAkC;EAAE,OAAO,ENmF1B,GAAO;;;AMlFxB,iBAAiC;EAAE,OAAO,EN9c1B,GAAO;;;AM+cvB,2BAA2C;EAAE,OAAO,EN2B1B,GAAO;;;AM1BjC,yBAAyC;EAAE,OAAO,ENmE1B,GAAO;;;AMlE/B,4BAA4C;EAAE,OAAO,ENxK1B,GAAO;;;AMyKlC,gBAAgC;EAAE,OAAO,EN9lB1B,GAAO;;;AM+lBtB,4BAA4C;EAAE,OAAO,ENtoB1B,GAAO;;;AMuoBlC,+BAA+C;EAAE,OAAO,ENqD1B,GAAO;;;AMpDrC,kBAAkC;EAAE,OAAO,ENxlB1B,GAAO;;;AMylBxB,sCAAsD;EAAE,OAAO,EN5oB1B,GAAO;;;AM6oB5C;8CAC8D;EAAE,OAAO,EN9qB1B,GAAO;;;AM+qBpD;;eAE+B;EAAE,OAAO,ENvf1B,GAAO;;;AMwfrB,gBAAgC;EAAE,OAAO,ENhY1B,GAAO;;;AMiYtB,kBAAkC;EAAE,OAAO,ENhY1B,GAAO;;;AMiYxB;wBACwC;EAAE,OAAO,EN1H1B,GAAO;;;AM2H9B,qBAAqC;EAAE,OAAO,ENzR1B,GAAO;;;AM0R3B,iBAAiC;EAAE,OAAO,ENiC1B,GAAO;;;AMhCvB,wBAAwC;EAAE,OAAO,ENiC1B,GAAO;;;AMhC9B,mBAAmC;EAAE,OAAO,ENlH1B,GAAO;;;AMmHzB,yBAAyC;EAAE,OAAO,ENlH1B,GAAO;;;AMmH/B,0BAA0C;EAAE,OAAO,ENlH1B,GAAO;;;AMmHhC,qBAAqC;EAAE,OAAO,ENrN1B,GAAO;;;AMsN3B,sBAAsC;EAAE,OAAO,ENpb1B,GAAO;;;AMqb5B,gBAAgC;EAAE,OAAO,ENmE1B,GAAO;;;AMlEtB,oBAAoC;EAAE,OAAO,ENpD1B,GAAO;;;AMqD1B;+BAC+C;EAAE,OAAO,ENzY1B,GAAO;;;AM0YrC;uBACuC;EAAE,OAAO,EN7a1B,GAAO;;;AM8a7B,sBAAsC;EAAE,OAAO,ENtX1B,GAAO;;;AMuX5B,wBAAwC;EAAE,OAAO,ENlf1B,GAAO;;;AMmf9B,0BAA0C;EAAE,OAAO,ENlf1B,GAAO;;;AMmfhC,iBAAiC;EAAE,OAAO,ENtT1B,GAAO;;;AMuTvB,uBAAuC;EAAE,OAAO,ENptB1B,GAAO;;;AMqtB7B,yBAAyC;EAAE,OAAO,ENptB1B,GAAO;;;AMqtB/B;uBACuC;EAAE,OAAO,ENrtB1B,GAAO;;;AMstB7B;yBACyC;EAAE,OAAO,ENttB1B,GAAO;;;AMutB/B,sBAAsC;EAAE,OAAO,ENJ1B,GAAO;;;AMK5B,wBAAwC;EAAE,OAAO,ENJ1B,GAAO;;;AMK9B,iBAAiC;EAAE,OAAO,ENH1B,GAAO;;;AMIvB,mBAAmC;EAAE,OAAO,EN3W1B,GAAO;;;AM4WzB;kBACkC;EAAE,OAAO,EN5W1B,GAAO;;;AM6WxB;oBACoC;EAAE,OAAO,EN7W1B,GAAO;;;AM8W1B,gBAAgC;EAAE,OAAO,ENtN1B,GAAO;;;AMuNtB,yBAAyC;EAAE,OAAO,EN3b1B,GAAO;;;AM4b/B,mBAAmC;EAAE,OAAO,ENtF1B,GAAO;;;AMuFzB;;2BAE2C;EAAE,OAAO,ENxE1B,GAAO;;;AMyEjC;qCACqD;EAAE,OAAO,ENvE1B,GAAO;;;AMwE3C;2BAC2C;EAAE,OAAO,EN3E1B,GAAO;;;AM4EjC;8BAC8C;EAAE,OAAO,EN5E1B,GAAO;;;AM6EpC;4BAC4C;EAAE,OAAO,ENjF1B,GAAO;;;AMkFlC,iBAAiC;EAAE,OAAO,EN3K1B,GAAO;;;AM4KvB;;eAE+B;EAAE,OAAO,ENzrB1B,GAAO;;;AM0rBrB,kBAAkC;EAAE,OAAO,ENlP1B,GAAO;;;AMmPxB,0BAA0C;EAAE,OAAO,ENK1B,GAAO;;;AMJhC,0BAA0C;EAAE,OAAO,ENK1B,GAAO;;;AMJhC,yBAAyC;EAAE,OAAO,ENK1B,GAAO;;;AMJ/B;uBACuC;EAAE,OAAO,END1B,GAAO;;;AME7B;yBACyC;EAAE,OAAO,ENF1B,GAAO;;;AMG/B,mBAAmC;EAAE,OAAO,ENxsB1B,GAAO;;;AMysBzB,eAA+B;EAAE,OAAO,ENpb1B,GAAO;;;AMqbrB,eAA+B;EAAE,OAAO,EN1hB1B,GAAO;;;AM2hBrB,eAA+B;EAAE,OAAO,ENxY1B,GAAO;;;AMyYrB,kBAAkC;EAAE,OAAO,EN/O1B,GAAO;;;AMgPxB,kBAAkC;EAAE,OAAO,ENziB1B,GAAO;;;AM0iBxB,oBAAoC;EAAE,OAAO,ENjU1B,GAAO;;;AMkU1B,sBAAsC;EAAE,OAAO,EN7K1B,GAAO;;;AM8K5B,sBAAsC;EAAE,OAAO,ENhI1B,GAAO;;;AMiI5B,qBAAqC;EAAE,OAAO,ENJ1B,GAAO;;;AMK3B,iBAAiC;EAAE,OAAO,ENxU1B,GAAO;;;AOzcvB,QAAS;EH8BP,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,GAAG;EACV,MAAM,EAAE,GAAG;EACX,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,IAAI;EACZ,QAAQ,EAAE,MAAM;EAChB,IAAI,EAAE,gBAAa;EACnB,MAAM,EAAE,CAAC;;;AAUT,mDACQ;EACN,QAAQ,EAAE,MAAM;EAChB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,CAAC;EACT,QAAQ,EAAE,OAAO;EACjB,IAAI,EAAE,IAAI;;;AIvDd,s0BAAK;EACH,WAAW,EAAE,OAAO;;AACpB,g+BAAQ;EACN,WAAW,EC+BuB,aAAa;ED9B/C,OAAO,EAAE,YAAY;EACrB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,MAAM;EACnB,WAAW,EAAE,CAAC;EACd,eAAe,EAAE,OAAO;;;AAM5B,miCAAkB;EAChB,OAAO,EAAE,YAAY;EACrB,eAAe,EAAE,OAAO;;;AAGxB,k+EAAgB;EACd,OAAO,EAAE,MAAM;;AACf,8hFAAuB;EACrB,WAAW,EAAE,KAAI;;AACnB,s+EAAsB;EACpB,OAAO,EAAE,YAAY;;;AAE3B,6mBAA2B;EACzB,OAAO,EAAE,GAAE;EjBpBL,kBAAoB,EAAE,qBAAM;EAK5B,eAAiB,EAAE,qBAAM;EAezB,UAAY,EAAE,qBAAM;;;AiBE5B,usBAAiC;EAC/B,OAAO,EAAE,CAAC;;;AAGV,k2CAAuB;EACrB,SAAS,EAAE,IAAI;EACf,cAAc,EAAE,IAAI;;;AEpBxB,+RAAS;EACP,OAAO,EAAE,IAAqB;EAC9B,WAAW,EDayB,IAAI;ECZxC,aAAa,EDYuB,IAAI;ECXxC,UAAU,EAAE,OAAmB;;;AAEjC,+CAAe;EACb,KAAK,EC2B+B,IAAM;ED1B1C,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,KAAK;EACd,KAAK,ECwB+B,IAAM;EDvB1C,UAAU,EAAE,OAAkB;EAC9B,MAAM,EAAE,KAAsB;EAC9B,OAAO,EAAE,QAA2C;EACpD,aAAa,EAAE,IAAqB;;;AAEtC,+cAAyB;EACvB,UAAU,EAAE,OAAkB;;AAC9B,i6CAAe;EACb,UAAU,EAAE,OAAiB;;;AACjC,wbAA0B;EACxB,UAAU,EAAE,OAAmB;;AAC/B,o3CAAe;EACb,UAAU,EAAE,OAAoB;;;AAEpC,ybAAuB;EACrB,UAAU,EAAE,OAAmB;;AAC/B,m3CAAe;EACb,UAAU,EAAE,OAAkB;;;AAElC,ycAA0B;EACxB,UAAU,EAAE,OAAuB;;AACnC,s5CAAe;EACb,UAAU,EAAE,OAAqB;;;AAErC,4fAA0B;EACxB,UAAU,ECU0B,OAAmB;;ADTvD,4/CAAe;EACb,KAAK,ECR6B,OAAW;EDS7C,UAAU,ECSwB,OAAmB;;ADRvD,shBAAC;EACC,KAAK,EClD6B,OAAmB;;;ADoDzD,wcAAsB;EACpB,aAAa,EAAE,CAAC;;;AAsBlB,kBAAkB;EAChB,QAAQ,EAAE,KAAK;EACf,MAAM,EAAE,GAAG;EACX,IAAI,EAAE,CAAC;EACP,OAAO,EDG6B,GAAG;;ACFvC,qBAAE;EACA,OAAO,EAAE,KAAK;EACd,KAAK,EDT6B,KAAK;ECUvC,UAAU,EAAE,WAAW;EACvB,KAAK,ECzC6B,IAAM;ED0CxC,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,8BAA0B;EACtC,OAAO,EAAE,MAAmB;EAC5B,SAAS,EAAE,GAAG;EACd,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;EACT,WAAW,EAAE,IAAI;EACjB,QAAQ,EAAE,MAAM;EnB3FZ,kBAAoB,EAAE,gBAAM;EAK5B,eAAiB,EAAE,gBAAM;EAezB,UAAY,EAAE,gBAAM;;AmByExB,0CAAsB;EACpB,UAAU,EChFsB,OAAM;;ADiFxC,uCAAmB;EACjB,UAAU,EDzBsB,OAAW;;AC0B7C,0CAAsB;EACpB,UAAU,EDnFsB,OAAO;;ACoFzC,yCAAqB;EACnB,UAAU,EDtEsB,OAAI;;ACuEtC,wBAAI;EACF,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,IAAI;;;AEhFd,oCAAsB;EFmFxB,kBAAkB;IAChB,MAAM,EAAE,IAAI;IACZ,GAAG,EAAE,CAAC;IACN,KAAK,EAAE,IAAI;;EACX,qBAAE;IACA,KAAK,EAAE,IAAI;;;AG3FjB,MAAM;EACJ,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,CAAC;EACT,cAAc,EAAE,QAAQ;EACxB,eAAe,EAAE,MAAM;EACvB,MAAM,EAAE,OAAO;EACf,WAAW,EAAE,MAAM;EACnB,kBAAkB,EAAE,MAAM;EAC1B,SAAS,EAAE,OAAO;;;AACpB,iDAAiD;EAC/C,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;;AACZ,gBAAgB;EACd,MAAM,EAAE,OAAO;;;AAEjB,IAAI;;EAEF,OAAO,EAAE,YAAY;EACrB,aAAa,EAAE,GAAG;EAClB,WAAW,EAAE,MAAM;EACnB,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;EAClB,MAAM,EAAE,OAAO;EACf,SAAS,EAAE,IAAI;EACf,OAAO,EAAE,iBAA6F;EACtG,KAAK,EFH+B,IAAM;EEI1C,MAAM,EAAE,4BAAyB;EACjC,gBAAgB,EJeoB,OAAM;EId1C,eAAe,EAAE,IAAI;EACrB,WAAW,EAAE,MAAM;EACnB,WAAW,EFWyB,2DAA2D;EEV/F,UAAU,EAAE,0FAAqF;EACjG,YAAY,EAAE,KAAK;EACnB,cAAc,EAAE,MAAM;EACtB,QAAQ,EAAE,MAAM;EAChB,IAAI,EAAE,CAAC;EACP,iBAAiB,EAAE,IAAI;EtBxDjB,mBAAoB,EsByDb,IAAI;EtBpDX,gBAAiB,EsBoDV,IAAI;EtB/CX,eAAgB,EsB+CT,IAAI;EtBrCX,WAAY,EsBqCL,IAAI;EtBzDX,kBAAoB,EAAE,eAAM;EAK5B,eAAiB,EAAE,eAAM;EAezB,UAAY,EAAE,eAAM;;;AsByC5B,UAAU;EACR,UAAU,EAAE,OAAwB;EACpC,KAAK,EFrB+B,IAAM;;;AEwB1C,UAAO;EACL,UAAU,EAAE,OAAqC;EACjD,KAAK,EF1B6B,IAAM;;AE2B1C,UAAO;EACL,UAAU,EAAE,OAAqC;EACjD,OAAO,EAAE,CAAC;;AACZ,WAAQ;EACN,UAAU,EAAE,oFAA+E;EAC3F,OAAO,EAAE,iBAA6F;;AACxG,YAAS;EACP,KAAK,EFlC6B,IAAM;;AEmC1C,aAAU;EACR,gBAAgB,EAAE,IAAI;EACtB,MAAM,EAAE,2DAA2D;EACnE,MAAM,EAAE,iBAAmB;EAC3B,OAAO,EAAE,GAAG;EACZ,MAAM,EAAE,WAAW;EACnB,UAAU,EAAE,IAAI;;;AAEpB,aAAa;EACX,gBAAgB,EAAE,IAAI;EACtB,MAAM,EAAE,2DAA2D;EACnE,MAAM,EAAE,iBAAmB;EAC3B,OAAO,EAAE,GAAG;EACZ,MAAM,EAAE,WAAW;EACnB,UAAU,EAAE,IAAI;;AAChB,8DAA0B;EACxB,gBAAgB,EAAE,IAAI;EACtB,MAAM,EAAE,2DAA2D;EACnE,MAAM,EAAE,iBAAmB;EAC3B,OAAO,EAAE,GAAI;EACb,MAAM,EAAE,WAAW;EACnB,UAAU,EAAE,IAAI;;;AAGpB,sBAAsB;EACpB,OAAO,EAAE,CAAC;EACV,MAAM,EAAE,CAAC;;;AAEX,UAAU;EACR,SAAS,EAAE,GAAG;;;AAEhB,SAAS;EACP,gBAAgB,EAAE,kBAAgB;;AAClC,eAAO;EACL,gBAAgB,EAAE,kBAA6B;;;AAEnD,YAAY;EACV,gBAAgB,EAAE,kBAA2C;EAC7D,KAAK,EAAE,kBAAsB;;AAC7B,kBAAO;EACL,gBAAgB,EAAE,kBAAuD;EACzE,KAAK,EFhF6B,OAAW;;AEiF/C,oBAAS;EACP,KAAK,EAAE,kBAAsB;;;AAEjC,YAAY;EACV,gBAAgB,EAAE,kBAAiB;;AACnC,kBAAO;EACL,gBAAgB,EAAE,kBAA6B;;;AAEnD,WAAW;EACT,gBAAgB,EAAE,kBAAe;;AACjC,iBAAO;EACL,gBAAgB,EAAE,kBAA4B;;;AAElD,YAAY;EACV,gBAAgB,EAAE,kBAAkB;;AACpC,kBAAO;EACL,gBAAgB,EAAE,kBAA+B;;;AACrD,WAAW;EACT,gBAAgB,EJvIoB,IAAI;;AIwIxC,iBAAO;EACL,gBAAgB,EAAE,kBAAoC;;;AAE1D,SAAS;EACP,gBAAgB,EAAE,sBAAsB;EACxC,KAAK,EFhJ+B,OAAmB;EEiJvD,UAAU,EAAE,IAAI;EAChB,YAAY,EAAE,sBAAsB;;AACpC,eAAO;EACL,gBAAgB,EAAE,sBAAsB;EACxC,KAAK,EAAE,kBAAoC;EAC3C,UAAU,EAAE,IAAI;;AAClB,gBAAQ;EACN,gBAAgB,EAAE,sBAAsB;EACxC,KAAK,EAAE,kBAAoC;EAC3C,UAAU,EAAE,IAAI;;AAClB,iBAAS;EACP,KAAK,EF3J6B,OAAwB;;;AE6J9D,oCAAoC;EAClC,cAAc,EAAE,MAAM;;;AAExB,aAAa;EACX,aAAa,EJ1IuB,IAAI;EhBuExC,KAAK,EAAE,CAAC;;AACR,yCAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,mBAAO;EACL,KAAK,EAAE,IAAI;;;AqB3Ff,YAAY;EACV,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,YAAY;;;AAIvB,qCAAqC;EACnC,OAAO,EAAE,KAAK;;;AAChB,iBAAiB;EACf,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,CAAC;EACP,OAAO,EAAE,IAAI;EACb,KAAK,EAAE,IAAI;EACX,GAAG,EAAE,IAAI;EACT,SAAS,EAAE,IAAI;EACf,UAAU,EHuB0B,OAAyB;EGtB7D,OAAO,ELmD6B,GAAG;EKlDvC,MAAM,EAAE,iBAAgC;EACxC,UAAU,EAAE,8BAA0B;EACtC,OAAO,EAAE,IAAqB;;AAC9B,0BAAQ;EACN,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,KAAK,EHM6B,OAAW;EGL7C,WAAW,EAAE,MAAM;EACnB,SAAS,EAAE,GAAG;EACd,OAAO,EAAE,MAAuB;EAChC,MAAM,EAAE,OAAO;;AACf,gCAAO;EACL,UAAU,EHvCsB,OAAmB;EGwCnD,KAAK,EHG2B,IAAM;;AGF1C,8BAAY;EACV,UAAU,EAAE,iBAAgC;EAC5C,MAAM,EAAE,KAAuB;;AACjC,6BAAW;EACT,cAAc,EAAE,IAAqB;;AACrC,kDAAoB;EAClB,KAAK,EAAE,IAAI;;AACf,qCAAmB;EACjB,UAAU,EAAE,OAA4B;EACxC,cAAc,EAAE,SAAS;EACzB,WAAW,EAAE,GAAG;EAChB,SAAS,EAAE,GAAG;;AACd,2CAAO;EACL,UAAU,EAAE,OAA4B;;AAC1C,0CAAI;EACF,KAAK,EHb2B,IAAM;;;AGe5C,6CAA6C;EAC3C,MAAM,EAAE,IAAI;EACZ,GAAG,EAAE,IAAI;EACT,IAAI,EAAE,IAAI;EACV,KAAK,EAAE,CAAC;;;AAGR,iDAAiB;EACf,UAAU,EHlBwB,OAAyB;EGmB3D,UAAU,EAAE,GAAG;;AACjB,mDAAmB;EACjB,OAAO,EAAE,QAA2C;;AACpD,yDAAO;EACL,UAAU,EHvEsB,OAAmB;EGwEnD,KAAK,EH7B2B,IAAM;;;AG+B5C,+CAA+C;EAC7C,KAAK,EAAE,CAAC;EACR,IAAI,EAAE,IAAI;EACV,UAAU,EAAE,KAAK;;;AAGjB,yBAAQ;EACN,OAAO,EAAE,GAAG;EACZ,aAAa,EAAE,oBAA0B;EACzC,WAAW,EAAE,qBAAqB;EAClC,YAAY,EAAE,qBAAqB;EACnC,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,KAAK;EACd,GAAG,EAAE,IAAI;EACT,IAAI,EAAE,GAAG;EACT,WAAW,EAAE,IAAI;;AACnB,gDAA+B;EAC7B,IAAI,EAAE,IAAI;;;ACtEZ,uBAAM;EACJ,OAAO,EAAE,KAAK;;;AAEhB,oIAA+C;EAC7C,OAAO,EAAE,YAAY;EACrB,QAAQ,EAAE,MAAM;EAChB,KAAK,EAAE,CAAC;EACR,cAAc,EAAE,MAAM;;;AAItB,0CAAO;EACL,OAAO,EAAE,YAAY;EACrB,cAAc,EAAE,MAAM;EACtB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,YAA+C;EACvD,KAAK,EAAE,IAAI;;AACf,4BAAW;EACT,KAAK,EAAE,IAAI;;AACX,kCAAK;EACH,OAAO,EAAE,KAAK;;AAChB,mCAAM;EACJ,UAAU,EAAE,GAAqB;;;AAEvC,QAAQ;EACN,MAAM,EAAE,CAAC;EACT,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;;;AACZ,MAAM;EACJ,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,CAAC;EACV,WAAW,EAAE,MAAM;EACnB,aAAa,EN/BuB,IAAI;EMgCxC,SAAS,EAAE,IAAI;EACf,YAAY,EAAE,IAAI;;;AACpB,KAAK;EACH,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,cAAa;EACrB,KAAK,ENR+B,IAAU;EMS9C,SAAS,EAAE,GAAG;;;AAEhB,uBAAuB;EACrB,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,CAAC;EACT,cAAc,EAAE,QAAQ;EACxB,eAAe,EAAE,MAAM;;;AAGzB,iBAAiB;EACf,aAAa,ENhDuB,IAAI;EhBuExC,KAAK,EAAE,CAAC;EuBrGR,SAAS,ECCC,IAAQ;EDChB,WAAI,EAAE,IAAI;EACV,YAAK,EAAE,IAAI;EvBkGb,KAAK,EAAE,CAAC;;AACR,iDAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,uBAAO;EACL,KAAK,EAAE,IAAI;;AALb,iDAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,uBAAO;EACL,KAAK,EAAE,IAAI;;;AsBzBf,yDAAyD;EACvD,OAAO,EAAE,IAAI;EACb,KAAK,EN/C+B,OAAI;;;AMoDxC,qGAA+C;EAC7C,cAAc,EAAE,IAAqB;;AACrC,0HAAM;EACJ,KAAK,EAAE,IAAI;;AAEX,mwEAAqP;EACnP,KAAK,EAAE,IAAI;;;AACnB,+BAA+B;EGlF3B,KAAK,EAAE,IAAsB;EAG3B,OAAO,EAAE,KAAK;EAed,YAAoB,EAAE,aAA+B;EACrD,KAAK,EAAE,IAAuC;ECnB5C,YAAoB,EAAE,CAAC;;ADqBzB,0CAAa;EACX,YAAoB,EAAE,CAAC;;;AHgE/B,iCAAiC;EGtF7B,KAAK,EAAE,IAAsB;EAG3B,OAAO,EAAE,KAAK;EAed,YAAoB,EAAE,aAA+B;EACrD,KAAK,EAAE,aAAuC;;AAE9C,4CAAa;EACX,YAAoB,EAAE,CAAC;;ACA7B,iDAAwB;EACtB,YAAoB,EAAE,CAAC;;AAEvB,mDAA0B;EACxB,KAAK,EALY,IAAkC;;;AJqEzD,iCAAiC;EG1F7B,KAAK,EAAE,IAAsB;EAG3B,OAAO,EAAE,KAAK;EAed,YAAoB,EAAE,aAA+B;EACrD,KAAK,EAAE,cAAuC;;AAE9C,4CAAa;EACX,YAAoB,EAAE,CAAC;;ACA7B,iDAAwB;EACtB,YAAoB,EAAE,CAAC;;AAEvB,mDAA0B;EACxB,KAAK,EALY,IAAkC;;;AJ0EzD,uDAAuD;EACrD,MAAM,EAAE,SAA2B;EACnC,SAAS,EAAE,GAAG;;;AAEhB,oBAAoB;EAClB,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,SAA2B;EACnC,SAAS,EAAE,GAAG;;;AAOZ,itBAAqP;EACnP,KAAK,EAAE,IAAI;;;AAIjB,uBAAuB;EACrB,OAAO,EAAE,YAAY;EACrB,YAAY,EAAE,KAAK;EACnB,KAAK,EAAE,IAAI;EACX,cAAc,EAAE,MAAM;EACtB,SAAS,EAAE,GAAG;;;AAEhB,gBAAgB;EACd,OAAO,EAAE,KAAK;EACd,KAAK,EN7H+B,IAAI;EM8HxC,SAAS,EAAE,GAAG;EACd,UAAU,EAAE,QAAO;EACnB,UAAU,EAAE,MAAM;;AAClB,kBAAC;EACC,SAAS,EAAE,OAAO;EAClB,UAAU,EAAE,MAAM;EAClB,aAAa,EAAE,GAAqB;;AACtC,6BAAY;EACV,aAAa,EAAE,CAAC;;;AA4DpB,KAAK;EACH,WAAW,EAAE,MAAM;;;AAGnB,+DAAmD;EACjD,kBAAkB,EAAE,MAAM;EAC1B,MAAM,EAAE,OAAO;EACf,WAAW,EJjJuB,2DAA2D;EIkJ7F,SAAS,EAAE,OAAO;;AACpB,6SAAqP;EACnP,kBAAkB,EAAE,IAAI;EACxB,OAAO,EAAE,GAAqB;EAC9B,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,cAA6B;EACrC,SAAS,EAAE,GAAG;EACd,WAAW,EJzJuB,2DAA2D;EI0J7F,UAAU,EAAE,oBAAmC;EAC/C,aAAa,EAAE,CAAC;ExBxNZ,kBAAoB,EAAE,kBAAM;EAK5B,eAAiB,EAAE,kBAAM;EAezB,UAAY,EAAE,kBAAM;;AwBuM1B,4BAAwB;EACtB,OAAO,EAAE,iBAAkB;;AAC7B,eAAW;EACT,MAAM,EAAE,OAAO;;AACjB,2CAAmC;ExB/N7B,kBAAoB,EwBgOZ,UAAU;ExB3NlB,eAAiB,EwB2NT,UAAU;ExB5MlB,UAAY,EwB4MJ,UAAU;EACtB,OAAO,EAAE,CAAC;EACV,YAAY,EAAE,QAAO;EACrB,OAAO,EAAE,IAAI;EACb,MAAM,EAAE,IAAI;;AACd,oBAAgB;ExBrOV,kBAAoB,EwBsOZ,UAAU;ExBjOlB,eAAiB,EwBiOT,UAAU;ExBlNlB,UAAY,EwBkNJ,UAAU;;AACtB,mGAA6D;EAC3D,kBAAkB,EAAE,IAAI;;AAC5B,iYAAyU;EACvU,OAAO,EAAE,CAAC;EACV,OAAO,EAAE,cAAc;EACvB,YAAY,ENxLsB,IAAU;;AMyL9C,oBAAgB;EACd,YAAY,EAAE,eAA8B;;AAC9C,iFAAqE;EACnE,OAAO,EAAE,gBAAsB;EAC/B,OAAO,EAAE,gBAAgB;;AAC3B,ybAAiY;EAC/X,MAAM,EAAE,WAAW;EACnB,gBAAgB,EAAE,OAAmC;;;AAEzD,iEAAiE;EAC/D,KAAK,ENzN+B,OAAI;EM0NxC,MAAM,EAAE,iBAAc;;;AACxB,mFAAmF;EACjF,YAAY,EN5NwB,OAAI;;;AM8NxC,2HAA+G;EAC7G,aAAa,EN/NqB,OAAI;;;AMiO1C,oBAAoB;EAClB,OAAO,EAAE,IAAqB;EAC9B,SAAS,EAAE,IAAI;;;AAKjB,QAAQ;EACN,QAAQ,EAAE,IAAI;EACd,cAAc,EAAE,GAAG;EACnB,KAAK,EAAE,IAAI;EACX,WAAW,EJ7MyB,2DAA2D;;;AI8MjG,gBAAgB;EACd,OAAO,EAAE,aAAgB;EACzB,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,cAA6B;EACrC,SAAS,EAAE,GAAG;EACd,UAAU,EAAE,oBAAmC;ExBhRzC,kBAAoB,EAAE,kBAAM;EAK5B,eAAiB,EAAE,kBAAM;EAezB,UAAY,EAAE,kBAAM;;;AwB+P5B,MAAM;EACJ,MAAM,EAAE,cAA6B;EACrC,gBAAgB,EJ3OoB,IAAM;;AI4O1C,gBAAW;EACT,MAAM,EAAE,IAAI;;;AAChB,4BAA4B;EAC1B,OAAO,EAAE,CAAC;;;AACZ,2FAA2F;EACzF,MAAM,EAAE,WAAW;EACnB,gBAAgB,EAAE,OAAmC;;;AAKrD,+DAAuD;EACrD,MAAM,EAAE,WAAW;;;AACvB,uBAAuB;EACrB,MAAM,EAAE,KAAuB;EAE/B,KAAK,EJhQ+B,OAAW;EIiQ/C,OAAO,EAAE,KAAK;;AACd,mCAAK;EACH,cAAc,EAAE,QAAQ;;;AAI5B,uBAAuB;EACrB,OAAO,EAAE,YAAY;EACrB,QAAQ,EAAE,MAAM;EAChB,KAAK,EAAE,CAAC;EACR,cAAc,EAAE,MAAM;;;AAuBxB,kCAAkC;EAChC,WAAW,EAAE,MAAM;EACnB,OAAO,EAAE,GAAqB;;AAC9B,sEAAiB;EACf,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,YAAY;EACrB,SAAS,EAAE,GAAG;EACd,gBAAgB,EJ1RkB,OAAmB;EI2RrD,MAAM,EAAE,cAA6B;EACrC,KAAK,EN7U6B,IAAI;;;AM+U1C,kCAAkC;EAChC,WAAW,EAAE,CAAC;;;AAChB,kCAAkC;EAChC,YAAY,EAAE,CAAC;;;AAcjB,UAAU;EACR,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,KAAK;EACd,MAAM,ENjV8B,IAAI;EMkVxC,UAAU,EAAE,IAAqB;EACjC,MAAM,EAAE,OAAO;;AACf,iBAAQ;EACN,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,EAAE;EACX,OAAO,EAAE,KAAK;EACd,IAAI,EAAE,CAAC;EACP,GAAG,EAAE,CAAC;EACN,KAAK,EAAE,IAAuB;EAC9B,MAAM,EAAE,IAAqB;EAC7B,aAAa,EAAE,GAAG;EAClB,UAAU,EN9WwB,IAAI;ElBNlC,kBAAoB,EAAE,oBAAM;EAK5B,eAAiB,EAAE,oBAAM;EAezB,UAAY,EAAE,oBAAM;;AwBkW1B,gBAAO;EACL,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,EAAE;EACX,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,aAAa,EAAE,GAAG;EAClB,UAAU,ENxXwB,IAAI;EMyXtC,IAAI,EAAE,IAAI;EACV,GAAG,EAAE,IAAI;ExB/XL,kBAAoB,EAAE,oBAAM;EAK5B,eAAiB,EAAE,oBAAM;EAezB,UAAY,EAAE,oBAAM;;AwB6W1B,eAAI;EACF,QAAQ,EAAE,QAAQ;EAClB,IAAI,EAAE,IAAqB;EAC3B,OAAO,EAAE,KAAK;EACd,SAAS,EAAE,IAAI;EACf,KAAK,ENhY6B,IAAI;EMiYtC,WAAW,EAAE,CAAC;;;AAEhB,wBAAQ;EACN,UAAU,EAAE,OAAmB;;AACjC,uBAAO;EACL,IAAI,ENrX8B,IAAI;EMsXtC,UAAU,EJ/XwB,OAAM;;;AIiY5C,mBAAmB;EACjB,MAAM,EAAE,WAAW;EACnB,OAAO,EAAE,GAAE;;;AAgDX,2GAAyB;EACvB,KAAK,ENpa6B,OAAI;;AMsatC,22BAAqP;EACnP,MAAM,EAAE,iBAAc;;AAC1B,iDAAQ;EACN,MAAM,EAAE,iBAAc;;;AAE1B,mBAAmB;EACjB,WAAW,EAAE,MAAM;;AACnB,qCAAiB;EACf,OAAO,EAAE,aAAgB;EACzB,OAAO,EAAE,YAAY;EACrB,SAAS,EAAE,GAAG;;;AAClB,gEAAgE;EAC9D,KAAK,EJlc+B,OAAM;;;AIqc5C,+DAA+D;EAC7D,KAAK,ENtb+B,OAAI;;;AMyb1C,gEAAgE;EAC9D,KAAK,ENzc+B,OAAO;;;AM4c7C,6DAA6D;EAC3D,KAAK,ENrZ+B,OAAW;;;AM2ZjD,UAAU;ExBleF,iBAAoB,EAAE,aAAM;EAK5B,cAAiB,EAAE,aAAM;EAKzB,aAAgB,EAAE,aAAM;EAKxB,YAAe,EAAE,aAAM;EAKvB,SAAY,EAAE,aAAM;;;AwBgd5B,WAAW;ExBpeH,iBAAoB,EAAE,cAAM;EAK5B,cAAiB,EAAE,cAAM;EAKzB,aAAgB,EAAE,cAAM;EAKxB,YAAe,EAAE,cAAM;EAKvB,SAAY,EAAE,cAAM;;;AwBkd5B,WAAW;ExBteH,iBAAoB,EAAE,cAAM;EAK5B,cAAiB,EAAE,cAAM;EAKzB,aAAgB,EAAE,cAAM;EAKxB,YAAe,EAAE,cAAM;EAKvB,SAAY,EAAE,cAAM;;;AwBod5B,OAAO;ExBxeC,iBAAoB,EAAE,UAAM;EAK5B,cAAiB,EAAE,UAAM;EAKzB,aAAgB,EAAE,UAAM;EAKxB,YAAe,EAAE,UAAM;EAKvB,SAAY,EAAE,UAAM;;AwBsd1B,iBAAW;ExB1eL,iBAAoB,EwB2eL,wBAAwB;ExBtevC,cAAiB,EwBseF,wBAAwB;ExBjevC,aAAgB,EwBieD,wBAAwB;ExB5dvC,YAAe,EwB4dA,wBAAwB;ExBvdvC,SAAY,EwBudG,wBAAwB;;AAC7C,kBAAY;ExB5eN,iBAAoB,EwB6eL,yBAAyB;ExBxexC,cAAiB,EwBweF,yBAAyB;ExBnexC,aAAgB,EwBmeD,yBAAyB;ExB9dxC,YAAe,EwB8dA,yBAAyB;ExBzdxC,SAAY,EwBydG,yBAAyB;;AAC9C,kBAAY;ExB9eN,iBAAoB,EwB+eL,yBAAyB;ExB1exC,cAAiB,EwB0eF,yBAAyB;ExBrexC,aAAgB,EwBqeD,yBAAyB;ExBhexC,YAAe,EwBgeA,yBAAyB;ExB3dxC,SAAY,EwB2dG,yBAAyB;;;AAEhD,yCAAyC;EAErC,8BAAqB;IACnB,MAAM,EAAE,SAAS;;EAEjB,2aAAqP;IACnP,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,KAAK;;EAClB,cAAK;IACH,aAAa,EAAE,KAAK;IACpB,OAAO,EAAE,KAAK;;;EAEhB,8YAAqO;IACnO,aAAa,EAAE,CAAC;;;EAElB,wCAAuB;IACrB,aAAa,EAAE,KAAK;IACpB,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,KAAK;IACd,KAAK,EAAE,IAAI;;EACb,4BAAW;IACT,MAAM,EAAE,WAAW;;;EACvB,mEAAmE;IACjE,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,GAAG;IACd,OAAO,EAAE,KAAuB;;;AHnfhC,oCAAsB;EQhC1B,YAAY;IAER,OAAO,EAAE,IAAI;;;;AR8Bb,oCAAsB;EQ5B1B,YAAY;IAER,OAAO,EAAE,IAAI;;;;AAEjB,WAAW;EACT,KAAK,EAAE,IAAI;;;AAEb,YAAY;EACV,KAAK,EAAE,KAAK;;;AAEd,WAAW;EACT,KAAK,EAAE,IAAI;;;AC4Cb,qEAAS;EACP,eAAe,EAAE,QAAQ;EACzB,cAAc,EAAE,CAAC;EACjB,WAAW,EAAE,IAAI;EACjB,aAAa,EZ/BuB,IAAI;;AYgCxC,6FAAO;EACL,KAAK,EAAE,IAAI;EACX,IAAI,EAAE,8BAA8B;EACpC,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,MAAM;;AACpB,8JAAM;EACJ,SAAS,EZjByB,GAAG;EYkBrC,MAAM,EAAE,CAAC;EACT,QAAQ,EAAE,OAAO;EACjB,OAAO,EZnB2B,QAAmC;;AYoBvE,sOAA8B;EAC5B,iBAAiB,EAAE,CAAC;;AACtB,uFAAK;EACH,KAAK,EAAE,IAAI;EACX,UAAU,EAAE,IAAI;EAChB,cAAc,EAAE,MAAM;EACtB,WAAW,EAAE,MAAM;;AACnB,gGAAE;EACA,WAAW,EZnDqB,IAAI;EYoDpC,aAAa,EAAE,iBAA6B;;AAChD,8EAAE;EACA,gBAAgB,EAAE,WAAW;EAC7B,cAAc,EAAE,MAAM;;;AAE1B,oFAAc;EACZ,WAAW,EAAE,IAAuB;;AACpC,qHAAY;EACV,aAAa,EAAE,CAAC;;;AACpB,8HAA4B;EAC1B,KAAK,EAAE,EAAE;EACT,aAAa,EAAE,CAAC;;AAChB,4XAA0C;EACxC,MAAM,EAAE,CAAC;;;AAEb,mBAAmB;EACjB,KAAK,EVlD+B,IAAY;EUmDhD,SAAS,EAAE,GAAG;;;AAChB,kBAAkB;EAChB,KAAK,EVrD+B,IAAY;EUsDhD,SAAS,EAAE,GAAG;;;AAIhB,6HAAyD;EACvD,gBAAgB,EV7CoB,OAAmB;;;AU+CzD,gBAAgB;EACd,gBAAgB,EVhDoB,OAAmB;;;;AUqDzD,mDAAsB;EACpB,MAAM,EAAE,iBAA6B;;AACrC,yDAAE;EACA,aAAa,EAAE,iBAA6B;EAC5C,WAAW,EAAE,iBAA6B;;AAC5C,qGAAwB;EACtB,mBAAmB,EAAE,CAAC;;;AAE1B,kBAAkB;EAChB,MAAM,EAAE,iBAA6B;;;AAGrC,0BAAE;EACA,aAAa,EAAE,iBAA6B;;AAC9C,gDAAwB;EACtB,mBAAmB,EAAE,CAAC;;;AAGxB,6CAAwB;EACtB,mBAAmB,EAAE,CAAC;;AACxB,gDAAM;EACJ,YAAY,EAAE,SAAS;EACvB,aAAa,EAAE,iBAA6B;;AAC9C,6CAAwB;EACtB,mBAAmB,EAAE,CAAC;;;;AAG1B,oBAAoB;EAClB,aAAa,EZhHuB,IAAI;EYiHxC,SAAS,EAAE,IAAI;EACf,QAAQ,EAAE,IAAI;;AACd,0BAAK;EACH,aAAa,EAAE,YAAY;;AAC3B,4DAAM;EACJ,WAAW,EAAE,MAAM;;;ACzIzB,CAAC;EACC,KAAK,EXN+B,OAAmB;EWOvD,eAAe,EAAE,IAAI;EACrB,MAAM,EAAE,OAAO;;AACf,OAAO;EACL,KAAK,EXR6B,OAAyB;;AWS7D,SAAS;EACP,KAAK,EXX6B,OAAwB;;;AWqC9D,IAAI;EACF,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,MAAM;;;AAEpB,IAAI;EACF,WAAW,EXmByB,2DAA2D;EWlB/F,WAAW,EAAE,MAAM;EACnB,KAAK,EXN+B,OAAW;EWO/C,UAAU,EAAE,IAAI;EAChB,UAAU,EAAE,MAAM;EAClB,UAAU,EbnD0B,OAAO;;;AaqD7C,aAAa;EACX,UAAU,EAAE,IAAI;;;AAElB,eAAe;EACb,UAAU,EAAE,MAAM;;;AAEpB,cAAc;EACZ,UAAU,EAAE,KAAK;;;AAEnB,cAAc;EACZ,SAAS,EAAE,IAAI;;;AAEjB,eAAe;EACb,SAAS,EAAE,IAAI;;;AAEjB,qBAAqB;EACnB,SAAS,EAAE,GAAG;;;AAEhB,eAAe;EACb,eAAe,EAAE,YAAY;;;AAE/B,gBAAgB;EACd,KAAK,EAAE,kBAAkB;;;AAC3B,uBAAuB;EACrB,KAAK,EAAE,kBAAgC;;;AACzC,aAAa;EACX,KAAK,EAAE,kBAAgB;;;AACzB,oBAAoB;EAClB,KAAK,EAAE,kBAA8B;;;AACvC,gBAAgB;EACd,KAAK,EAAE,kBAAiB;;;AAC1B,uBAAuB;EACrB,KAAK,EAAE,kBAA+B;;;AACxC,eAAe;EACb,KAAK,EAAE,kBAAe;;;AACxB,sBAAsB;EACpB,KAAK,EAAE,kBAA6B;;;AACtC,gBAAgB;EACd,KAAK,EAAE,kBAAsB;;;AAC/B,uBAAuB;EACrB,KAAK,EAAE,kBAAoC;;;AAkB7C,uEAAyB;EACvB,UAAU,EAAE,CAAC;EACb,WAAW,EAAE,GAAG;EAChB,WAAW,EXhDyB,8DAA8D;;;AWkDpG,CAAC;EACC,WAAW,Eb1FyB,IAAI;Ea2FxC,MAAM,EAAE,CAAC;EACT,SAAS,Eb/F2B,IAAI;EagGxC,aAAa,Eb7FuB,IAAI;;;Aa+F1C,EAAE;EACA,SAAS,EAAE,IAAI;;;AAEjB,2CAAE;EACA,SAAS,EAAE,IAAI;;;AAEjB,EAAE;EACA,SAAS,EAAE,IAAI;;;AAEjB,EAAE;EACA,SAAS,EAAE,IAAI;;;AAEjB,EAAE;EACA,SAAS,EAAE,IAAI;;;AAEjB,EAAE;EACA,SAAS,EAAE,IAAI;;;AAEjB,EAAE;EACA,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,GAAG;EACX,MAAM,EAAE,CAAC;EACT,UAAU,EAAE,iBAA6B;EACzC,MAAM,EAAE,MAAmB;EAC3B,OAAO,EAAE,CAAC;;;AAEZ,wCAAI;EACF,WAAW,EAAE,MAAM;EACnB,SAAS,EAAE,IAAI;EACf,UAAU,EXzG0B,IAAM;EW0G1C,MAAM,EAAE,iBAAiC;EACzC,SAAS,EAAE,GAAG;EACd,OAAO,EAAE,KAAK;EACd,WAAW,EXvFyB,oNAAoN;EWwFxP,KAAK,Eb1H+B,OAAI;Ea2HxC,UAAU,EAAE,IAAI;;AAChB,2CAAY;EACV,SAAS,EAAE,GAAG;;;AAmClB,2FAAmB;EACjB,UAAU,EAAE,IAAI;EAChB,WAAW,EbzKyB,IAAI;Ea0KxC,aAAa,Eb1KuB,IAAI;;Aa2KxC,uGAAE;EACA,UAAU,EAAE,IAAI;EAChB,WAAW,Eb7KuB,IAAI;;Aa8KtC,2JAAY;EACV,aAAa,EAAE,CAAC;;AAClB,mHAAE;EACA,aAAa,EAAE,CAAC;;AAClB,mHAAE;EACA,UAAU,EAAE,MAAM;;AAClB,+HAAE;EACA,UAAU,EAAE,MAAM;;AACtB,+HAAK;EACH,UAAU,EAAE,OAAO;;;AAEzB,oFAAsB;EACpB,UAAU,EAAE,OAAO;EACnB,WAAW,Eb3LyB,IAAI;Ea4LxC,aAAa,Eb5LuB,IAAI;;Aa6LxC,gGAAE;EACA,UAAU,EAAE,OAAO;EACnB,WAAW,Eb/LuB,IAAI;;AagMtC,oJAAY;EACV,aAAa,EAAE,CAAC;;AAClB,4GAAE;EACA,aAAa,EAAE,CAAC;;AAChB,wHAAE;EACA,UAAU,EAAE,IAAI;;;ACrOxB,eAAe;E9BuGb,KAAK,EAAE,CAAC;;AACR,6CAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,qBAAO;EACL,KAAK,EAAE,IAAI;;;A8B1Gf,kBAAkB;EAChB,OAAO,EAAE,YAAY;;AACrB,uCAAsB;EACpB,KAAK,EAAE,KAAK;;AACd,oBAAC;EACC,OAAO,EAAE,YAAY;EACrB,OAAO,EAAE,GAAG;;AACZ,gCAAa;EACX,YAAY,EAAE,CAAC;;AACnB,+FAAI;EACF,OAAO,EAAE,GAAG;EACZ,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,IAAI;;AAChB,uHAAS;EACP,KAAK,EZ8B2B,OAAW;;;AY7BjD,qBAAqB;EACnB,aAAa,EAAE,CAAC;EAChB,KAAK,EZ8B+B,OAAW;EY7B/C,SAAS,EAAE,GAAG;EACd,OAAO,EAAE,YAAY;;;AXUnB,oCAAsB;EWNxB,qBAAqB;IACnB,OAAO,EAAE,IAAI;;;EACf,uCAAuC;IACrC,OAAO,EAAE,IAAI;;;AAEjB,YAAY;EACV,uCAAuC;IACrC,OAAO,EAAE,IAAI;;;ACjCjB,SAAS;EACP,QAAQ,EAAE,KAAK;EACf,GAAG,ECAO,OAAO;;;ADGjB,gBAAO;EACL,eAAe,EAAE,IAAI;;;AAEzB,cAAc;E/B+FZ,KAAK,EAAE,CAAC;;AACR,2CAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,oBAAO;EACL,KAAK,EAAE,IAAI;;A+BnGb,oCAAM;EACJ,OAAO,EAAE,YAAY;;AACvB,uBAAQ;EACN,UAAU,EAAE,wBAAoB;;AAEhC,6BAAa;EACX,WAAW,EAAE,iBAAyB;;AACxC,8BAAc;EACZ,YAAY,EAAE,iBAAyB;;AAC3C,gBAAC;EACC,MAAM,EAAE,IAAmB;EAC3B,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,IAAmB;EAChC,OAAO,EAAE,MAAiB;;;AAE9B,iBAAiB;EACf,KAAK,EfuD+B,KAAK;;AetDzC,qDAAiB;EACf,MAAM,EAAE,IAAmB;EAC3B,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,IAAmB;EAChC,OAAO,EAAE,SAAS;EAClB,aAAa,EAAE,CAAC;EAChB,OAAO,EAAE,KAAK;EACd,WAAW,EAAE,IAAI;EACjB,cAAc,EAAE,SAAS;EACzB,SAAS,EAAE,GAAG;EACd,KAAK,EbI6B,OAAwB;EaH1D,WAAW,EAAE,MAAM;;AAErB,oBAAE;EACA,aAAa,EAAE,CAAC;;AAEhB,+BAAY;EACV,UAAU,EAAE,iBAAyB;;AACvC,kCAAe;EACb,aAAa,EAAE,iBAAyB;;AAC1C,4BAAS;EACP,UAAU,EAAE,OAA4C;;AACxD,8BAAC;EACC,KAAK,EbDyB,IAAY;EaE1C,YAAY,EAAE,iBAAsD;EACpE,OAAO,EAAE,gBAAyB;;AAClC,oCAAO;EACL,UAAU,EAAE,OAA4C;;AAC9D,qGAAI;EACF,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,OAAO;EACnB,KAAK,EAAE,OAAO;EACd,YAAY,EAAE,CAAC;EACf,aAAa,EAAE,CAAC;;AAElB,wCAAmB;EACjB,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,IAAI;EACX,WAAW,EAAE,MAAM;EAGnB,SAAS,EAAE,KAAI;EACf,WAAW,EAAE,KAAK;EAClB,KAAK,EAAE,OAA8B;;AAGzC,2DAAuB;EACrB,KAAK,Eb3B6B,OAAW;Ea4B7C,OAAO,EAAE,gBAAmB;EAC5B,WAAW,EAAE,IAAI;EACjB,QAAQ,EAAE,QAAQ;EAClB,UAAU,EbtBwB,OAAyB;EauB3D,MAAM,EAAE,IAAI;EACZ,YAAY,EAAE,YAAY;;AAE1B,uEAAO;EACL,UAAU,Eb3BsB,OAAyB;;Aa4BzD,+GAAmB;EACjB,KAAK,EbpCyB,IAAY;;AaqC9C,mGAAmB;EAGjB,OAAO,EAAE,KAAK;EACd,SAAS,EAAE,KAAI;EACf,WAAW,EAAE,KAAK;EAClB,KAAK,EAAE,OAA8B;;AAEzC,2CAAyB;EACvB,aAAa,EAAE,iBAAsD;EACrE,UAAU,EAAE,iBAAsD;;AAIlE,sHAAI;EACF,OAAO,EAAE,IAAI;;AACf,sIAAc;EACZ,OAAO,EAAE,KAAK;;AAGd,2CAAG;EACD,UAAU,EAAE,OAA4C;EACxD,OAAO,EAAE,gBAAyB;;AACpC,yDAAiB;EACf,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,OAA4C;EACxD,OAAO,EAAE,gBAAyB;;AACtC,2DAA2B;EACzB,KAAK,EbjE2B,IAAY;;AakE9C,mDAAmB;EACjB,KAAK,EAAE,OAA4C;;AACvD,+BAAa;EACX,SAAS,EAAE,KAAI;;AAEb,2CAAG;EACD,UAAU,EAAE,OAA4C;EACxD,OAAO,EAAE,gBAAyB;;AACpC,yDAAiB;EACf,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,OAA4C;EACxD,OAAO,EAAE,gBAAyB;;AACtC,2DAA2B;EACzB,KAAK,Eb/E2B,IAAY;;AagF9C,mDAAmB;EACjB,KAAK,EAAE,OAA4C;;AACvD,+BAAa;EACX,SAAS,EAAE,KAAI;;AAEjB,+BAAa;EACX,OAAO,EAAE,KAAK;;AAChB,uBAAK;EACH,aAAa,EAAE,CAAC;EAChB,OAAO,EAAE,IAAI;;AAEb,kCAAK;EACH,OAAO,EAAE,KAAK;;AAClB,4BAAU;EACR,aAAa,EAAE,CAAC;EAChB,KAAK,Eb9F6B,OAAW;Ea+F7C,WAAW,EAAE,MAAM;;AACrB,mBAAC;EACC,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,gBAAmB;EAC5B,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,QAAQ;EAClB,SAAS,EAAE,GAAG;EACd,KAAK,EbvG6B,OAAW;;AawG7C,yBAAO;EACL,gBAAgB,EAAE,OAAoC;EACtD,MAAM,EAAE,OAAO;;AACf,6CAAmB;EACjB,KAAK,Eb5GyB,OAAW;;Aa6G7C,0BAAQ;EACN,gBAAgB,EfhFgB,OAAW;EeiF3C,MAAM,EAAE,OAAO;EACf,KAAK,Eb/G2B,IAAM;;AagHtC,8CAAmB;EACjB,KAAK,EbjHyB,IAAM;;;AamH5C,mBAAmB;EACjB,OAAO,EAAE,KAAK;EACd,KAAK,EfvF+B,KAAK;EewFzC,OAAO,EAAE,OAAW;EACpB,aAAa,EAAE,OAAW;EAC1B,OAAO,EfrF6B,GAAG;EesFvC,gBAAgB,EbnHoB,OAAO;EaoH3C,UAAU,EAAE,MAAM;EAClB,OAAO,EAAE,OAAW;EACpB,OAAO,EAAE,KAAK;EACd,KAAK,EbxH+B,OAAyB;EayH7D,aAAa,EAAE,OAAW;;AAC1B,oCAAgB;EACd,KAAK,EAAE,IAAI;EACX,aAAa,EAAE,IAAI;EACnB,OAAO,EAAE,QAAQ;EACjB,YAAY,EAAE,OAAuB;;AACvC,uBAAG;EACD,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,sBAA0B;EAClC,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,gBAAgB,Ef5GkB,OAAW;Ee6G7C,OAAO,EAAE,GAAG;EACZ,aAAa,EAAE,IAAI;;AACrB,6DAAqB;EACnB,KAAK,EbxI6B,OAAyB;EayI3D,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,YAAY;EACrB,OAAO,EAAE,OAA2C;EACpD,aAAa,EAAE,OAAW;;AAE1B,yEAAO;EACL,UAAU,EAAE,wBAAoB;;AAClC,+EAAQ;EACN,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,MAAM;EACd,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,aAAa,EAAE,CAAC;EAChB,SAAS,EAAE,IAAI;EACf,UAAU,EAAE,gBAAa;;AAEzB,yFAAQ;EACN,UAAU,EAAE,MAAM;;AACxB,iCAAa;EACX,UAAU,EAAE,SAAkB;EAC9B,aAAa,EAAE,OAAW;EAC1B,WAAW,EAAE,MAAM;EACnB,KAAK,EAAE,wBAAoB;;;AAI7B,gCAAM;EACJ,KAAK,EbrN6B,OAAmB;;AasNvD,2BAAC;EACC,KAAK,Eb7K6B,OAAW;;Aa8K7C,iCAAO;EACL,gBAAgB,EbzNgB,OAAmB;Ea0NnD,KAAK,Eb/K2B,IAAM;;;AaiL5C,gBAAgB;EjC3NR,kBAAoB,EAAE,gBAAM;EAK5B,eAAiB,EAAE,gBAAM;EAezB,UAAY,EAAE,gBAAM;EiCyM1B,QAAQ,EAAE,QAAQ;EAClB,OAAO,EAAE,CAAC;EACV,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,CAAC;;AACV,4BAAa;EACX,IAAI,EAAE,CAAC;EACP,KAAK,EAAE,IAAI;EACX,OAAO,EAAE,CAAC;;AACZ,0BAAW;EACT,KAAK,EAAE,IAAI;EACX,IAAI,EAAE,KAAK;EACX,OAAO,EAAE,CAAC;;AACZ,2BAAY;EACV,KAAK,EAAE,KAAK;EACZ,IAAI,EAAE,IAAI;EACV,OAAO,EAAE,CAAC;;;AAGd,gBAAgB;EACd,UAAU,EbjM0B,OAAyB;;;AamM/D,gBAAgB;EACd,QAAQ,EAAE,QAAQ;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;;;AAEd,YAAY;EACV,QAAQ,EAAE,KAAK;EACf,GAAG,EAAE,CAAC;EACN,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EACP,cAAc,EAAE,GAAG;EACnB,KAAK,EfrL+B,KAAK;EesLzC,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,IAAI;EAChB,UAAU,EbpN0B,OAAsB;EaqN1D,OAAO,EfrL6B,GAAG;;;AeuLzC,eAAe;EACb,KAAK,EAAE,KAAyB;EAChC,QAAQ,EAAE,QAAQ;EAClB,UAAU,EAAE,MAAM;EAClB,UAAU,EAAE,MAAM;EAClB,MAAM,EAAE,IAAI;;;AAEd,WAAW;EACT,OAAO,EAAE,IAAI;EACb,UAAU,Eb9Q0B,OAAmB;Ea+QvD,KAAK,EbpO+B,IAAM;EaqO1C,OAAO,EAAE,gBAAuB;EAChC,QAAQ,EAAE,QAAQ;EAClB,WAAW,EAAE,IAAI;EACjB,UAAU,EAAE,MAAM;EAClB,SAAS,EAAE,IAAI;E/BrLf,KAAK,EAAE,CAAC;;AACR,qCAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,iBAAO;EACL,KAAK,EAAE,IAAI;;A+BiLb,aAAC;EACC,KAAK,Eb5O6B,IAAM;Ea6OxC,WAAW,EAAE,IAAI;;AAEnB,eAAG;EACD,YAAY,EAAE,IAAqB;EACnC,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,gBAAgB,EftNkB,OAAW;EeuN7C,OAAO,EAAE,GAAG;EACZ,aAAa,EAAE,IAAI;;AACrB,aAAC;EACC,SAAS,EAAE,IAAI;EACf,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,OAAO;EACf,WAAW,EAAE,OAAO;;;AAExB,oBAAoB;EAClB,WAAW,Ef/NyB,KAAK;EegOzC,UAAU,EbzP0B,OAAyB;Ea0P7D,UAAU,EAAE,IAAI;;;AAElB,eAAe;EACb,OAAO,EAAE,eAAmB;EAC5B,MAAM,EAAE,IAAI;EACZ,SAAS,EbxS2B,KAAK;EaySzC,MAAM,EAAE,IAAI;;;AAEd,aAAa;EACX,QAAQ,EAAE,KAAK;EACf,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,UAAU,EAAE,kBAAc;EAC1B,OAAO,EAAE,IAAI;EACb,OAAO,EAAE,GAAkB;;AAC3B,gBAAI;EACF,OAAO,EAAE,KAAK;;;AAClB,MAAM;EACJ,KAAK,EbnR+B,IAAY;;AaoRhD,QAAC;EACC,aAAa,EAAE,IAAqB;;AACtC,+FAAgB;EACd,OAAO,EAAE,GAAG;EACZ,WAAW,EbhQuB,oNAAoN;EaiQtP,SAAS,EAAE,GAAG;EACd,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,IAAI;EACZ,KAAK,Eb5R6B,IAAY;;;Aa8RlD,mBAAmB;E/BxOjB,KAAK,EAAE,CAAC;;A+ByOR,qDAAiB;EACf,KAAK,EAAE,IAAI;;A/BzOb,qDAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,yBAAO;EACL,KAAK,EAAE,IAAI;;;A+BuOf,wBAAwB;EACtB,UAAU,EAAE,IAAI;E/B9OhB,KAAK,EAAE,CAAC;;AACR,+DAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,8BAAO;EACL,KAAK,EAAE,IAAI;;;A+B4Ob,0BAAU;EACR,aAAa,Ef1TqB,IAAI;Ee2TtC,aAAa,EAAE,iBAA6B;EAC5C,cAAc,Ef5ToB,IAAI;;Ae6TxC,sCAAsB;EACpB,UAAU,EAAE,iBAA6B;EACzC,WAAW,Ef/TuB,IAAI;;AegUxC,4BAAY;EACV,SAAS,EAAE,IAAI;EACf,aAAa,EAAE,IAAqB;EACpC,OAAO,EAAE,YAAY;;AACvB,wBAAQ;EACN,KAAK,EbpT6B,IAAY;EaqT9C,SAAS,EAAE,GAAG;;;AZtUd,oCAAsB;EY0UxB,gBAAgB;IACd,UAAU,EbnTwB,OAAyB;;;EaoT7D,WAAW;IACT,OAAO,EAAE,KAAK;;;EAChB,YAAY;IAER,IAAI,EAAE,MAAmB;;EAG3B,kBAAO;IACL,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,CAAC;;;EACX,eAAe;IACb,KAAK,EAAE,IAAI;;;EACb,mBAAmB;IACjB,KAAK,EAAE,IAAI;;;EACb,yBAAyB;IACvB,KAAK,EAAE,IAAI;;;EACb,oBAAoB;IAClB,WAAW,EAAE,CAAC;;EACd,oCAAe;IACb,OAAO,EC7XD,OAAO;;ED8Xf,0BAAO;IACL,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,GAAG;IACT,GAAG,EAAE,CAAC;IACN,MAAM,EAAE,IAAI;IACZ,QAAQ,EAAE,MAAM;;;AAEtB,qCAA+C;EAC7C,oBAAoB;IAClB,UAAU,EAAE,mBAAe;;;EAC7B,eAAe;IACb,MAAM,EAAE,CAAC;IACT,UAAU,EbrVwB,OAAyB;;;AauV/D,YAAY;EACV,mCAAmC;IACjC,OAAO,EAAE,IAAI;;;EACf,oBAAoB;IAClB,WAAW,EAAE,CAAC;;;AEnZlB,aAAa;EACX,QAAQ,EAAE,KAAK;EACf,MAAM,EAAE,CAAC;EACT,IAAI,EAAE,CAAC;EACP,UAAU,EAAE,MAAM;EAClB,KAAK,EjB4E+B,KAAK;EiB3EzC,KAAK,EfkD+B,OAAyB;EejD7D,UAAU,EAAE,OAAkC;EAC9C,WAAW,Ef8DyB,2DAA2D;Ee7D/F,OAAO,EjB+E6B,GAAG;;AiB9EvC,eAAC;EACC,KAAK,EfH6B,OAAmB;EeIrD,eAAe,EAAE,IAAI;;AACvB,8BAAgB;EACd,OAAO,EAAE,IAAI;;AACf,kCAAoB;EAClB,OAAO,EAAE,IAAqB;EAC9B,gBAAgB,EAAE,OAAkC;EACpD,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,KAAK;EACjB,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,OAAO;EACf,KAAK,EfC6B,OAAM;ElBgF1C,KAAK,EAAE,CAAC;;AACR,mFAAS;EAEP,OAAO,EAAE,KAAK;EACd,OAAO,EAAE,EAAE;;AACb,wCAAO;EACL,KAAK,EAAE,IAAI;;AiCrFX,01DAAG;EACD,KAAK,Ef+B2B,OAAyB;;Ae9B3D,0FAAQ;EACN,KAAK,EAAE,IAAI;;AACb,6CAAU;EACR,KAAK,EAAE,IAAI;;AACb,kDAAiB;EACf,gBAAgB,EjBQgB,OAAI;EiBPpC,KAAK,EfmB2B,IAAM;;AelBxC,yDAAwB;EACtB,gBAAgB,EfkCgB,OAAO;EejCvC,KAAK,EjBzB2B,IAAI;;AiB0BxC,sBAAU;EACR,UAAU,EAAE,IAAI;;AAClB,0CAA8B;EAC5B,OAAO,EAAE,KAAK;;AAChB,iCAAmB;EACjB,SAAS,EAAE,GAAG;EACd,OAAO,EAAE,IAAqB;EAC9B,KAAK,EfM6B,IAAY;EeL9C,OAAO,EAAE,IAAI;;AACb,oCAAE;EACA,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,GAAG;EACX,MAAM,EAAE,CAAC;EACT,MAAM,EAAE,MAAM;EACd,OAAO,EAAE,CAAC;EACV,UAAU,EAAE,iBAA6C;;AAC3D,oCAAE;EACA,OAAO,EAAE,YAAY;EACrB,MAAM,EAAE,CAAC;;AACT,sCAAC;EACC,OAAO,EAAE,YAAY;EACrB,OAAO,EAAE,GAAqB;EAC9B,KAAK,EfFyB,OAAyB;;AeG7D,uBAAW;EACT,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,KAAK,EAAE,IAAI;EACX,IAAI,EAAE,IAAI;EACV,MAAM,EAAE,IAAI;EACZ,SAAS,EjBgByB,KAAK;;AiBfvC,kCAAU;EACR,KAAK,EAAE,IAAI;;AACb,oEAAQ;EACN,KAAK,EAAE,IAAI;;AACb,qDAA+B;EAC7B,UAAU,EAAE,KAAK;;AACjB,gIAAQ;EACN,KAAK,EAAE,IAAI;;AACb,gEAAU;EACR,KAAK,EAAE,IAAI;;AACf,4CAAoB;EAClB,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,KAAuB;EAChC,OAAO,EAAE,KAAK;EACd,UAAU,EAAE,MAAM;;;AdlDpB,oCAAsB;EcqDxB,aAAa;IACX,KAAK,EAAE,GAAG;IACV,OAAO,EAAE,IAAI;;EACb,mBAAO;IACL,OAAO,EAAE,KAAK;;;ACxElB,gBAAG;EACD,SAAS,EAAE,IAAI;EACf,MAAM,EAAE,IAAI;;AAEd,uBAAU;EACR,aAAa,ElBUqB,IAAI;;AkBTtC,iCAAS;EACP,UAAU,EAAE,MAAM;;AACpB,4CAAoB;EAClB,aAAa,EAAE,GAAG;;AAEtB,oCAAuB;EACrB,UAAU,EAAE,MAAM;;AAGpB,4DAAoC;EAClC,aAAa,ElBDqB,IAAI;;AkBIxC,wBAAW;EACT,eAAe,EAAE,IAAI;;AAGvB,4DAAiD;EAC/C,WAAW,EAAE,WAAW;EACxB,OAAO,EAAE,GAAO;EAChB,KAAK,EhBO6B,OAAW;EgBN7C,cAAc,EAAE,KAAK;EACrB,SAAS,EAAE,GAAG;EACd,MAAM,EAAE,OAAO;;AAIjB,uBAAU;EACR,WAAW,ElBnBuB,IAAI;EkBoBtC,WAAW,ElBpBuB,IAAI;EkBqBtC,aAAa,ElBrBqB,IAAI;;AkBuBxC,oEAA0C;EACxC,MAAM,EAAE,iBAA6B;EACrC,OAAO,EAAE,GAAG;EACZ,UAAU,EAAE,IAAI;EAEhB,MAAM,EAAE,YAAyB;;AACjC,oHAAuB;EACrB,MAAM,EAAE,IAAI;EACZ,MAAM,EAAE,CAAC;;AAEb,4CAA+B;EAC7B,KAAK,EAAE,IAAI;;AACb,2BAAc;EACZ,YAAY,EAAE,iBAA0C;EACxD,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,SAA2C;EACpD,WAAW,EhBEuB,oNAAoN;;AgBDxP,wCAA2B;EACzB,WAAW,EAAE,GAAG;EAChB,MAAM,EAAE,CAAC;EACT,OAAO,EAAE,SAA2C;EACpD,WAAW,EhBHuB,oNAAoN;EgBItP,OAAO,EAAE,KAAK;EACd,QAAQ,EAAE,IAAI;;AAChB,qGAA8D;EAC5D,SAAS,EAAE,IAAI;EACf,WAAW,EAAE,MAAM;;AAErB,YAAY;EACV,uGAAgE;IAC9D,WAAW,EAAE,QAAQ;;;AAKvB,4VAAK;EACH,aAAa,EAAE,CAAC;;AAKlB,qCAAQ;EACN,YAAY,EAAE,GAAG;;AAUrB,8BAAiB;EACf,YAAY,EAAE,kBAAc;;AAC5B,oEAAM;EACJ,UAAU,EAAE,sBAAsB;EAClC,YAAY,EAAE,6BAAyB;;AAG3C,2EAAiD;EAC/C,UAAU,EAAE,WAAW;;AACzB,2EAAiD;EAC/C,UAAU,EAAE,WAAW;;AAGzB,sDAA4B;EAC1B,aAAa,EAAE,IAAqB;;AACtC,wBAAW;EACT,WAAW,EAAE,GAAG;EAChB,aAAa,ElB5FqB,IAAI;;AkB6FxC,oCAAuB;EACrB,WAAW,ElB9FuB,IAAI;EkB+FtC,aAAa,EAAE,GAAG;;AAGpB,yBAAY;EACV,WAAW,EAAE,IAAI;EACjB,aAAa,EAAE,IAAqB;;AACtC,yBAAY;EACV,KAAK,EhBvF6B,OAAW;;AgBwF/C,yBAAY;EACV,KAAK,EAAE,KAAK;EACZ,MAAM,EAAE,iBAA2C;;AACrD,wBAAW;EACT,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,iBAA2C;;AACrD,0BAAa;EACX,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,KAAK;;AAMd,+UAAW;EACT,UAAU,EAAE,MAAM;EAClB,SAAS,EAAE,IAAI;;AAEf,2YAAO;EACL,OAAO,EAAE,GAAO;EAChB,WAAW,EAAE,WAAW;;AAC5B,ucAAyB;EACvB,UAAU,EAAE,OAAO;;AAEvB,8CAAiC;EAC/B,SAAS,EAAE,IAAI;;AAEjB,sBAAS;EACP,UAAU,EAAE,MAAM;;AAGpB,qBAAQ;EACN,KAAK,EAAE,KAAK;EACZ,KAAK,EAAE,GAAG;EACV,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,aAAuC;EAC/C,OAAO,ElB3I2B,IAAI;EkB4ItC,UAAU,EhB7GwB,OAAmB;EgB8GrD,MAAM,EAAE,iBAA+B;;AAEvC,2EAAS;EACP,SAAS,EAAE,GAAG;;AAChB,2BAAK;EACH,aAAa,EAAE,CAAC;;AAClB,oCAAc;EACZ,OAAO,EAAE,KAAK;EACd,WAAW,EhB9GqB,8DAA8D;EgB+G9F,WAAW,EAAE,IAAI;EACjB,UAAU,EhBtHsB,OAAmB;EgBuHnD,OAAO,EAAE,QAA2C;EACpD,MAAM,EAAE,KAAkB;EAC1B,aAAa,ElB1JmB,IAAI;EkB2JpC,SAAS,EAAE,IAAI;;AAEnB,yBAAY;EACV,UAAU,EhB1HwB,OAAO;EgB2HzC,OAAO,EAAE,YAAY;EACrB,WAAW,EAAE,IAAI;EACjB,OAAO,EAAE,KAAuB;;AAGlC,kEAAwC;EACtC,cAAc,EAAE,QAAQ;EACxB,QAAQ,EAAE,QAAQ;EAClB,GAAG,EAAE,MAAM;EACX,WAAW,EAAE,CAAC;EACd,SAAS,EAAE,GAAG;;AAIhB,0EAAgD;EAC9C,UAAU,EAAE,IAAI;EAChB,MAAM,EAAE,IAAI;EACZ,KAAK,EhB/J6B,IAAY;;AgBgK9C,kKAAM;EACJ,MAAM,EAAE,IAAI;EACZ,gBAAgB,EAAE,sBAAsB;EACxC,WAAW,EAAE,MAAM;;AACrB,4FAAQ;EACN,YAAY,EAAE,CAAC;EACf,aAAa,EAAE,CAAC;EAChB,cAAc,EAAE,GAAG;;AACrB,sKAAI;EACF,KAAK,EhBlL2B,IAAK;;AgBoLzC,sFAA4D;EAC1D,aAAa,EAAE,CAAC;;AAGlB;4DAAgD;EAE9C,UAAU,ElBlMwB,IAAI;;AkBoMxC,4GAAkF;EAChF,aAAa,ElBrMqB,IAAI;;AkB4MxC,6BAAgB;EAEd,MAAM,EAAE,IAAI;;AACZ,gCAAE;EACA,MAAM,EAAE,IAAI;;AACd,yCAAW;EACT,OAAO,EAAE,YAAY;;AACvB,yCAAW;EACT,aAAa,EAAE,IAAI;EACnB,UAAU,EAAE,IAAI;EAChB,WAAW,EAAE,MAAM;;AACrB,yCAAW;EACT,UAAU,EAAE,IAAI;;AAGpB,mDAAQ;EAEN,KAAK,ElBnP6B,IAAI;EkBoPtC,OAAO,EAAE,OAAO;;AAChB,6HAAO;EACL,SAAS,EAAE,eAAe;EAC1B,WAAW,EAAE,MAAM;;AAErB,2EAAS;EACP,KAAK,ElB7N2B,OAAI;;AkB8NtC,6HAAW;EACT,WAAW,EAAE,IAAI;EACjB,KAAK,EhBxN2B,OAAW;;AgB0N/C,yDAAY;EACV,KAAK,EhBlQ6B,OAAmB;;AgBmQvD,eAAE;EACA,aAAa,ElB5OqB,IAAI;;AkB6OtC,kBAAE;EACA,WAAW,EAAE,IAAI;;AAEnB,gFAAgB;EACd,aAAa,EAAE,eAAgC;;AAEjD,kBAAE;EACA,MAAM,EAAE,aAA4C;;AAMxD,8BAAiB;EACf,aAAa,ElB3PqB,IAAI;;AkB6PtC,iCAAE;EACA,OAAO,EAAE,KAAK;EACd,MAAM,EAAE,KAAuB;EAC/B,SAAS,EAAE,GAAG;EACd,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,OAA0B;EACtC,KAAK,EhB1O2B,OAAO;EgB2OvC,UAAU,EAAE,iBAAoC;EAChD,OAAO,EAAE,GAAqB;EAC9B,QAAQ,EAAE,QAAQ;;AAClB,wCAAQ;EACN,KAAK,EAAE,OAA0B;;AACnC,6CAAW;EACT,KAAK,EhB3PyB,OAAW;EgB4PzC,SAAS,EAAE,eAAe;;AAE9B,oCAAK;EACH,aAAa,EAAE,GAAqB;EACpC,MAAM,EAAE,IAAI;EACZ,WAAW,EAAE,iBAAuB;EACpC,UAAU,EAAE,OAAa;EACzB,KAAK,EhB1Q2B,IAAK;;AgB2QrC,gDAAW;EACT,KAAK,EhBrQyB,OAAW;EgBsQzC,SAAS,EAAE,eAAe;;AAC9B,6CAAc;EACZ,UAAU,EAAE,CAAC;;AAEf,yGAAQ;EACN,WAAW,EAAE,IAAI;;AACjB,yRAA2B;EACzB,gBAAgB,EAAE,WAAW;EAC7B,MAAM,EAAE,IAAI;EACZ,OAAO,EAAE,CAAC;EACV,SAAS,EAAE,eAAe;;AAC5B,oIAAU;EACR,WAAW,EAAE,IAAI;;AAErB,wCAAS;EACP,OAAO,EAAE,YAAY;EACrB,OAAO,EAAE,KAAK;EACd,KAAK,ElB5T2B,IAAI;EkB6TpC,WAAW,EAAE,IAAI;;AACnB,wCAAS;EACP,OAAO,EAAE,YAAY;EACrB,aAAa,EAAE,GAAG;;AAEtB,wDAA8B;EAC5B,OAAO,EAAE,YAAY;EACrB,KAAK,EhBvT6B,OAAM;EgBwTxC,SAAS,EAAE,GAAG;EACd,YAAY,ElBhTsB,IAAI;;AkBiTxC,2BAAc;EACZ,OAAO,EAAE,KAAK;EACd,KAAK,EAAE,KAAK;;AACd,qBAAQ;EACN,aAAa,EAAE,IAAI;EACnB,WAAW,EAAE,IAAI;;AAEnB,oDAAa;EACX,UAAU,EAAE,OAAO;EACnB,OAAO,EAAE,OAAO;EAChB,WAAW,EAAE,MAAM;EACnB,WAAW,EAAE,OAAO;EACpB,SAAS,EAAE,OAAO;EAClB,KAAK,EAAE,OAAO;EACd,MAAM,EAAE,OAAO;EACf,WAAW,EAAE,OAAO;;AACpB,sFAAgB;EACd,sBAAsB,EAAE,oBAAoB;;AAG5C,oGAAQ;EACN,YAAY,EAAE,GAAG;;AACvB,sBAAS;EACP,MAAM,EAAE,iBAAuC;EAC/C,UAAU,EAAE,OAA6B;EACzC,SAAS,EAAE,GAAG;EACd,WAAW,EAAE,GAAG;EAChB,aAAa,EAAE,GAAqB;EACpC,OAAO,EAAE,SAA4C;EACrD,MAAM,EAAE,QAA2B;;AACrC,6BAAgB;EACd,UAAU,EAAE,MAAM;;;AfhVlB,oCAAsB;EesVtB,qBAAQ;IACN,KAAK,EAAE,IAAI;;;ACvXjB,wBAAwB;EACtB,KAAK,EjB8C+B,OAAW;;;AiB5CjD,KAAK;EACH,UAAU,EAAE,MAAM;;;;ECHlB,WAAW,EAAE,aAAa;EAC1B,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,4GAA4G;;;EAGjH,WAAW,EAAE,aAAa;EAC1B,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,2GAA2G;;;EAGhH,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,+FAA+F;;;EAGpG,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,sFAAsF;;;EAG3F,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,4FAA4F;;;EAGjG,WAAW,EAAE,MAAM;EACnB,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,yGAAyG;;;EAG9G,WAAW,EAAE,aAAa;EAC1B,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,kHAAkH;;;EAGvH,WAAW,EAAE,aAAa;EAC1B,UAAU,EAAE,MAAM;EAClB,WAAW,EAAE,GAAG;EAChB,GAAG,EAAE,yGAAyG", -"sources": ["../../../bower_components/neat/app/assets/stylesheets/grid/_grid.scss","../../../bower_components/bourbon/dist/addons/_prefixer.scss","../../../bower_components/wyrm/sass/wyrm_core/_reset.sass","../../../bower_components/wyrm/sass/wyrm_core/_mixin.sass","../../../bower_components/font-awesome/scss/font-awesome.scss","../../../bower_components/font-awesome/scss/_path.scss","../../../bower_components/font-awesome/scss/_core.scss","../../../bower_components/font-awesome/scss/_larger.scss","../../../bower_components/font-awesome/scss/_fixed-width.scss","../../../bower_components/font-awesome/scss/_list.scss","../../../bower_components/font-awesome/scss/_variables.scss","../../../bower_components/font-awesome/scss/_bordered-pulled.scss","../../../bower_components/font-awesome/scss/_animated.scss","../../../bower_components/font-awesome/scss/_rotated-flipped.scss","../../../bower_components/font-awesome/scss/_mixins.scss","../../../bower_components/font-awesome/scss/_stacked.scss","../../../bower_components/font-awesome/scss/_icons.scss","../../../bower_components/font-awesome/scss/_screen-reader.scss","../../../bower_components/wyrm/sass/wyrm_core/_font_icon_defaults.sass","../../../bower_components/wyrm/sass/wyrm_core/_wy_variables.sass","../../../bower_components/wyrm/sass/wyrm_core/_alert.sass","../../../sass/_theme_variables.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_media.scss","../../../bower_components/wyrm/sass/wyrm_core/_button.sass","../../../bower_components/wyrm/sass/wyrm_core/_dropdown.sass","../../../bower_components/wyrm/sass/wyrm_core/_form.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_outer-container.scss","../../../bower_components/neat/app/assets/stylesheets/settings/_grid.scss","../../../bower_components/neat/app/assets/stylesheets/grid/_span-columns.scss","../../../bower_components/wyrm/sass/wyrm_core/_neat_extra.sass","../../../bower_components/wyrm/sass/wyrm_core/_generic.sass","../../../bower_components/wyrm/sass/wyrm_core/_table.sass","../../../bower_components/wyrm/sass/wyrm_core/_type.sass","../../../sass/_theme_breadcrumbs.sass","../../../sass/_theme_layout.sass","../../../bower_components/neat/app/assets/stylesheets/grid/_private.scss","../../../sass/_theme_badge.sass","../../../sass/_theme_rst.sass","../../../sass/_theme_mathjax.sass","../../../sass/_theme_font_local.sass"], -"names": [], -"file": "theme.css" -} diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf deleted file mode 100644 index 401ec0f3..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/FontAwesome.otf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf deleted file mode 100644 index 9addc892..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Bold.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Regular.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Regular.ttf deleted file mode 100644 index 592ccd20..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Inconsolata-Regular.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf deleted file mode 100644 index 1d23c706..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Bold.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-BoldItalic.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-BoldItalic.ttf deleted file mode 100644 index a3b8e332..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-BoldItalic.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Italic.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Italic.ttf deleted file mode 100644 index 70a870f4..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Italic.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf deleted file mode 100644 index 0f3d0f83..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/Lato-Regular.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf deleted file mode 100644 index df5d1df2..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Bold.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf deleted file mode 100644 index eb52a790..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/RobotoSlab-Regular.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot b/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot deleted file mode 100644 index e9f60ca9..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg b/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg deleted file mode 100644 index 855c845e..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,2671 +0,0 @@ - - - - -Created by FontForge 20120731 at Mon Oct 24 17:37:40 2016 - By ,,, -Copyright Dave Gandy 2016. All rights reserved. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf b/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 35acda2f..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff b/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff deleted file mode 100644 index 400014a4..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff2 b/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 4d13fc60..00000000 Binary files a/docs/build/_themes/sphinx_rtd_theme/static/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/docs/build/_themes/sphinx_rtd_theme/static/js/modernizr.min.js b/docs/build/_themes/sphinx_rtd_theme/static/js/modernizr.min.js deleted file mode 100644 index f65d4797..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/static/js/modernizr.min.js +++ /dev/null @@ -1,4 +0,0 @@ -/* Modernizr 2.6.2 (Custom Build) | MIT & BSD - * Build: http://modernizr.com/download/#-fontface-backgroundsize-borderimage-borderradius-boxshadow-flexbox-hsla-multiplebgs-opacity-rgba-textshadow-cssanimations-csscolumns-generatedcontent-cssgradients-cssreflections-csstransforms-csstransforms3d-csstransitions-applicationcache-canvas-canvastext-draganddrop-hashchange-history-audio-video-indexeddb-input-inputtypes-localstorage-postmessage-sessionstorage-websockets-websqldatabase-webworkers-geolocation-inlinesvg-smil-svg-svgclippaths-touch-webgl-shiv-mq-cssclasses-addtest-prefixed-teststyles-testprop-testallprops-hasevent-prefixes-domprefixes-load - */ -;window.Modernizr=function(a,b,c){function D(a){j.cssText=a}function E(a,b){return D(n.join(a+";")+(b||""))}function F(a,b){return typeof a===b}function G(a,b){return!!~(""+a).indexOf(b)}function H(a,b){for(var d in a){var e=a[d];if(!G(e,"-")&&j[e]!==c)return b=="pfx"?e:!0}return!1}function I(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:F(f,"function")?f.bind(d||b):f}return!1}function J(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+p.join(d+" ")+d).split(" ");return F(b,"string")||F(b,"undefined")?H(e,b):(e=(a+" "+q.join(d+" ")+d).split(" "),I(e,b,c))}function K(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=h,(m?l:n).innerHTML+=f,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=g.style.overflow,g.style.overflow="hidden",g.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),g.style.overflow=k),!!i},z=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return y("@media "+b+" { #"+h+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},A=function(){function d(d,e){e=e||b.createElement(a[d]||"div"),d="on"+d;var f=d in e;return f||(e.setAttribute||(e=b.createElement("div")),e.setAttribute&&e.removeAttribute&&(e.setAttribute(d,""),f=F(e[d],"function"),F(e[d],"undefined")||(e[d]=c),e.removeAttribute(d))),e=null,f}var a={select:"input",change:"input",submit:"form",reset:"form",error:"img",load:"img",abort:"img"};return d}(),B={}.hasOwnProperty,C;!F(B,"undefined")&&!F(B.call,"undefined")?C=function(a,b){return B.call(a,b)}:C=function(a,b){return b in a&&F(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=w.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(w.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(w.call(arguments)))};return e}),s.flexbox=function(){return J("flexWrap")},s.canvas=function(){var a=b.createElement("canvas");return!!a.getContext&&!!a.getContext("2d")},s.canvastext=function(){return!!e.canvas&&!!F(b.createElement("canvas").getContext("2d").fillText,"function")},s.webgl=function(){return!!a.WebGLRenderingContext},s.touch=function(){var c;return"ontouchstart"in a||a.DocumentTouch&&b instanceof DocumentTouch?c=!0:y(["@media (",n.join("touch-enabled),("),h,")","{#modernizr{top:9px;position:absolute}}"].join(""),function(a){c=a.offsetTop===9}),c},s.geolocation=function(){return"geolocation"in navigator},s.postmessage=function(){return!!a.postMessage},s.websqldatabase=function(){return!!a.openDatabase},s.indexedDB=function(){return!!J("indexedDB",a)},s.hashchange=function(){return A("hashchange",a)&&(b.documentMode===c||b.documentMode>7)},s.history=function(){return!!a.history&&!!history.pushState},s.draganddrop=function(){var a=b.createElement("div");return"draggable"in a||"ondragstart"in a&&"ondrop"in a},s.websockets=function(){return"WebSocket"in a||"MozWebSocket"in a},s.rgba=function(){return D("background-color:rgba(150,255,150,.5)"),G(j.backgroundColor,"rgba")},s.hsla=function(){return D("background-color:hsla(120,40%,100%,.5)"),G(j.backgroundColor,"rgba")||G(j.backgroundColor,"hsla")},s.multiplebgs=function(){return D("background:url(https://),url(https://),red url(https://)"),/(url\s*\(.*?){3}/.test(j.background)},s.backgroundsize=function(){return J("backgroundSize")},s.borderimage=function(){return J("borderImage")},s.borderradius=function(){return J("borderRadius")},s.boxshadow=function(){return J("boxShadow")},s.textshadow=function(){return b.createElement("div").style.textShadow===""},s.opacity=function(){return E("opacity:.55"),/^0.55$/.test(j.opacity)},s.cssanimations=function(){return J("animationName")},s.csscolumns=function(){return J("columnCount")},s.cssgradients=function(){var a="background-image:",b="gradient(linear,left top,right bottom,from(#9f9),to(white));",c="linear-gradient(left top,#9f9, white);";return D((a+"-webkit- ".split(" ").join(b+a)+n.join(c+a)).slice(0,-a.length)),G(j.backgroundImage,"gradient")},s.cssreflections=function(){return J("boxReflect")},s.csstransforms=function(){return!!J("transform")},s.csstransforms3d=function(){var a=!!J("perspective");return a&&"webkitPerspective"in g.style&&y("@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}",function(b,c){a=b.offsetLeft===9&&b.offsetHeight===3}),a},s.csstransitions=function(){return J("transition")},s.fontface=function(){var a;return y('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},s.generatedcontent=function(){var a;return y(["#",h,"{font:0/0 a}#",h,':after{content:"',l,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a},s.video=function(){var a=b.createElement("video"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('video/ogg; codecs="theora"').replace(/^no$/,""),c.h264=a.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/,""),c.webm=a.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,"")}catch(d){}return c},s.audio=function(){var a=b.createElement("audio"),c=!1;try{if(c=!!a.canPlayType)c=new Boolean(c),c.ogg=a.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),c.mp3=a.canPlayType("audio/mpeg;").replace(/^no$/,""),c.wav=a.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),c.m4a=(a.canPlayType("audio/x-m4a;")||a.canPlayType("audio/aac;")).replace(/^no$/,"")}catch(d){}return c},s.localstorage=function(){try{return localStorage.setItem(h,h),localStorage.removeItem(h),!0}catch(a){return!1}},s.sessionstorage=function(){try{return sessionStorage.setItem(h,h),sessionStorage.removeItem(h),!0}catch(a){return!1}},s.webworkers=function(){return!!a.Worker},s.applicationcache=function(){return!!a.applicationCache},s.svg=function(){return!!b.createElementNS&&!!b.createElementNS(r.svg,"svg").createSVGRect},s.inlinesvg=function(){var a=b.createElement("div");return a.innerHTML="",(a.firstChild&&a.firstChild.namespaceURI)==r.svg},s.smil=function(){return!!b.createElementNS&&/SVGAnimate/.test(m.call(b.createElementNS(r.svg,"animate")))},s.svgclippaths=function(){return!!b.createElementNS&&/SVGClipPath/.test(m.call(b.createElementNS(r.svg,"clipPath")))};for(var L in s)C(s,L)&&(x=L.toLowerCase(),e[x]=s[L](),v.push((e[x]?"":"no-")+x));return e.input||K(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)C(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof f!="undefined"&&f&&(g.className+=" "+(b?"":"no-")+a),e[a]=b}return e},D(""),i=k=null,function(a,b){function k(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function l(){var a=r.elements;return typeof a=="string"?a.split(" "):a}function m(a){var b=i[a[g]];return b||(b={},h++,a[g]=h,i[h]=b),b}function n(a,c,f){c||(c=b);if(j)return c.createElement(a);f||(f=m(c));var g;return f.cache[a]?g=f.cache[a].cloneNode():e.test(a)?g=(f.cache[a]=f.createElem(a)).cloneNode():g=f.createElem(a),g.canHaveChildren&&!d.test(a)?f.frag.appendChild(g):g}function o(a,c){a||(a=b);if(j)return a.createDocumentFragment();c=c||m(a);var d=c.frag.cloneNode(),e=0,f=l(),g=f.length;for(;e",f="hidden"in a,j=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){f=!0,j=!0}})();var r={elements:c.elements||"abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",shivCSS:c.shivCSS!==!1,supportsUnknownElements:j,shivMethods:c.shivMethods!==!1,type:"default",shivDocument:q,createElement:n,createDocumentFragment:o};a.html5=r,q(b)}(this,b),e._version=d,e._prefixes=n,e._domPrefixes=q,e._cssomPrefixes=p,e.mq=z,e.hasEvent=A,e.testProp=function(a){return H([a])},e.testAllProps=J,e.testStyles=y,e.prefixed=function(a,b,c){return b?J(a,b,c):J(a,"pfx")},g.className=g.className.replace(/(^|\s)no-js(\s|$)/,"$1$2")+(f?" js "+v.join(" "):""),e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f"); - - // Add extra class to responsive tables that contain - // footnotes or citations so that we can target them for styling - $("table.docutils.footnote") - .wrap("
"); - $("table.docutils.citation") - .wrap("
"); - - // Add expand links to all parents of nested ul - $('.wy-menu-vertical ul').not('.simple').siblings('a').each(function () { - var link = $(this); - expand = $(''); - expand.on('click', function (ev) { - self.toggleCurrent(link); - ev.stopPropagation(); - return false; - }); - link.prepend(expand); - }); - }; - - nav.reset = function () { - // Get anchor from URL and open up nested nav - var anchor = encodeURI(window.location.hash) || '#'; - - try { - var link = $('.wy-menu-vertical') - .find('[href="' + anchor + '"]'); - // If we didn't find a link, it may be because we clicked on - // something that is not in the sidebar (eg: when using - // sphinxcontrib.httpdomain it generates headerlinks but those - // aren't picked up and placed in the toctree). So let's find - // the closest header in the document and try with that one. - if (link.length === 0) { - var doc_link = $('.document a[href="' + anchor + '"]'); - var closest_section = doc_link.closest('div.section'); - // Try again with the closest section entry. - link = $('.wy-menu-vertical') - .find('[href="#' + closest_section.attr("id") + '"]'); - } - // If we found a matching link then reset current and re-apply - // otherwise retain the existing match - if (link.length > 0) { - $('.wy-menu-vertical .current').removeClass('current'); - link.addClass('current'); - link.closest('li.toctree-l1').addClass('current'); - link.closest('li.toctree-l1').parent().addClass('current'); - link.closest('li.toctree-l1').addClass('current'); - link.closest('li.toctree-l2').addClass('current'); - link.closest('li.toctree-l3').addClass('current'); - link.closest('li.toctree-l4').addClass('current'); - } - } - catch (err) { - console.log("Error expanding nav for anchor", err); - } - - }; - - nav.onScroll = function () { - this.winScroll = false; - var newWinPosition = this.win.scrollTop(), - winBottom = newWinPosition + this.winHeight, - navPosition = this.navBar.scrollTop(), - newNavPosition = navPosition + (newWinPosition - this.winPosition); - if (newWinPosition < 0 || winBottom > this.docHeight) { - return; - } - this.navBar.scrollTop(newNavPosition); - this.winPosition = newWinPosition; - }; - - nav.onResize = function () { - this.winResize = false; - this.winHeight = this.win.height(); - this.docHeight = $(document).height(); - }; - - nav.hashChange = function () { - this.linkScroll = true; - this.win.one('hashchange', function () { - this.linkScroll = false; - }); - }; - - nav.toggleCurrent = function (elem) { - var parent_li = elem.closest('li'); - parent_li.siblings('li.current').removeClass('current'); - parent_li.siblings().find('li.current').removeClass('current'); - parent_li.find('> ul li.current').removeClass('current'); - parent_li.toggleClass('current'); - } - - return nav; -}; - -module.exports.ThemeNav = ThemeNav(); - -if (typeof(window) != 'undefined') { - window.SphinxRtdTheme = { Navigation: module.exports.ThemeNav }; -} - - -// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel -// https://gist.github.com/paulirish/1579671 -// MIT license - -(function() { - var lastTime = 0; - var vendors = ['ms', 'moz', 'webkit', 'o']; - for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { - window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; - window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] - || window[vendors[x]+'CancelRequestAnimationFrame']; - } - - if (!window.requestAnimationFrame) - window.requestAnimationFrame = function(callback, element) { - var currTime = new Date().getTime(); - var timeToCall = Math.max(0, 16 - (currTime - lastTime)); - var id = window.setTimeout(function() { callback(currTime + timeToCall); }, - timeToCall); - lastTime = currTime + timeToCall; - return id; - }; - - if (!window.cancelAnimationFrame) - window.cancelAnimationFrame = function(id) { - clearTimeout(id); - }; -}()); - -},{"jquery":"jquery"}]},{},["sphinx-rtd-theme"]); diff --git a/docs/build/_themes/sphinx_rtd_theme/theme.conf b/docs/build/_themes/sphinx_rtd_theme/theme.conf deleted file mode 100644 index 16ad38fe..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/theme.conf +++ /dev/null @@ -1,18 +0,0 @@ -[theme] -inherit = basic -stylesheet = css/theme.css -pygments_style = default - -[options] -canonical_url = -analytics_id = -collapse_navigation = False -sticky_navigation = True -navigation_depth = 4 -includehidden = True -titles_only = -logo_only = -display_version = True -prev_next_buttons_location = bottom -style_external_links = False -vcs_pageview_mode = diff --git a/docs/build/_themes/sphinx_rtd_theme/versions.html b/docs/build/_themes/sphinx_rtd_theme/versions.html deleted file mode 100644 index 4d78287a..00000000 --- a/docs/build/_themes/sphinx_rtd_theme/versions.html +++ /dev/null @@ -1,37 +0,0 @@ -{% if READTHEDOCS %} -{# Add rst-badge after rst-versions for small badge style. #} -
- - Read the Docs - v: {{ current_version }} - - -
-
-
{{ _('Versions') }}
- {% for slug, url in versions %} -
{{ slug }}
- {% endfor %} -
-
-
{{ _('Downloads') }}
- {% for type, url in downloads %} -
{{ type }}
- {% endfor %} -
-
-
{{ _('On Read the Docs') }}
-
- {{ _('Project Home') }} -
-
- {{ _('Builds') }} -
-
-
- {% trans %}Free document hosting provided by Read the Docs.{% endtrans %} - -
-
-{% endif %} - diff --git a/docs/build/conf.py b/docs/build/conf.py deleted file mode 100644 index 1edad226..00000000 --- a/docs/build/conf.py +++ /dev/null @@ -1,178 +0,0 @@ -# -*- coding: utf-8 -*- -# -# gunpowder documentation build configuration file, created by -# sphinx-quickstart on Fri Jun 30 12:59:21 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os -import sys -sys.path.insert(0, os.path.abspath('../..')) - - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', - 'sphinx.ext.coverage', - 'sphinx.ext.mathjax', - 'sphinx.ext.viewcode', - 'sphinx.ext.githubpages', - 'jupyter_sphinx' -] - -def setup(app): - app.add_css_file('custom.css') - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'gunpowder' -author = u'Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape' -copyright = u'2020, ' + author - -here = os.path.abspath(os.path.dirname(__file__)) -version_info = {} -with open(os.path.join(here, '..', '..', 'gunpowder', 'version_info.py')) as fp: - exec(fp.read(), version_info) -gp_version = version_info['_version'] - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -version = u'{}.{}'.format(gp_version.major(), gp_version.minor()) -# The full version, including alpha/beta/rc tags. -release = str(gp_version) - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. -language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. -todo_include_todos = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -html_theme_path = ['_themes'] -html_theme = 'sphinx_rtd_theme' -html_theme_options = { - 'logo_only': True -} -html_logo = 'gunpowder.svg' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. -htmlhelp_basename = 'gunpowderdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - (master_doc, 'gunpowder.tex', u'gunpowder Documentation', - u'Jan Funke', 'manual'), -] - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'gunpowder', u'gunpowder Documentation', - [author], 1) -] - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - (master_doc, 'gunpowder', u'gunpowder Documentation', - author, 'gunpowder', 'One line description of project.', - 'Miscellaneous'), -] - - - diff --git a/docs/build/example_boundaries.rst b/docs/build/example_boundaries.rst deleted file mode 100755 index 2c9dae89..00000000 --- a/docs/build/example_boundaries.rst +++ /dev/null @@ -1,399 +0,0 @@ -.. _sec_tutorial: - -Example: Boundary Prediction for Instance Segmentation -====================================================== - -(written by Sherry Ding) - -.. automodule:: gunpowder - :noindex: - -This is a tutorial about how to use ``gunpowder`` to assemble pipelines to train and test a neural network. As an -example, here we do neuron segmentation on the `cremi dataset `_ using a *3D U-Net*. To segment -neurons, we predict inter-voxel affinities from volumes of raw data. A ``gunpowder`` processing pipeline consists -of nodes that can be chained together using **+**. The major nodes of our training pipeline in this example includes -reading in sources, data augmentation, processing the labels, classifier training, and batch saving. Now we'll describe -the `code `_ in parts. - -Before we start, packages *malis* and *tensorflow* need to be installed for this example. - -.. code-block:: bash - - sudo apt-get install libboost-all-dev gcc # necessary for package malis (example for Ubuntu) - pip install malis - conda install tensorflow-gpu - - -Create a network to train with ------------------------------- - -Before assembling a pipeline and training on the data, it is required to build the neural network first, as it will be -called in the pipeline to train with. In this example, we build a *3D U-Net* with *tensorflow* as our neural network, and -store it in a *meta* file with its configuration in a *json* file for calling in the pipeline. The following script creates -a network for training and a larger network for faster prediction/testing. - -.. code-block:: bash - - python mknet.py - - -Assemble the training pipeline ------------------------------- - -Now we can assemble the training pipeline using ``gunpowder``. - -.. code-block:: python - - from __future__ import print_function - import gunpowder as gp - import json - import math - import logging - - logging.basicConfig(level=logging.INFO) - -First of all, we have to create :class:`ArrayKeys` for all arrays that the pipeline will use, i.e., give names to -our :class:`Arrays` for later requests or access. We create :class:`ArrayKeys` for raw intensities, ground -truth labels with unique IDs, ground truth affinities, weight to use to balance the loss, predicted affinities, and gredient -of the loss with regard to the predicted affinities. - -.. code-block:: python - - # raw intensities - raw = gp.ArrayKey('RAW') - - # objects labeled with unique IDs - gt_labels = gp.ArrayKey('LABELS') - - # array of per-voxel affinities to direct neighbors - gt_affs= gp.ArrayKey('AFFINITIES') - - # weights to use to balance the loss - loss_weights = gp.ArrayKey('LOSS_WEIGHTS') - - # the predicted affinities - pred_affs = gp.ArrayKey('PRED_AFFS') - - # the gredient of the loss wrt to the predicted affinities - pred_affs_gradients = gp.ArrayKey('PRED_AFFS_GRADIENTS') - -Next, we load the *3D U-Net* that we built and saved for training, and use its configurations to set the input and output size. - -.. code-block:: python - - with open('train_net_config.json', 'r') as f: - net_config = json.load(f) - - # get the input and output size in world units (nm, in this case) - voxel_size = gp.Coordinate((40, 4, 4)) - input_size = gp.Coordinate(net_config['input_shape'])*voxel_size - output_size = gp.Coordinate(net_config['output_shape'])*voxel_size - -We use :class:`BatchRequest` to formulate the request for what a batch should contain. For training, a batch -should contain raw data, ground truth affinities, and loss weights. In this example, we also request a batch for snapshot. -:class:`Snapshot` saves a passing batch in an *hdf* file for inspection. - -.. code-block:: python - - # formulate the request for what a batch should (at least) contain - request = gp.BatchRequest() - request.add(raw, input_size) - request.add(gt_affs, output_size) - request.add(loss_weights, output_size) - - # when we make a snapshot for inspection (see below), we also want to - # request the predicted affinities and gradients of the loss wrt the - # affinities - snapshot_request = gp.BatchRequest() - snapshot_request[pred_affs] = request[gt_affs] - snapshot_request[pred_affs_gradients] = request[gt_affs] - -Now we are going to assemble the training pipeline. As mentioned before, a ``gunpowder`` pipeline consists of nodes that are -chained using **+**. In this example, the first node deals with the sources. - -.. code-block:: python - - pipeline = ( - - # a tuple of sources, one for each sample (A, B, and C) provided by the CREMI challenge - tuple( - - # read batches from the HDF5 file - gp.Hdf5Source( - 'sample_'+s+'_padded_20160501.hdf', - datasets = { - raw: 'volumes/raw', - gt_labels: 'volumes/labels/neuron_ids' - } - ) + - - # convert raw to float in [0, 1] - gp.Normalize(raw) + - - # chose a random location for each requested batch - gp.RandomLocation() - - for s in ['A', 'B', 'C'] - ) + - -Here, :class:`Hdf5Source` provides arrays from samples that are in HDF5 format. :class:`Normalize` -normalizes values of the array to be floats between 0 and 1. :class:`RandomLocation` chooses a random -loacation for each request batch. - -Next we choose a random source, and do data augmentation. TODO: random source. Data augmentation "increases" the amount -of training data by augmenting them via a number of random transformations. The augmentations we use here are elastic -augmentation, transpose and mirror augmentation, as well as scaling and shifting the intensity. - -.. code-block:: python - - # chose a random source (i.e., sample) from the above - gp.RandomProvider() + - - # elastically deform the batch - gp.ElasticAugment( - [4,40,40], - [0,2,2], - [0,math.pi/2.0], - prob_slip=0.05, - prob_shift=0.05, - max_misalign=25) + - - # apply transpose and mirror augmentations - gp.SimpleAugment(transpose_only=[1, 2]) + - - # scale and shift the intensity of the raw array - gp.IntensityAugment( - raw, - scale_min=0.9, - scale_max=1.1, - shift_min=-0.1, - shift_max=0.1, - z_section_wise=True) + - -We also need to process the ground truth labels and affinities, e.g., grow a boundary between labels, convert labels -into affinities, and balance samples. - -.. code-block:: python - - # grow a boundary between labels - gp.GrowBoundary( - gt_labels, - steps=3, - only_xy=True) + - - # convert labels into affinities between voxels - gp.AddAffinities( - [[-1, 0, 0], [0, -1, 0], [0, 0, -1]], - gt_labels, - gt_affs) + - - # create a weight array that balances positive and negative samples in - # the affinity array - gp.BalanceLabels( - gt_affs, - loss_weights) + - -In this example, as our batch requests are repeatly the same, we pre-cache batches. :class:`PreCache` -means that a set of workers is spawned to pre-cache the batches in parallel processes for serving subsequent -requests quickly. - -.. code-block:: python - - # pre-cache batches from the point upstream - gp.PreCache( - cache_size=10, - num_workers=5) + - -The next node performs one training iteration for each passing batch. - -.. code-block:: python - - # perform one training iteration for each passing batch (here we use - # the tensor names earlier stored in train_net.config) - gp.tensorflow.Train( - 'train_net', - net_config['optimizer'], - net_config['loss'], - inputs={ - net_config['raw']: raw, - net_config['gt_affs']: gt_affs, - net_config['loss_weights']: loss_weights - }, - outputs={ - net_config['pred_affs']: pred_affs - }, - gradients={ - net_config['pred_affs']: pred_affs_gradients - }, - save_every=1) + - -We save the passing batch using :class:`Snapshot` and show a summary of time consuming. - -.. code-block:: python - - # save the passing batch as an HDF5 file for inspection - gp.Snapshot( - { - raw: '/volumes/raw', - gt_labels: '/volumes/labels/neuron_ids', - gt_affs: '/volumes/labels/affs', - pred_affs: '/volumes/pred_affs', - pred_affs_gradients: '/volumes/pred_affs_gradients' - }, - output_dir='snapshots', - output_filename='batch_{iteration}.hdf', - every=100, - additional_request=snapshot_request, - compression_type='gzip') + - - # show a summary of time spend in each node every 10 iterations - gp.PrintProfilingStats(every=10) - ) - -The final thing we need to do is requesting batches for the pipeline. - -.. code-block:: python - - print("Training for", iterations, "iterations") - - with gp.build(pipeline): - for i in range(iterations): - pipeline.request_batch(request) - - print("Finished") - -Let's put all above codes into a function called *train*, with an input parameter *iterations*. One iteration means -training on one batch once. - -.. code-block:: python - - def train(iterations): - ... - -In this example, we repeatly request a batch and train on it for 200000 times. - -.. code-block:: python - - if __name__ == "__main__": - train(200000) - - -Assemble the testing pipeline ------------------------------ - -After trained the network, we also use ``gunpowder`` to assemble the testing pipeline. - -.. code-block:: python - - from __future__ import print_function - import gunpowder as gp - import json - -The first is still creating :class:`ArrayKeys` for all arrays. We create :class:`ArrayKeys` -for raw intensities of testing data and predicted affinities. - -.. code-block:: python - - # raw intensities - raw = gp.ArrayKey('RAW') - - # the predicted affinities - pred_affs = gp.ArrayKey('PRED_AFFS') - -Load the *3D U-Net* that we built and saved for testing, and use its configurations to set the input and output size. - -.. code-block:: python - - with open('test_net_config.json', 'r') as f: - net_config = json.load(f) - - # get the input and output size in world units (nm, in this case) - voxel_size = gp.Coordinate((40, 4, 4)) - input_size = gp.Coordinate(net_config['input_shape'])*voxel_size - output_size = gp.Coordinate(net_config['output_shape'])*voxel_size - context = input_size - output_size - -We formulate the request for what a batch should contain. For testing, a batch should contain raw data and predicted -affinities. - -.. code-block:: python - - # formulate the request for what a batch should contain - request = gp.BatchRequest() - request.add(raw, input_size) - request.add(pred_affs, output_size) - -Next is to assemble the testing pipeline. The pipeline for testing/prediction is much simpler. It should at least -include a source node and a prediction node. - -.. code-block:: python - - source = gp.Hdf5Source( - 'sample_A_padded_20160501.hdf', - datasets = { - raw: 'volumes/raw' - }) - - # get the ROI provided for raw (we need it later to calculate the ROI in - # which we can make predictions) - with gp.build(source): - raw_roi = source.spec[raw].roi - - pipeline = ( - - # read from HDF5 file - source + - - # convert raw to float in [0, 1] - gp.Normalize(raw) + - - # perform one training iteration for each passing batch (here we use - # the tensor names earlier stored in train_net.config) - gp.tensorflow.Predict( - graph='test_net.meta', - checkpoint='train_net_checkpoint_%d'%iteration, - inputs={ - net_config['raw']: raw - }, - outputs={ - net_config['pred_affs']: pred_affs - }, - array_specs={ - pred_affs: gp.ArraySpec(roi=raw_roi.grow(-context, -context)) - }) + - -We also contain a :class:`Hdf5Write` node to store all passing batches, and a node showing a summary -of time consuming. - -.. code-block:: python - - # store all passing batches in the same HDF5 file - gp.Hdf5Write( - { - raw: '/volumes/raw', - pred_affs: '/volumes/pred_affs', - }, - output_filename='predictions_sample_A.hdf', - compression_type='gzip' - ) + - - # show a summary of time spend in each node every 10 iterations - gp.PrintProfilingStats(every=10) + - -Last :class:`Scan` node is used to iteratively request batches over the whole dataset in a scanning fashion - -.. code-block:: python - - # iterate over the whole dataset in a scanning fashion, emitting - # requests that match the size of the network - gp.Scan(reference=request) - ) - -Finally, we request an empty batch from :class:`Scan` to trigger scanning of the dataset. - -.. code-block:: python - - with gp.build(pipeline): - # request an empty batch from Scan to trigger scanning of the dataset - # without keeping the complete dataset in memory - pipeline.request_batch(gp.BatchRequest()) diff --git a/docs/build/gunpowder.svg b/docs/build/gunpowder.svg deleted file mode 100644 index 2a3d5d22..00000000 --- a/docs/build/gunpowder.svg +++ /dev/null @@ -1,284 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/docs/example_boundaries.html b/docs/example_boundaries.html deleted file mode 100644 index d2a4b98c..00000000 --- a/docs/example_boundaries.html +++ /dev/null @@ -1,707 +0,0 @@ - - - - - - - - - - - Example: Boundary Prediction for Instance Segmentation — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Example: Boundary Prediction for Instance Segmentation
  • - - -
  • - - - View page source - - -
  • - -
- - -
-
-
-
- -
-

Example: Boundary Prediction for Instance Segmentation

-

(written by Sherry Ding)

-

This is a tutorial about how to use gunpowder to assemble pipelines to train and test a neural network. As an -example, here we do neuron segmentation on the cremi dataset using a 3D U-Net. To segment -neurons, we predict inter-voxel affinities from volumes of raw data. A gunpowder processing pipeline consists -of nodes that can be chained together using +. The major nodes of our training pipeline in this example includes -reading in sources, data augmentation, processing the labels, classifier training, and batch saving. Now we’ll describe -the code in parts.

-

Before we start, packages malis and tensorflow need to be installed for this example.

-
sudo apt-get install libboost-all-dev gcc  # necessary for package malis (example for Ubuntu)
-pip install malis
-conda install tensorflow-gpu
-
-
-
-

Create a network to train with

-

Before assembling a pipeline and training on the data, it is required to build the neural network first, as it will be -called in the pipeline to train with. In this example, we build a 3D U-Net with tensorflow as our neural network, and -store it in a meta file with its configuration in a json file for calling in the pipeline. The following script creates -a network for training and a larger network for faster prediction/testing.

-
python mknet.py
-
-
-
-
-

Assemble the training pipeline

-

Now we can assemble the training pipeline using gunpowder.

-
from __future__ import print_function
-import gunpowder as gp
-import json
-import math
-import logging
-
-logging.basicConfig(level=logging.INFO)
-
-
-

First of all, we have to create ArrayKeys for all arrays that the pipeline will use, i.e., give names to -our Arrays for later requests or access. We create ArrayKeys for raw intensities, ground -truth labels with unique IDs, ground truth affinities, weight to use to balance the loss, predicted affinities, and gredient -of the loss with regard to the predicted affinities.

-
# raw intensities
-raw = gp.ArrayKey('RAW')
-
-# objects labeled with unique IDs
-gt_labels = gp.ArrayKey('LABELS')
-
-# array of per-voxel affinities to direct neighbors
-gt_affs= gp.ArrayKey('AFFINITIES')
-
-# weights to use to balance the loss
-loss_weights = gp.ArrayKey('LOSS_WEIGHTS')
-
-# the predicted affinities
-pred_affs = gp.ArrayKey('PRED_AFFS')
-
-# the gredient of the loss wrt to the predicted affinities
-pred_affs_gradients = gp.ArrayKey('PRED_AFFS_GRADIENTS')
-
-
-

Next, we load the 3D U-Net that we built and saved for training, and use its configurations to set the input and output size.

-
with open('train_net_config.json', 'r') as f:
-    net_config = json.load(f)
-
-# get the input and output size in world units (nm, in this case)
-voxel_size = gp.Coordinate((40, 4, 4))
-input_size = gp.Coordinate(net_config['input_shape'])*voxel_size
-output_size = gp.Coordinate(net_config['output_shape'])*voxel_size
-
-
-

We use BatchRequest to formulate the request for what a batch should contain. For training, a batch -should contain raw data, ground truth affinities, and loss weights. In this example, we also request a batch for snapshot. -Snapshot saves a passing batch in an hdf file for inspection.

-
# formulate the request for what a batch should (at least) contain
-request = gp.BatchRequest()
-request.add(raw, input_size)
-request.add(gt_affs, output_size)
-request.add(loss_weights, output_size)
-
-# when we make a snapshot for inspection (see below), we also want to
-# request the predicted affinities and gradients of the loss wrt the
-# affinities
-snapshot_request = gp.BatchRequest()
-snapshot_request[pred_affs] = request[gt_affs]
-snapshot_request[pred_affs_gradients] = request[gt_affs]
-
-
-

Now we are going to assemble the training pipeline. As mentioned before, a gunpowder pipeline consists of nodes that are -chained using +. In this example, the first node deals with the sources.

-
pipeline = (
-
-    # a tuple of sources, one for each sample (A, B, and C) provided by the CREMI challenge
-    tuple(
-
-        # read batches from the HDF5 file
-        gp.Hdf5Source(
-            'sample_'+s+'_padded_20160501.hdf',
-            datasets = {
-                raw: 'volumes/raw',
-                gt_labels: 'volumes/labels/neuron_ids'
-            }
-        ) +
-
-        # convert raw to float in [0, 1]
-        gp.Normalize(raw) +
-
-        # chose a random location for each requested batch
-        gp.RandomLocation()
-
-        for s in ['A', 'B', 'C']
-    ) +
-
-
-

Here, Hdf5Source provides arrays from samples that are in HDF5 format. Normalize -normalizes values of the array to be floats between 0 and 1. RandomLocation chooses a random -loacation for each request batch.

-

Next we choose a random source, and do data augmentation. TODO: random source. Data augmentation “increases” the amount -of training data by augmenting them via a number of random transformations. The augmentations we use here are elastic -augmentation, transpose and mirror augmentation, as well as scaling and shifting the intensity.

-
# chose a random source (i.e., sample) from the above
-gp.RandomProvider() +
-
-# elastically deform the batch
-gp.ElasticAugment(
-    [4,40,40],
-    [0,2,2],
-    [0,math.pi/2.0],
-    prob_slip=0.05,
-    prob_shift=0.05,
-    max_misalign=25) +
-
-# apply transpose and mirror augmentations
-gp.SimpleAugment(transpose_only=[1, 2]) +
-
-# scale and shift the intensity of the raw array
-gp.IntensityAugment(
-    raw,
-    scale_min=0.9,
-    scale_max=1.1,
-    shift_min=-0.1,
-    shift_max=0.1,
-    z_section_wise=True) +
-
-
-

We also need to process the ground truth labels and affinities, e.g., grow a boundary between labels, convert labels -into affinities, and balance samples.

-
# grow a boundary between labels
-gp.GrowBoundary(
-    gt_labels,
-    steps=3,
-    only_xy=True) +
-
-# convert labels into affinities between voxels
-gp.AddAffinities(
-    [[-1, 0, 0], [0, -1, 0], [0, 0, -1]],
-    gt_labels,
-    gt_affs) +
-
-# create a weight array that balances positive and negative samples in
-# the affinity array
-gp.BalanceLabels(
-    gt_affs,
-    loss_weights) +
-
-
-

In this example, as our batch requests are repeatly the same, we pre-cache batches. PreCache -means that a set of workers is spawned to pre-cache the batches in parallel processes for serving subsequent -requests quickly.

-
# pre-cache batches from the point upstream
-gp.PreCache(
-    cache_size=10,
-    num_workers=5) +
-
-
-

The next node performs one training iteration for each passing batch.

-
# perform one training iteration for each passing batch (here we use
-# the tensor names earlier stored in train_net.config)
-gp.tensorflow.Train(
-    'train_net',
-    net_config['optimizer'],
-    net_config['loss'],
-    inputs={
-        net_config['raw']: raw,
-        net_config['gt_affs']: gt_affs,
-        net_config['loss_weights']: loss_weights
-    },
-    outputs={
-        net_config['pred_affs']: pred_affs
-    },
-    gradients={
-        net_config['pred_affs']: pred_affs_gradients
-    },
-    save_every=1) +
-
-
-

We save the passing batch using Snapshot and show a summary of time consuming.

-
    # save the passing batch as an HDF5 file for inspection
-    gp.Snapshot(
-        {
-            raw: '/volumes/raw',
-            gt_labels: '/volumes/labels/neuron_ids',
-            gt_affs: '/volumes/labels/affs',
-            pred_affs: '/volumes/pred_affs',
-            pred_affs_gradients: '/volumes/pred_affs_gradients'
-        },
-        output_dir='snapshots',
-        output_filename='batch_{iteration}.hdf',
-        every=100,
-        additional_request=snapshot_request,
-        compression_type='gzip') +
-
-    # show a summary of time spend in each node every 10 iterations
-    gp.PrintProfilingStats(every=10)
-)
-
-
-

The final thing we need to do is requesting batches for the pipeline.

-
print("Training for", iterations, "iterations")
-
-with gp.build(pipeline):
-    for i in range(iterations):
-        pipeline.request_batch(request)
-
-print("Finished")
-
-
-

Let’s put all above codes into a function called train, with an input parameter iterations. One iteration means -training on one batch once.

-
def train(iterations):
-    ...
-
-
-

In this example, we repeatly request a batch and train on it for 200000 times.

-
if __name__ == "__main__":
-    train(200000)
-
-
-
-
-

Assemble the testing pipeline

-

After trained the network, we also use gunpowder to assemble the testing pipeline.

-
from __future__ import print_function
-import gunpowder as gp
-import json
-
-
-

The first is still creating ArrayKeys for all arrays. We create ArrayKeys -for raw intensities of testing data and predicted affinities.

-
# raw intensities
-raw = gp.ArrayKey('RAW')
-
-# the predicted affinities
-pred_affs = gp.ArrayKey('PRED_AFFS')
-
-
-

Load the 3D U-Net that we built and saved for testing, and use its configurations to set the input and output size.

-
with open('test_net_config.json', 'r') as f:
-    net_config = json.load(f)
-
-# get the input and output size in world units (nm, in this case)
-voxel_size = gp.Coordinate((40, 4, 4))
-input_size = gp.Coordinate(net_config['input_shape'])*voxel_size
-output_size = gp.Coordinate(net_config['output_shape'])*voxel_size
-context = input_size - output_size
-
-
-

We formulate the request for what a batch should contain. For testing, a batch should contain raw data and predicted -affinities.

-
# formulate the request for what a batch should contain
-request = gp.BatchRequest()
-request.add(raw, input_size)
-request.add(pred_affs, output_size)
-
-
-

Next is to assemble the testing pipeline. The pipeline for testing/prediction is much simpler. It should at least -include a source node and a prediction node.

-
source = gp.Hdf5Source(
-    'sample_A_padded_20160501.hdf',
-    datasets = {
-        raw: 'volumes/raw'
-    })
-
-# get the ROI provided for raw (we need it later to calculate the ROI in
-# which we can make predictions)
-with gp.build(source):
-    raw_roi = source.spec[raw].roi
-
-pipeline = (
-
-    # read from HDF5 file
-    source +
-
-    # convert raw to float in [0, 1]
-    gp.Normalize(raw) +
-
-    # perform one training iteration for each passing batch (here we use
-    # the tensor names earlier stored in train_net.config)
-    gp.tensorflow.Predict(
-        graph='test_net.meta',
-        checkpoint='train_net_checkpoint_%d'%iteration,
-        inputs={
-            net_config['raw']: raw
-        },
-        outputs={
-            net_config['pred_affs']: pred_affs
-        },
-        array_specs={
-            pred_affs: gp.ArraySpec(roi=raw_roi.grow(-context, -context))
-        }) +
-
-
-

We also contain a Hdf5Write node to store all passing batches, and a node showing a summary -of time consuming.

-
# store all passing batches in the same HDF5 file
-gp.Hdf5Write(
-    {
-        raw: '/volumes/raw',
-        pred_affs: '/volumes/pred_affs',
-    },
-    output_filename='predictions_sample_A.hdf',
-    compression_type='gzip'
-) +
-
-# show a summary of time spend in each node every 10 iterations
-gp.PrintProfilingStats(every=10) +
-
-
-

Last Scan node is used to iteratively request batches over the whole dataset in a scanning fashion

-
    # iterate over the whole dataset in a scanning fashion, emitting
-    # requests that match the size of the network
-    gp.Scan(reference=request)
-)
-
-
-

Finally, we request an empty batch from Scan to trigger scanning of the dataset.

-
with gp.build(pipeline):
-    # request an empty batch from Scan to trigger scanning of the dataset
-    # without keeping the complete dataset in memory
-    pipeline.request_batch(gp.BatchRequest())
-
-
-
-
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/genindex.html b/docs/genindex.html deleted file mode 100644 index 02984bbc..00000000 --- a/docs/genindex.html +++ /dev/null @@ -1,833 +0,0 @@ - - - - - - - - - - - Index — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Index
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- - -

Index

- -
- A - | B - | C - | D - | E - | F - | G - | H - | I - | K - | M - | N - | P - | R - | S - | T - | U - | V - | Z - -
-

A

- - - -
- -

B

- - - -
- -

C

- - - -
- -

D

- - - -
- -

E

- - - -
- -

F

- - -
- -

G

- - - -
- -

H

- - - -
- -

I

- - - -
- -

K

- - -
- -

M

- - - -
- -

N

- - - -
- -

P

- - - -
- -

R

- - - -
- -

S

- - - -
- -

T

- - - -
- -

U

- - - -
- -

V

- - -
- -

Z

- - - -
- - - -
- -
-
- - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/index.html b/docs/index.html deleted file mode 100644 index 11bd1fdc..00000000 --- a/docs/index.html +++ /dev/null @@ -1,442 +0,0 @@ - - - - - - - - - - - Gunpowder Documentation — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- - -
-

Indices and tables

- -
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/install.html b/docs/install.html deleted file mode 100644 index 0be2db1b..00000000 --- a/docs/install.html +++ /dev/null @@ -1,374 +0,0 @@ - - - - - - - - - - - Installation — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Installation

-
pip install gunpowder
-
-
-

That’s all.

-
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 00000000..747ffb7b --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/objects.inv b/docs/objects.inv deleted file mode 100644 index aa245439..00000000 Binary files a/docs/objects.inv and /dev/null differ diff --git a/docs/overview.html b/docs/overview.html deleted file mode 100644 index bc25264d..00000000 --- a/docs/overview.html +++ /dev/null @@ -1,398 +0,0 @@ - - - - - - - - - - - Overview — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Overview

-

Many data loading, training, and prediction tasks can be thought of as chaining -a sequence of operations. For example, to train a model to segment cells in a -large 2D+t movie, one might want to:

-
-
    -
  1. Read the data (the movie) and meta data (spatial resolution, data -type, ground-truth annotations).

  2. -
  3. Pick a sample to train on from a random frame, at a random location.

  4. -
  5. Augment the sample (rotate, mirror, flip, elastically deform, change -intensity, etc.).

  6. -
  7. Stack several samples together into a batch.

  8. -
  9. Perform a training iteration on the batch

  10. -
-
-

In gunpowder, a sequence of operations like the example above is assembled -in the form of a pipeline of linked nodes. Once the pipeline is built, -requests can be made at the end of the pipeline (e.g, “give me a batch with -ten images of size (100, 100)”). This request will then be passed upstream -from node to node. Nodes will update the request to ask for additional data -they need (e.g., a node performing a rotation of 45° will require an image of -size (142, 142) to satisfy the requested size (100, 100)). Once the -request hits a source node, a batch with the requested data will be -created. This batch is then sent downstream the pipeline, once again visiting -each node along the path to perform the actual operation (e.g., rotate by 45° -and crop to (100, 100)).

-

The Simple Pipeline demonstrates how such -a pipeline in assembled in gunpowder (and also how to use a similar -pipeline for prediction).

-
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/py-modindex.html b/docs/py-modindex.html deleted file mode 100644 index a96157d5..00000000 --- a/docs/py-modindex.html +++ /dev/null @@ -1,383 +0,0 @@ - - - - - - - - - - - Python Module Index — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Python Module Index
  • - - -
  • - -
  • - -
- - -
-
-
-
- - -

Python Module Index

- -
- g -
- - - - - - - - - - - - - -
 
- g
- gunpowder -
    - gunpowder.tensorflow -
    - gunpowder.torch -
- - -
- -
-
- - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/search.html b/docs/search.html deleted file mode 100644 index 69e504af..00000000 --- a/docs/search.html +++ /dev/null @@ -1,374 +0,0 @@ - - - - - - - - - - - Search — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- -
    - -
  • Docs »
  • - -
  • Search
  • - - -
  • - - - -
  • - -
- - -
-
-
-
- - - - -
- -
- -
- -
-
- - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/searchindex.js b/docs/searchindex.js deleted file mode 100644 index 5e8a4d70..00000000 --- a/docs/searchindex.js +++ /dev/null @@ -1 +0,0 @@ -Search.setIndex({docnames:["api","example_boundaries","index","install","overview","tutorial_batch_provider","tutorial_simple_pipeline"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.viewcode":1,sphinx:56},filenames:["api.rst","example_boundaries.rst","index.rst","install.rst","overview.rst","tutorial_batch_provider.rst","tutorial_simple_pipeline.rst"],objects:{"":{gunpowder:[6,0,0,"-"]},"gunpowder.Array":{copy:[0,2,1,""],crop:[0,2,1,""],merge:[0,2,1,""]},"gunpowder.ArraySpec":{copy:[0,2,1,""],dtype:[0,3,1,""],interpolatable:[0,3,1,""],nonspatial:[0,3,1,""],roi:[0,3,1,""],voxel_size:[0,3,1,""]},"gunpowder.Batch":{arrays:[0,3,1,""],crop:[0,2,1,""],get_total_roi:[0,2,1,""],graphs:[0,3,1,""],items:[0,2,1,""],merge:[0,2,1,""]},"gunpowder.BatchFilter":{enable_autoskip:[0,2,1,""],prepare:[0,2,1,""],process:[0,2,1,""],provides:[0,2,1,""],request_batch:[0,2,1,""],setup:[0,2,1,""],spec:[0,2,1,""],teardown:[0,2,1,""],updates:[0,2,1,""]},"gunpowder.BatchProvider":{provide:[0,2,1,""],provides:[0,2,1,""],request_batch:[0,2,1,""],setup:[0,2,1,""],spec:[0,2,1,""],teardown:[0,2,1,""]},"gunpowder.BatchRequest":{add:[0,2,1,""]},"gunpowder.Graph":{add_edge:[0,2,1,""],add_node:[0,2,1,""],crop:[0,2,1,""],from_nx_graph:[0,2,1,""],merge:[0,2,1,""],node:[0,2,1,""],relabel_connected_components:[0,2,1,""],remove_edge:[0,2,1,""],remove_node:[0,2,1,""],to_nx_graph:[0,2,1,""],trim:[0,2,1,""]},"gunpowder.GraphSpec":{copy:[0,2,1,""],directed:[0,3,1,""],dtype:[0,3,1,""],roi:[0,3,1,""]},"gunpowder.ProviderSpec":{array_specs:[0,3,1,""],graph_specs:[0,3,1,""],items:[0,2,1,""]},"gunpowder.Roi":{contains:[0,2,1,""],copy:[0,2,1,""],dims:[0,2,1,""],empty:[0,2,1,""],get_begin:[0,2,1,""],get_bounding_box:[0,2,1,""],get_center:[0,2,1,""],get_end:[0,2,1,""],get_shape:[0,2,1,""],grow:[0,2,1,""],intersect:[0,2,1,""],intersects:[0,2,1,""],set_shape:[0,2,1,""],shift:[0,2,1,""],size:[0,2,1,""],snap_to_grid:[0,2,1,""],to_slices:[0,2,1,""],unbounded:[0,2,1,""],union:[0,2,1,""]},"gunpowder.tensorflow":{Predict:[0,1,1,""],Train:[0,1,1,""]},"gunpowder.torch":{Predict:[0,1,1,""],Train:[0,1,1,""]},gunpowder:{AddAffinities:[0,1,1,""],Array:[0,1,1,""],ArrayKey:[0,1,1,""],ArraySpec:[0,1,1,""],BalanceLabels:[0,1,1,""],Batch:[0,1,1,""],BatchFilter:[0,1,1,""],BatchProvider:[0,1,1,""],BatchRequest:[0,1,1,""],Coordinate:[0,1,1,""],Crop:[0,1,1,""],CsvPointsSource:[0,1,1,""],DaisyRequestBlocks:[0,1,1,""],DefectAugment:[0,1,1,""],DownSample:[0,1,1,""],DvidSource:[0,1,1,""],Edge:[0,1,1,""],ElasticAugment:[0,1,1,""],ExcludeLabels:[0,1,1,""],Graph:[0,1,1,""],GraphKey:[0,1,1,""],GraphSpec:[0,1,1,""],GrowBoundary:[0,1,1,""],Hdf5Source:[0,1,1,""],Hdf5Write:[0,1,1,""],IntensityAugment:[0,1,1,""],IntensityScaleShift:[0,1,1,""],KlbSource:[0,1,1,""],MergeProvider:[0,1,1,""],Node:[0,1,1,""],NoiseAugment:[0,1,1,""],Normalize:[0,1,1,""],Pad:[0,1,1,""],PreCache:[0,1,1,""],PrintProfilingStats:[0,1,1,""],ProviderSpec:[0,1,1,""],RandomLocation:[0,1,1,""],RandomProvider:[0,1,1,""],RasterizationSettings:[0,1,1,""],RasterizeGraph:[0,1,1,""],Reject:[0,1,1,""],RenumberConnectedComponents:[0,1,1,""],Roi:[0,1,1,""],Scan:[0,1,1,""],SimpleAugment:[0,1,1,""],Snapshot:[0,1,1,""],SpecifiedLocation:[0,1,1,""],Squeeze:[0,1,1,""],Stack:[0,1,1,""],Unsqueeze:[0,1,1,""],UpSample:[0,1,1,""],ZarrSource:[0,1,1,""],ZarrWrite:[0,1,1,""],tensorflow:[0,0,0,"-"],torch:[0,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","method","Python method"],"3":["py","attribute","Python attribute"]},objtypes:{"0":"py:module","1":"py:class","2":"py:method","3":"py:attribute"},terms:{"100":[1,4,5],"1000":6,"101":0,"1073741824":0,"108":5,"114":6,"128":[5,6],"142":4,"150":6,"154":[],"168":5,"177":5,"19623":6,"1gb":0,"2000":0,"200000":1,"214":6,"228":5,"236":5,"23619":5,"248":5,"255":0,"289":5,"2pi":0,"305":5,"353":5,"512":6,"byte":0,"case":[0,1,5,6],"class":[2,5],"default":[0,5,6],"final":[1,5,6],"float":[0,1,5,6],"function":[0,1,5,6],"import":[1,5,6],"int":0,"long":6,"new":[0,2,6],"return":[0,5,6],"static":5,"true":[0,1,5,6],But:6,Doing:6,For:[0,1,4,5,6],Has:0,IDs:[0,1],One:[0,1,5],That:3,The:[0,1,2,4,6],There:0,These:0,Use:0,Used:0,Uses:0,Will:0,With:6,__future__:1,__init__:5,__main__:1,__name__:1,_padded_20160501:1,about:[0,1,5,6],abov:[1,4,6],absolut:0,accept:[0,6],access:[0,1,5,6],accord:0,accordingli:5,accumul:0,across:0,act:5,activ:6,actual:[0,4,5],adam:6,adamoptim:0,add:[0,1,5,6],add_custom_optim:0,add_edg:0,add_nod:0,addaffin:1,added:[0,6],adding:0,addit:[0,2,4],additional_request:[0,1],advis:6,aff:1,affin:[0,1],affinities_mask:0,affinitii:0,affinity_neighborhood:0,after:[0,1,5],again:[4,5],agnost:6,ahead:6,alia:0,align:[0,6],all:[0,1,3,5,6],alloc:0,allow:[0,2,5,6],along:[0,4,5],alongsid:6,alpha:0,alreadi:[0,5],also:[0,1,4,5,6],although:5,alwai:[0,5,6],amount:[0,1,5],amount_neg:0,amount_po:0,angl:0,ani:[0,5,6],anisotrop:6,annot:4,announc:[0,5],anoth:[0,5,6],answer:[5,6],anywai:0,api:[2,6],appar:5,append:0,appli:[0,1,5,6],applic:6,apt:1,arbitrari:5,arbitrarili:[2,6],area:[0,5,6],arg:0,argument:[0,5,6],arithmet:0,around:0,arrai:[1,2],array_kei:0,array_lik:0,array_spec:[0,1],arraykei:[1,5,6],arrayspec:[1,5,6],artifact:[0,5],artifact_sourc:0,artifacts_mask:0,ask:[4,5,6],assembl:[0,2,4,6],assign:0,associ:[0,5,6],assum:[0,5,6],astronaut:[5,6],astyp:[5,6],attach:5,attr:[0,5,6],attribut:[0,5,6],augment:[1,2,4,5],automat:0,autskip:0,avail:0,avoid:[0,5],awai:0,axes:[0,5,6],axi:[0,5],axis:0,back:[0,5],background:0,background_valu:0,bad:[0,5],balanc:[0,1],balancelabel:1,ball:0,base:[2,6],basenam:0,basic:2,basicconfig:1,batch:[1,2,4,5],batch_:1,batch_left:5,batch_right:5,batchfilt:5,batchrequest:[1,5,6],bceloss:6,becaus:[0,6],becom:6,been:[0,5,6],befor:[0,1,5,6],begin:[5,6],behav:6,being:[0,5,6],below:[1,5,6],benefit:6,best:6,better:[0,5],between:[0,1,5,6],beyond:5,bg_valu:0,binari:[0,6],biproduct:0,bit:5,blend:0,block:0,block_done_callback:0,bool:0,border:[0,5],both:[0,5,6],bound:[0,5],boundari:[0,2,5],box:0,build:[0,1,5,6],built:[1,4,6],cach:[0,1,2,6],cache_s:[0,1],calcul:[0,1],call:[0,1,5,6],callback:0,calle:0,came:5,can:[0,1,4,5,6],cannot:0,caus:0,cell:4,center:0,center_graph:0,central:5,chain:[1,4,6],challeng:1,chang:[0,2,4],channel:[0,5,6],channels_first:0,channels_last:0,character:0,check:0,check_funct:0,checkpoint:[0,1],checkpoint_basenam:0,choic:0,choos:[0,1],choose_randomli:0,chose:[0,1],chosen:0,chunk:[0,6],claim:5,classif:0,classifi:1,classmethod:0,clip:0,clipmax:0,clipmin:0,close:5,closest:0,cluster:0,code:[1,5],col:[5,6],colab:6,collect:0,color:0,color_attr:0,com:6,combin:[2,5],combined_sourc:6,come:[0,6],comma:0,common:0,commun:0,compar:[5,6],compat:0,complement:[2,6],complet:[0,1,5,6],complex:5,compon:0,compress:0,compression_typ:[0,1],comput:[0,5],concaten:5,concept:[5,6],conda:1,config:1,configur:1,confirm:5,conflict:[0,5],connect:0,consequ:[5,6],consid:[0,5],consist:[0,1,6],constant:0,constructor:5,consum:1,contain:[1,2,5,6],conten:0,content:[0,5,6],context:[1,5],context_roi:5,contrast:[0,5],contrast_scal:0,contribut:0,control:0,control_point_spac:[0,6],conveni:[0,5],convert:[0,1],convolut:6,convpass:6,coordin:[1,5],copi:[0,5,6],copy_from_self:0,core:0,corner:6,correct:[5,6],correspond:0,correspondingli:6,cover:[0,5,6],cpu:0,creat:[0,2,4],create_dataset:6,cremi:1,criteria:0,crop:[4,5,6],cross:6,csv:0,cuda:0,cumbersom:6,current:[0,5],custom:0,custom_loss:0,cut:0,cycl:0,dag:0,daisi:0,dangl:0,data:[1,2,4],dataset:[0,1,5,6],dataset_dtyp:0,dataset_nam:[0,6],datatyp:[0,6],deal:[1,6],decid:5,decis:5,declar:[5,6],def:[0,1,5,6],defin:[0,5],deform:[0,1,4,6],deformation_strength:0,deliber:5,deliv:[0,5,6],demand:0,demonstr:4,dens:0,dep:5,depend:[0,5],deriv:0,describ:[0,1,5],design:[5,6],desir:0,destruct:0,determin:0,determinist:0,dev:1,deviat:0,devic:0,dict:0,dictionari:[0,5,6],did:[5,6],differ:[0,5,6],difficulti:6,dim:[0,5],dimens:[0,5,6],dimension:[0,2],ding:1,direct:[0,1,5],directli:[5,6],directori:0,disabl:0,discard:[0,6],discret:[0,5],disjoint:0,disk:0,displai:5,distanc:0,distribut:0,divid:5,divis:0,document:0,doe:[0,5,6],doing:6,done:[5,6],down:5,downsampl:6,downsample_factor:6,downstream:[0,4,5],draw:0,drawn:[0,6],dtype:[0,5,6],due:0,dummi:[5,6],durat:0,dure:0,dvid:0,each:[0,1,4,5,6],earlier:[0,1,5,6],easi:6,effect:[5,6],either:[0,5],elast:[0,1,4,6],elastic_aug:6,elasticaug:[1,5,6],elasticli:0,element:0,elimin:5,els:[5,6],emit:1,empti:[0,1,6],enabl:0,enable_autoskip:0,end:[0,4,6],enlarg:5,enough:6,ensur:[0,5,6],ensure_cent:0,ensure_nonempti:0,enter:0,entir:0,entri:0,entropi:6,enumer:[5,6],equal:[0,5],equival:6,erod:0,etc:[0,4],eval:6,evalu:[0,6],even:6,everi:[0,1,5,6],everywher:0,evid:6,exact:6,exactli:[0,5,6],exampl:[0,2,4,5],exce:0,except:[0,6],exclud:0,exclus:6,exist:[0,5,6],exp:0,expect:[0,5],expens:[0,6],export_meta_graph:0,expos:0,express:0,extent:6,extra:0,extra_data:0,face:0,facilit:2,fact:[5,6],factor:[0,6],fall:0,fals:[0,5,6],fantas:5,far:[0,6],fashion:[0,1,6],fast:0,faster:[0,1],fe60a7d9a375d64208266f96a739ab01f62a0c78:6,featur:6,feed:6,feel:6,fetch:6,few:[5,6],fg_valu:0,field:0,fig:[5,6],figsiz:[5,6],figur:[5,6],file:[0,1],filenam:0,fill:[0,5],filter:[0,5,6],find:[0,6],fine:6,finish:[0,1,6],first:[0,1,5,6],fit:6,flag:0,flip:4,float32:[0,5,6],fmap_inc_factor:6,fold:0,follow:[0,1,5,6],form:[0,4,6],format:[0,1],formul:[1,6],forward:0,found:0,four:6,fraction:0,fraction_neg:0,fraction_posit:0,frame:4,frame_:0,framework:2,free:[0,6],freq:0,frequenc:0,from:[0,1,2,4,5,6],from_nx_graph:0,fulfil:0,full:0,funkelab:6,funlib:6,further:0,furthermor:0,gain:0,gaussian:[0,5,6],gave:6,gcc:1,gener:[0,6],generictrain:0,geometr:2,geometri:2,get:[0,1,5,6],get_begin:0,get_bounding_box:0,get_cent:0,get_end:0,get_shap:0,get_tensor_by_nam:0,get_total_roi:0,git:6,github:6,give:[0,1,4,5,6],given:[0,5,6],glob:0,goe:5,going:[1,5],good:5,gpu:[0,1,6],gradient:[0,1],graph:1,graph_kei:0,graph_spec:0,gredient:1,grid:0,ground:[0,1,4,5,6],ground_truth:[5,6],grow:[0,1,5],growboundari:1,grown:5,gt_aff:1,gt_data:[5,6],gt_label:[0,1],guarante:0,guesswork:5,gunpowd:[0,1,3,4,5,6],gzip:[0,1],hand:5,handl:0,happen:5,has:[0,5,6],have:[0,1,5,6],hdf5:[0,1],hdf5sourc:1,hdf5write:1,hdf:[0,1],head:6,help:[0,6],helper:0,here:[0,1,5,6],heterogen:6,highlight:6,hit:[4,5],hold:[0,5],hollow:0,hostnam:0,how:[0,1,4,5,6],howev:[0,5,6],http:6,human:0,id_dim:0,ident:6,identifi:0,iff:0,ignor:0,ignore_mask:0,ignore_mask_erod:0,illustr:[5,6],imag:[2,4,5],implement:[0,5,6],implicitli:5,imshow:[5,6],in_arrai:5,in_channel:6,includ:[0,1,5,6],inclus:0,incom:0,increas:[1,5,6],increment:6,inde:[5,6],independ:[0,5,6],index:[0,2],indic:0,individu:[0,6],infer:0,infinit:[0,5],info:1,inform:[0,5,6],inherit:0,init:0,initi:0,inner_radius_fract:0,input:[0,1,6],input_s:1,input_shap:1,insid:[0,5],inspect:[1,6],instal:[1,2,5,6],instanc:[0,2,5,6],instead:[0,5,6],instruct:5,int8:0,integ:[0,5],integr:0,intens:[0,1,2,4,5],intensity_aug:6,intensityaug:[1,6],inter:1,interest:[0,5,6],intern:6,interpol:0,interpolat:[0,5,6],interpret:[0,6],intersect:0,interv:0,introduc:[0,6],invers:0,invert:5,inverted_raw:5,invertintens:5,involv:5,isotrop:6,issu:6,item:0,iter:[1,2,4,6],its:[0,1,5,6],itself:[0,6],jitter:0,jitter_sigma:[0,6],job:0,json:1,jump:6,just:[0,5,6],keep:[0,1,6],kei:[0,5,6],kept:0,kernel:5,kernel_size_down:6,kernel_size_up:6,kind:6,klb:0,know:6,kwarg:0,label:[1,2],labels_mask:0,larg:[0,2,4,5],larger:[0,1],largest:0,last:[0,1,5],later:[1,6],lead:[0,5],learn:[2,6],learnt:0,least:[0,1],leav:[0,5],left:6,legal:0,len:[5,6],less:0,let:[0,1,5],level:[0,1,6],libboost:1,librari:2,lies:0,like:[0,2,4,5,6],limit:[0,6],line:0,linear:0,linearli:0,link:[0,4,6],list:[0,6],loacat:1,load:[0,1,2,4],loc:0,locat:[1,2,4,5,6],log:[0,1],log_dir:0,log_everi:0,longer:6,look:[0,5,6],loss:[0,1],loss_input:[0,6],loss_weight:1,lost:0,low:0,lzf:0,machin:[0,2],made:[0,4,5],mai:0,main:[5,6],major:1,make:[0,1,5,6],mali:1,mani:[0,4,6],manipul:2,manner:0,manual:[0,6],manual_se:6,map:[0,5,6],mark:0,mask:0,mass:0,match:[0,1,6],math:[1,6],matplotlib:[5,6],matter:5,max:0,max_misalign:[0,1],max_shared_memori:0,maxim:0,mean:[0,1,5,6],median:0,meet:0,memori:[0,1,6],mention:1,merg:[0,5,6],merge_profiling_stat:0,mergeprovid:6,messag:0,meta:[0,1,4,5,6],metadata:0,method:[0,5],might:[0,4,5,6],mimic:0,min:0,min_mask:0,minim:[0,2],mirror:[0,1,4,5,6],mirror_onli:0,miss:0,mknet:1,mode:[0,6],model:[0,4],modif:6,modifi:[0,5,6],modul:[0,2,6],moment:0,more:[0,5,6],most:[0,5,6],move:0,movi:4,much:[0,1,6],multi:2,multipl:[0,2,5],multipli:5,must:0,naiv:5,naivesmooth:5,name:[0,1,6],ndarrai:0,ndim:0,necessari:[0,1,5],need:[0,1,4,5,6],neg:[0,1,5],negat:0,neighbor:[0,1,5],neighborhood:0,net:[1,6],net_config:1,network:[0,2],networkx:0,neural:[1,6],neuron:1,neuron_id:1,nevertheless:6,newaxi:[5,6],next:[1,2,5],node:[1,2,4,6],nois:[0,6],noise_aug:6,noiseaug:6,non:[0,5,6],none:[0,5,6],nonspati:0,normal:[1,5,6],notabl:[5,6],note:0,notebook:6,noth:[0,5,6],notic:0,now:[0,1,5,6],num_class:0,num_fmap:6,num_fmaps_out:[],num_repetit:0,num_thread:0,num_work:[0,1],number:[0,1,5,6],numpi:[0,5,6],object:[0,1],observ:5,obtain:0,occur:5,odd_request:6,offer:0,offset:[0,5],often:0,onc:[1,4,6],one:[0,1,4,5,6],ones:[0,5],onli:[0,5,6],only_xi:[0,1],open:[1,5,6],oper:[0,4,5,6],oppos:0,optim:[0,1],option:[0,6],orchestr:6,order:[0,5,6],orient:0,origin:[0,5],other:[0,5,6],otherwis:0,our:[1,5,6],out:[0,5,6],out_arrai:5,output:[1,2,5,6],output_dir:[0,1],output_filenam:[0,1,6],output_s:1,output_shap:1,outsid:0,over:[0,1,2,6],overlap:5,oversampl:0,overview:2,overwrit:[0,5],overwritten:0,own:2,p_nonempti:0,packag:[1,5,6],pad:6,page:2,pair:0,parallel:[0,1,6],param:0,paramet:[0,1,6],part:[0,1,6],partial:[0,5],particular:[0,2,5,6],pass:[0,1,4,5,6],path:[0,4],peak:0,per:[0,1],perform:[1,2,4,5,6],pick:[0,4,5],piec:6,piecewis:0,pip:[1,3,5,6],pipelin:[0,2,4,5],pixel:5,place:[0,2],placehold:[0,5,6],plt:[5,6],plu:0,plug:5,point:[1,2],point_balance_radiu:0,points_spec:0,popul:0,port:0,posit:[0,1,5],possibl:0,potenti:6,practic:5,pre:[0,1,2,6],precach:1,pred_aff:1,pred_affs_gradi:1,predict:[2,4],predictions_sample_a:1,prefix:5,prepar:[0,2],present:5,preserv:0,prevent:0,previou:[0,5],print:[0,1,5,6],print_funct:1,printprofilingstat:1,prob_artifact:0,prob_deform:0,prob_low_contrast:0,prob_miss:0,prob_shift:[0,1],prob_slip:[0,1],probabl:0,problem:5,procedur:6,proceedur:0,process:[1,2],produc:[0,5,6],product:[5,6],profil:[0,6],properti:0,provid:[1,2,5,6],provider_spec:0,pure:0,put:1,pyklb:0,pyplot:[5,6],python:1,pytorch:[2,6],queri:0,queue:0,quickli:[0,1],quit:5,radiu:[0,5],random:[0,1,2,4,5],random_loc:[5,6],random_nois:0,random_se:0,randomli:[0,6],randomloc:[1,5,6],randomprovid:1,rang:[0,1,6],raster:0,rasterizationset:0,ratio:0,raw1:5,raw2:5,raw:[0,1,5,6],raw_data:[5,6],raw_roi:1,read:[0,1,4,5,6],read_roi:0,readabl:0,reader:0,realli:5,reason:5,reassembl:6,receiv:[0,5],recommend:0,recompute_missing_point:0,record:0,rectangular:0,refer:[1,2,6],referenc:0,regard:1,regardless:0,region:[0,5,6],reject_prob:0,rel:[0,6],relabel_connected_compon:0,relai:0,relat:0,remain:[0,6],remind:5,remov:0,remove_edg:0,remove_nod:0,repeat:[0,5],repeatedli:0,repeatli:1,replac:[0,5,6],report:0,repres:0,request:[1,2,4],request_batch:[0,1,5,6],request_left:5,request_right:5,requir:[0,1,4,5,6],rerun:6,resolut:[0,4,5,6],resourc:0,respect:0,restor:0,result:[0,2,5,6],retain_connect:0,retriev:0,reveal:6,revisit:5,rgb:6,right:0,roi:[1,5,6],roi_map:0,rotat:[0,4,6],rotation_interv:[0,6],row:[5,6],run:[0,5],run_blockwis:0,runtim:0,safe:6,same:[0,1,5,6],sampl:[0,1,2,4,5],sample_:1,sample_a_padded_20160501:1,sample_data:[5,6],satisfi:[0,4,5,6],save:[0,1,6],save_everi:[0,1],scalar:0,scale:[0,1,6],scale_max:[0,1,6],scale_min:[0,1,6],scale_shift:0,scan:[1,6],scan_request:6,scikit:0,scope:0,script:1,search:2,sec_requests_batch:0,second:[0,5,6],section:0,see:[0,1,5,6],seed:[0,5,6],seem:5,seen:[0,5,6],segment:[2,4,6],select:[0,6],self:[0,5],send:[0,5,6],sens:0,sent:[0,4,5],separ:0,sequenc:[0,4,5],sequenti:6,seri:0,serv:[0,1],server:0,set:[0,1,5,6],set_shap:0,setup:[0,5],sever:[0,4,6],shape:[0,5,6],share:0,sharei:[5,6],sharex:[5,6],sherri:1,shield:5,shift:[0,1,5,6],shift_max:[0,1,6],shift_min:[0,1,6],should:[0,1,5],show:[0,1,5,6],shown:[5,6],shrink:0,sigma:[0,5,6],sigmoid:6,signal:6,signific:5,significantli:0,similar:[0,4,6],simpl:[0,2,4,5],simple_aug:[5,6],simpleaug:[1,5,6],simpler:1,simpli:[0,5,6],simultan:[0,6],sinc:[0,5,6],singl:[0,6],sink:0,size:[0,1,4,5,6],skimag:[0,5,6],skip:0,skip_empti:0,slab:0,slice:0,slight:6,slip:0,small:6,smaller:[0,6],smallest:0,smooth:5,snap:0,snap_to_grid:0,snapshot:1,snapshot_request:1,snapshotrequest:0,snippet:6,solv:0,some:[0,5,6],someth:5,sometim:5,sort:0,sourc:[1,2,4,5],source_gt:6,source_raw:6,spacial:[0,5],spars:0,spatial:[0,4,5,6],spatial_dim:0,spawn:[0,1],spawn_subprocess:0,spec:[0,1,5],special:6,specif:[2,5,6],specifi:[0,6],speed:0,spend:1,spent:0,sphere:0,squar:6,squeez:[5,6],stack:[4,6],stage:5,standard:0,start:[0,1,5,6],statist:0,step:[0,1,5,6],still:[1,5,6],stop:0,storag:2,store:[0,1,5,6],store_value_rang:0,str:0,strategi:0,strength:0,strict:0,string:0,structur:0,stuctur:0,sub:5,subcategori:0,subclass:0,subplot:[5,6],subsampl:0,subsequ:[0,1,6],substanti:0,subtl:5,subtract:[0,5],successfulli:0,sudo:1,sum:0,summair:0,summari:[0,1],superclass:0,support:[0,6],suppos:5,sure:[0,5,6],surpris:5,szip:0,tag:0,tailor:6,take:[0,5,6],target:0,task:4,tbatch:5,teardown:0,technic:5,tell:[5,6],templat:0,temporari:0,ten:4,tensor:[0,1],tensorboard:0,tensorflow:[1,2,6],test:[0,2],test_net:1,test_net_config:1,text:0,than:[0,5],thei:[0,4,5,6],them:[0,1,6],therefor:[5,6],thi:[0,1,4,5,6],thing:1,think:5,those:[0,5,6],thought:4,thread:0,three:6,threshold:0,through:[0,5,6],thu:[0,2],tied:2,time:[0,1,5,6],to_nx_graph:0,to_slic:0,todo:1,togeth:[0,1,4,5,6],told:6,top:6,topic:[5,6],torch:6,total:0,toward:[0,6],train:[2,4,5],train_net:1,train_net_checkpoint_:1,train_net_config:1,train_step:0,transform:[0,1,6],transpar:6,transpos:[0,1,5,6],transpose_onli:[0,1],treat:[0,5],trequest:5,trigger:1,trim:0,truncat:5,truth:[0,1,4,5,6],tube:0,tupl:[0,1,5],turn:5,tutori:[1,2],two:[0,5,6],type:[0,4,5,6],ubuntu:1,uint8:[0,5,6],ultim:5,unbound:0,unbounded:0,unchang:0,underli:5,undersampl:0,undo:5,unet:6,uniformli:0,union:0,uniqu:[0,1],unit:[0,1],unknown:0,unlabel:0,unless:0,until:[0,6],updat:[0,4,5],upper:0,upstream:[0,1,4,5,6],use:[0,1,4,5,6],use_fast_points_transform:0,used:[0,1,5,6],useful:[0,5,6],user:6,uses:[0,5,6],using:[0,1,5,6],usual:0,util:[0,5],uuid:0,valid:[0,6],valu:[0,1,5,6],variabl:0,veri:6,versa:0,version:[0,5],vertic:0,via:[0,1,5,6],vice:0,view:[0,5],virtual:5,visibl:0,visit:[4,5],visual:[0,6],volum:[0,1,2],voxel:[0,1,5,6],voxel_s:[0,1,5],wai:[0,5,6],wall:0,want:[0,1,4],warn:0,weight:[0,1],well:[0,1,6],were:[0,5,6],what:[0,1,5],whatev:5,when:[0,1,5,6],where:[0,5,6],whether:0,which:[0,1,5,6],whole:[0,1,2,5],wise:0,wish:6,within:[0,5,6],without:[0,1],word:5,work:[0,5,6],worker:[0,1],world:[0,1],would:[0,5,6],wrapper:0,write:[0,2,6],write_roi:0,written:[1,5],wrote:5,wrt:1,yet:0,you:[0,2,5,6],your:[0,2],yourself:6,z_section_wis:[0,1],zarr:[0,5,6],zarr_writ:6,zarrsourc:[5,6],zarrwrit:6,zero:0},titles:["API Reference","Example: Boundary Prediction for Instance Segmentation","Gunpowder Documentation","Installation","Overview","Tutorial: Writing Your Own Node","Tutorial: A Simple Pipeline"],titleterms:{"class":0,"new":5,The:5,addaffin:0,addit:5,api:0,arrai:[0,5,6],arraykei:0,arrayspec:0,assembl:1,augment:[0,6],balancelabel:0,base:0,basic:5,batch:[0,6],batchfilt:0,batchprovid:0,batchrequest:0,boundari:1,chang:[5,6],combin:0,contain:0,coordin:0,creat:[1,5,6],crop:0,csvpointssourc:0,daisyrequestblock:0,data:[0,5,6],defectaug:0,document:2,downsampl:0,dvidsourc:0,edg:0,elasticaug:0,exampl:[1,6],excludelabel:0,further:6,geometr:6,geometri:0,graph:0,graphkei:0,graphspec:0,growboundari:0,gunpowd:2,hdf5sourc:0,hdf5write:0,helper:[5,6],imag:[0,6],indic:2,instal:3,instanc:1,intens:6,intensityaug:0,intensityscaleshift:0,iter:0,klbsourc:0,label:0,larg:6,locat:0,loss:6,manipul:0,mergeprovid:0,minim:6,model:6,multipl:6,network:[1,6],next:6,node:[0,5],noiseaug:0,normal:0,offset:6,optim:6,output:0,overview:4,own:5,pad:0,perform:0,pipelin:[1,6],place:5,point:0,precach:0,predict:[0,1,6],preliminari:[5,6],prepar:[5,6],printprofilingstat:0,process:[0,5],provid:0,providerspec:0,random:6,randomloc:0,randomprovid:0,rasterizegraph:0,refer:0,reject:0,renumberconnectedcompon:0,request:[0,5,6],roi:0,sampl:6,scan:0,segment:1,simpl:6,simpleaug:0,snapshot:0,sourc:[0,6],specif:0,specifiedloc:0,squeez:0,stack:0,tabl:2,tensorflow:0,test:1,torch:0,train:[0,1,6],tutori:[5,6],unsqueez:0,upsampl:0,what:[2,6],whole:6,write:5,your:5,zarrsourc:0,zarrwrit:0}}) \ No newline at end of file diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css new file mode 100644 index 00000000..733aec05 --- /dev/null +++ b/docs/source/_static/css/custom.css @@ -0,0 +1,75 @@ +:root { + --color-a: #60c557; + --color-b: #84d27d; + --color-c: #36872f; + --color-a-light: #60c55733; + --color-b-light: #84d27d33; + --color-c-light: #36872f33; + --color-dark-bg: #484848; +} + +.wy-nav-top { + background: var(--color-a); +} + +.wy-side-nav-search { + background: var(--color-dark-bg); +} + +a { + color: var(--color-a); +} +a:hover { + color: var(--color-c); +} + +a:visited { + color: var(--color-c-light); +} + +.wy-menu-vertical a { + filter: brightness(1.8); +} + +.wy-menu-vertical a:active { + background-color: var(--color-b); +} + +.wy-menu-vertical a:visited { + filter: brightness(1.8); +} + +.rst-content .admonition-title { + background: var(--color-a); +} + +.rst-content .hint .admonition-title { + background: var(--color-a-light); +} + +button.toggle-button { + color: var(--color-a-light); +} + +.rst-content .admonition { + background: var(--color-a-light); +} + +.rst-content .admonition-title::before { + content: ""; +} + +.rst-content code.literal { + color: var(--color-a); +} + +html.writer-html4 .rst-content dl:not(.docutils) > dt { + color: var(--color-a); + border-top-color: var(--color-a); + background: var(--color-a-light); +} +html.writer-html5 .rst-content dl[class]:not(.option-list):not(.field-list):not(.footnote):not(.glossary):not(.simple) > dt { + color: var(--color-a); + border-top-color: var(--color-a); + background: var(--color-a-light); +} diff --git a/docs/build/api.rst b/docs/source/api.rst similarity index 97% rename from docs/build/api.rst rename to docs/source/api.rst index 20b7943f..5f120a1c 100644 --- a/docs/build/api.rst +++ b/docs/source/api.rst @@ -4,7 +4,7 @@ API Reference ============= .. automodule:: gunpowder - :noindex: + :no-index: Data Containers --------------- @@ -48,7 +48,7 @@ Requests and Specifications ProviderSpec ^^^^^^^^^^^^ .. autoclass:: ProviderSpec - :members: array_specs, points_specs, items + :members: items BatchRequest ^^^^^^^^^^^^ @@ -73,11 +73,6 @@ Coordinate .. autoclass:: Coordinate :members: -Roi -^^^ - .. autoclass:: Roi - :members: - Node Base Classes ----------------- @@ -233,7 +228,7 @@ RenumberConnectedComponents ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: RenumberConnectedComponents -Point Processing Nodes +Graph Processing Nodes ---------------------- RasterizeGraph @@ -300,6 +295,7 @@ Output Nodes ------------ .. automodule:: gunpowder + :no-index: Hdf5Write ^^^^^^^^^ diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 00000000..529dbe8b --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,71 @@ +# -*- coding: utf-8 -*- +# +# gunpowder documentation build configuration file, created by +# sphinx-quickstart on Fri Jun 30 12:59:21 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# + +from datetime import datetime + +import gunpowder +import tomli + +with open("../../pyproject.toml", "rb") as fh: + project = tomli.load(fh)["project"] + +author_list = ", ".join([author["name"] for author in project["authors"]]) + +project = "gunpowder" +copyright = f"{datetime.now().year}, {author_list}" +author = author_list +version = gunpowder.version_info.__version__ +release = gunpowder.version_info.__version__ + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + "jupyter_sphinx", + "sphinx.ext.autodoc", + "sphinx.ext.githubpages", + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", + "sphinx_rtd_theme", + "sphinx_togglebutton", + "sphinxcontrib.jquery", +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "sphinx_rtd_theme" +html_logo = "img/gunpowder.svg" +html_static_path = ["_static"] +html_css_files = ["css/custom.css"] +html_show_sourcelink = False + +togglebutton_hint = "" +togglebutton_hint_hide = "" + +pygments_style = "lovelace" diff --git a/docs/_static/gunpowder.svg b/docs/source/img/gunpowder.svg similarity index 100% rename from docs/_static/gunpowder.svg rename to docs/source/img/gunpowder.svg diff --git a/docs/build/index.rst b/docs/source/index.rst similarity index 98% rename from docs/build/index.rst rename to docs/source/index.rst index 03a035b2..6d57849f 100644 --- a/docs/build/index.rst +++ b/docs/source/index.rst @@ -32,7 +32,6 @@ tied to a particular learning framework, and thus complements libraries like tutorial_simple_pipeline tutorial_batch_provider api - example_boundaries Indices and tables ================== diff --git a/docs/build/install.rst b/docs/source/install.rst old mode 100755 new mode 100644 similarity index 100% rename from docs/build/install.rst rename to docs/source/install.rst diff --git a/docs/build/overview.rst b/docs/source/overview.rst similarity index 100% rename from docs/build/overview.rst rename to docs/source/overview.rst diff --git a/docs/build/tutorial_batch_provider.rst b/docs/source/tutorial_batch_provider.rst similarity index 99% rename from docs/build/tutorial_batch_provider.rst rename to docs/source/tutorial_batch_provider.rst index a2d9ff62..a7d19453 100644 --- a/docs/build/tutorial_batch_provider.rst +++ b/docs/source/tutorial_batch_provider.rst @@ -1,6 +1,7 @@ .. _sec_tutorial_batch_provider: .. automodule:: gunpowder + :no-index: Tutorial: Writing Your Own Node ------------------------------- @@ -352,7 +353,7 @@ The next version of our smooth node will therefore do the following: roi = request[self.array].roi # 1. compute the context - context = gp.Coordinate((self.truncate,)*roi.dims()) * self.sigma + context = gp.Coordinate((self.truncate,)*roi.dims) * self.sigma # 2. enlarge the requested ROI by the context context_roi = roi.grow(context, context) diff --git a/docs/build/tutorial_simple_pipeline.rst b/docs/source/tutorial_simple_pipeline.rst similarity index 100% rename from docs/build/tutorial_simple_pipeline.rst rename to docs/source/tutorial_simple_pipeline.rst diff --git a/docs/tutorial_batch_provider.html b/docs/tutorial_batch_provider.html deleted file mode 100644 index 96d07c11..00000000 --- a/docs/tutorial_batch_provider.html +++ /dev/null @@ -1,1008 +0,0 @@ - - - - - - - - - - - Tutorial: Writing Your Own Node — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Tutorial: Writing Your Own Node

-

This tutorial illustrates how to write your own gunpowder node. We will -cover the following topics:

- -

We will use the same example data used in the previous -tutorial. To follow along with the tutorial, -have a look at the following preliminaries:

-
-

Tutorial Preliminaries: Data Preparation and Helpers

-

To follow the example here, install those packages…:

-
pip install gunpowder
-pip install zarr
-pip install matplotlib
-
-
-

…and run the following code to set up the dataset and define a helper -function to display images:

-
-
-
import matplotlib.pyplot as plt
-import numpy as np
-import random
-import zarr
-from skimage import data
-from skimage import filters
-
-# make sure we all see the same
-np.random.seed(23619)
-random.seed(23619)
-
-# open a sample image (channels first)
-raw_data = data.astronaut().transpose(2, 0, 1)
-
-# create some dummy "ground-truth" to train on
-gt_data = filters.gaussian(raw_data[0], sigma=3.0) > 0.75
-gt_data = gt_data[np.newaxis,:].astype(np.float32)
-
-# store image in zarr container
-f = zarr.open('sample_data.zarr', 'w')
-f['raw'] = raw_data
-f['raw'].attrs['resolution'] = (1, 1)
-f['ground_truth'] = gt_data
-f['ground_truth'].attrs['resolution'] = (1, 1)
-
-# helper function to show image(s), channels first
-def imshow(raw1, raw2=None):
-  rows = 1
-  if raw2 is not None:
-    rows += 1
-  cols = raw1.shape[0] if len(raw1.shape) > 3 else 1
-  fig, axes = plt.subplots(rows, cols, figsize=(10, 4), sharex=True, sharey=True, squeeze=False)
-  if len(raw1.shape) == 3:
-    axes[0][0].imshow(raw1.transpose(1, 2, 0))
-  else:
-    for i, im in enumerate(raw1):
-      axes[0][i].imshow(im.transpose(1, 2, 0))
-  row = 1
-  if raw2 is not None:
-    if len(raw2.shape) == 3:
-      axes[row][0].imshow(raw2.transpose(1, 2, 0))
-    else:
-      for i, im in enumerate(raw2):
-        axes[row][i].imshow(im.transpose(1, 2, 0))
-  plt.show()
-
-
-
-
-
-
-
-

The data we are working with is shown below. It is stored in a zarr -container sample_data.zarr in dataset called raw, which has one -attribute resolution = (1, 1):

-
-
-
imshow(zarr.open('sample_data.zarr')['raw'][:])
-
-
-
-
-_images/tutorial_batch_provider_1_0.png -
-
-
-

The basics: prepare and process

-

As we have already seen in the previous -tutorial, the concepts of requests and -batches are central to gunpowder. As a reminder, requests are send -upstream in a pipeline to ask for data, and batches are sent downstream, -being modified by the nodes they pass through.

-

This concept is illustrated by the following simple pipeline that reads image -data from a zarr source, picks a random location in it, and augments the -data (by random mirrors and transpose operations):

-
-
-
import gunpowder as gp
-
-raw = gp.ArrayKey('RAW')
-
-source = gp.ZarrSource(
-    'sample_data.zarr',  # the zarr container
-    {raw: 'raw'},  # which dataset to associate to the array key
-    {raw: gp.ArraySpec(interpolatable=True)}  # meta-information
-)
-random_location = gp.RandomLocation()
-simple_augment = gp.SimpleAugment()
-pipeline = source + random_location + simple_augment
-
-request = gp.BatchRequest()
-request[raw] = gp.Roi((0, 0), (64, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_batch_provider_2_0.png -
-
-

After building the pipeline, we request a batch by sending a specific -request. On its way up, this request gets modified by the nodes in the -pipeline it visits. When the request hits source, this node creates the -actual batch and fills it with the requested data. The batch is then passed -down again through the pipeline to visit each node a second time.

-

Most of the nodes in gunpowder are BatchFilters, -which implement two methods:

-
    -
  1. BatchFilter.prepare() is being called for a request that passes -through the node on its way up the pipeline.

  2. -
  3. BatchFilter.process() is being called for a batch that passes through -the node on its way down the pipeline.

  4. -
-

You can write your own node by sub-classing BatchFilter and implement -either of the two methods. To see how that works, let’s start with a simple -node that does nothing but to print the request and the batch that pass through -it:

-
-
-
class Print(gp.BatchFilter):
-
-  def __init__(self, prefix):
-    self.prefix = prefix
-
-  def prepare(self, request):
-    print(f"{self.prefix}\tRequest going upstream: {request}")
-
-  def process(self, batch, request):
-    print(f"{self.prefix}\tBatch going downstream: {batch}")
-
-
-
-
-
-
-

The argument to prepare is the current request being sent upstream. -process, on the other hand, is called with the batch. It also receives the -original request (the same one sent earlier to prepare) as a second -argument for convenience.

-

If we plug this new node into our pipeline, we see the following output:

-
-
-
pipeline = (
-  source +
-  Print("A") +
-  random_location +
-  Print("B") +
-  simple_augment +
-  Print("C"))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-
C	Request going upstream: 
-	RAW: ROI: [0:64, 0:128] (64, 128), voxel size: None, interpolatable: None, non-spatial: False, dtype: None, placeholder: False
-
-B	Request going upstream: 
-	RAW: ROI: [-32:96, 32:96] (128, 64), voxel size: None, interpolatable: None, non-spatial: False, dtype: None, placeholder: False
-
-A	Request going upstream: 
-	RAW: ROI: [108:236, 13:77] (128, 64), voxel size: None, interpolatable: None, non-spatial: False, dtype: None, placeholder: False
-
-A	Batch going downstream: 
-	RAW: ROI: [108:236, 13:77] (128, 64), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: uint8, placeholder: False
-
-B	Batch going downstream: 
-	RAW: ROI: [-32:96, 32:96] (128, 64), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: uint8, placeholder: False
-
-C	Batch going downstream: 
-	RAW: ROI: [0:64, 0:128] (64, 128), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: uint8, placeholder: False
-
-
-
-_images/tutorial_batch_provider_4_1.png -
-
-

Our print node with the prefix C directly receives the request we sent. -After passing through simple_augment, we can now see that the request was -modified: simple_augment apparently decided to perform a transpose on the -batch, and is consequently requesting raw data in a transposed ROI, as we can -see from the request that print node B received. Notably, the new request -is technically out of bounds (the y dimension has a negative offset). -random_location, however, shifts whatever request it receives to a random -location inside the area provided upstream. We see the effect of that in -print node A, where the request has been modified to start at (177, -289). This is the request that is ultimately passed to source, which -creates a batch with raw data from exactly this location.

-

As the batch goes down the pipeline again, we see that each node undoes the -changes it made to the request. For example: random_location was asked to -provide data from [-32:96, 32:96]. Although it modified the request with a -random shift to read from [177:305, 289:353], it still claims the data came -from [-32:96, 32:96].

-

This is a deliberate design decision in gunpowder: Every node provides a -batch with exactly the ROIs that were requested. It would be quite surprising -if a request to a ROI [-32:96, 32:96] was answered with data in a ROI -[177:305, 289:353]. Instead, we treat nodes like RandomLocation or -SimpleAugment as views into some virtual data. This data does not -have to be static, it can change between different requests on the discretion -of the node. -A good way to think about RandomLocation is therefore that it provides -data in an infinitely large region. No matter where in this region you request -data, it will return a random sample of the data that is provided upstream, as -if this data just happened to be where you requested it.

-
-
-

Changing an array in-place

-

The following example shows how to perform a simple in-place operation on an -array. For that, we will create a node that inverts the intensity of the raw -data passing through it. We will use the invert() method from skimage -to do that:

-
-
-
from skimage import util
-
-class InvertIntensities(gp.BatchFilter):
-
-  def __init__(self, array):
-    self.array = array
-
-  def process(self, batch, request):
-
-    data = batch[self.array].data
-    batch[self.array].data = util.invert(data)
-
-# ensure that raw is float in [0, 1]
-normalize = gp.Normalize(raw)
-
-pipeline = (
-  source +
-  normalize +
-  random_location +
-  InvertIntensities(raw))
-
-# increase size of request to better see the result
-request[raw] = gp.Roi((0, 0), (128, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_batch_provider_5_0.png -
-
-

This example shows how to get access to the data of an array stored in a batch. -This is, in fact, not different from how we accessed the data of the batch -after it was returned from the pipeline. A batch acts as a dictionary, mapping -ArrayKeys to Arrays. Each Array, in -turn, has a data attribute (the numpy array containing the actual data) -and a spec attribute (an instance of ArraySpec, containing the -ROI, resolution, and other meta-information).

-
-

Note

-

It is good practice to pass the array key of arrays that are supposed to be -modified by a node to its constructor and store it in the node. Here, we tell -InvertIntensities to only modify raw. If our batch would contain more -than one array, this allows us to modify only the one we are interested in. -This does not apply to nodes that modify all arrays in a batch equally, like -RandomLocation or ElasticAugment.

-
-

Since our simple InvertIntensities node does not need to change the request -(it does not require additional data or change the ROI of an array in the -passing through batch), we did not have to implement the prepare() method -in this case.

-
-
-

Requesting additional data

-

Sometimes, the output of a node depends on additional data. Consider, for -example, the case of simple Gaussian smoothing of the image. A naive in-place -implementation would look something like this:

-
-
-
from skimage import filters
-
-class NaiveSmooth(gp.BatchFilter):
-
-  def __init__(self, array, sigma):
-    self.array = array
-    self.sigma = sigma
-
-  def process(self, batch, request):
-
-    data = batch[self.array].data
-    batch[self.array].data = filters.gaussian(data, sigma=self.sigma)
-
-pipeline = (
-  source +
-  normalize +
-  NaiveSmooth(raw, sigma=5.0))
-
-# request data in a specific location
-request[raw] = gp.Roi((100, 100), (128, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_batch_provider_6_0.png -
-
-

This does not look bad, but there is a subtle problem here: Gaussian smoothing -close to the boundary will have to fantasize some data that is not present -beyond the boundary. The skimage.filter.gaussian implementation will simply -repeat the last observed value at the boundary by default. We can see that this -leads to border artifacts if we make two requests of ROIs that are neighboring -and look at their concatenated output:

-
-
-
request_left = gp.BatchRequest()
-request_left[raw] = gp.Roi((100, 100), (128, 128))
-request_right = gp.BatchRequest()
-request_right[raw] = gp.Roi((100, 228), (128, 128))
-
-with gp.build(pipeline):
-  batch_left = pipeline.request_batch(request_left)
-  batch_right = pipeline.request_batch(request_right)
-
-concatenated = np.concatenate([batch_left[raw].data, batch_right[raw].data], axis=2)
-imshow(concatenated)
-
-
-
-
-_images/tutorial_batch_provider_7_0.png -
-
-

In order to avoid this border artifact, we will need to have access to more -data than just requested by the ROI we received. In particular, the amount of -context we need is given by sigma and the truncate value used by -skimage.filters.gaussian. The product of the two defines the radius of the -kernel that skimage uses to smooth the image. For a pixel at the boundary, -this means that it needs at most sigma * truncate additional pixels beyond -the boundary to compute the correct result.

-

The next version of our smooth node will therefore do the following:

-
    -
  1. Compute the context needed in each direction.

  2. -
  3. Increase the requested ROI by this context, effectively asking for more data -upstream than what was requested from downstream.

  4. -
  5. Smooth the whole image it receives.

  6. -
  7. Crop the result back to the requested ROI.

  8. -
-
-
-
class Smooth(gp.BatchFilter):
-
-  def __init__(self, array, sigma):
-    self.array = array
-    self.sigma = sigma
-    self.truncate = 4
-
-  def prepare(self, request):
-
-    # the requested ROI for array
-    roi = request[self.array].roi
-
-    # 1. compute the context
-    context = gp.Coordinate((self.truncate,)*roi.dims()) * self.sigma
-
-    # 2. enlarge the requested ROI by the context
-    context_roi = roi.grow(context, context)
-
-    # create a new request with our dependencies
-    deps = gp.BatchRequest()
-    deps[self.array] = context_roi
-
-    # return the request
-    return deps
-
-  def process(self, batch, request):
-
-    # 3. smooth the whole array (including the context)
-    data = batch[self.array].data
-    batch[self.array].data = filters.gaussian(
-      data,
-      sigma=self.sigma,
-      truncate=self.truncate)
-
-    # 4. crop the array back to the request
-    batch[self.array] = batch[self.array].crop(request[self.array].roi)
-
-pipeline = (
-  source +
-  normalize +
-  Smooth(raw, sigma=5.0))
-
-with gp.build(pipeline):
-  batch_left = pipeline.request_batch(request_left)
-  batch_right = pipeline.request_batch(request_right)
-
-concatenated = np.concatenate([batch_left[raw].data, batch_right[raw].data], axis=2)
-imshow(concatenated)
-
-
-
-
-_images/tutorial_batch_provider_8_0.png -
-
-

As expected, we used the prepare() method to enlarge the ROI of the -requested array. For that, we first compute the context needed as a -Coordinate. A Coordinate in gunpowder is really just a -tuple of integers, with some operators attached such that it is convenient to -add, subtract, multiply, and divide coordinates. All of those operations are -dimension independent. In fact, the node we have just written would equally -work for requests with an arbitrary number of spacial dimensions.

-
-

Note

-

Coordinate to be a tuple of integers is a deliberate design -decision. Those coordinates do also underly Roi, i.e., a ROI is also -always defined by an integer offset and size.

-
-

Still within prepare(), we use Roi.grow() to create a ROI that is -enlarged by context in both the negative and positive direction. Finally, -we create a new batch request with the enlarged ROI for array and return it -from prepare(). This instructs gunpowder to merge this dependency with -whatever else might be contained in the current request and pass this request -upstream.

-

When we receive the batch in process, it does contain data for array in -the enlarged ROI. After applying the Gaussian filter to it, we crop it using -the convenience function Array.crop(). This function uses the -meta-information stored in an Array to figure out where exactly to -crop the data (in particular, it uses the spec.roi and spec.voxel_size -attribute stored in the array).

-

Finally, we will have a look at the sequence of requests made in our updated -pipeline, using the Print node we wrote at the beginning of this tutorial:

-
-
-
pipeline = (
-  source +
-  normalize +
-  Print("before Smooth") +
-  Smooth(raw, sigma=5.0) +
-  Print("after Smooth"))
-
-request = gp.BatchRequest()
-request[raw] = gp.Roi((100, 100), (128, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-
-
-
-
after Smooth	Request going upstream: 
-	RAW: ROI: [100:228, 100:228] (128, 128), voxel size: None, interpolatable: None, non-spatial: False, dtype: None, placeholder: False
-
-before Smooth	Request going upstream: 
-	RAW: ROI: [80:248, 80:248] (168, 168), voxel size: None, interpolatable: None, non-spatial: False, dtype: None, placeholder: False
-
-before Smooth	Batch going downstream: 
-	RAW: ROI: [80:248, 80:248] (168, 168), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: <class 'numpy.float32'>, placeholder: False
-
-after Smooth	Batch going downstream: 
-	RAW: ROI: [100:228, 100:228] (128, 128), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: <class 'numpy.float32'>, placeholder: False
-
-
-
-
-
-

This confirms that Smooth did indeed increase the ROI for raw. We asked -to smooth with a sigma of 5.0 and set the truncate value to 4.0, which -gives us a context of 20. Consequently, the request send upstream out of -Smooth starts at 80 instead of 100, and the size of the ROI was grown by -40.

-

Although we did request more data for the same array we produce in this -example, this is not required. In your prepare() method, you can ask for -any ROI of any array. This might be useful if your node produces outputs that -should be stored in a new array (leaving the original one as-is) or to combine -multiple arrays into one.

-
-
-

Creating new arrays

-

If your node creates a new array (in contrast to modifying existing ones), one -additional step is required: We have to tell the downstream nodes about the new -array and where it is defined. This is done by overwriting the -BatchFilter.setup() function.

-

For the example here, we will revisit the InvertIntensities node. This -time, however, we will create a new array with the inverted data instead of -replacing the content of the array.

-
-
-
class InvertIntensities(gp.BatchFilter):
-
-  def __init__(self, in_array, out_array):
-    self.in_array = in_array
-    self.out_array = out_array
-
-  def setup(self):
-
-    # tell downstream nodes about the new array
-    self.provides(
-      self.out_array,
-      self.spec[self.in_array].copy())
-
-  def prepare(self, request):
-
-    # to deliver inverted raw data, we need raw data in the same ROI
-    deps = gp.BatchRequest()
-    deps[self.in_array] = request[self.out_array].copy()
-
-    return deps
-
-  def process(self, batch, request):
-
-    # get the data from in_array and invert it
-    data = util.invert(batch[self.in_array].data)
-
-    # create the array spec for the new array
-    spec = batch[self.in_array].spec.copy()
-    spec.roi = request[self.out_array].roi.copy()
-
-    # create a new batch to hold the new array
-    batch = gp.Batch()
-
-    # create a new array
-    inverted = gp.Array(data, spec)
-
-    # store it in the batch
-    batch[self.out_array] = inverted
-
-    # return the new batch
-    return batch
-
-# declare a new array key for inverted raw
-inverted_raw = gp.ArrayKey('INVERTED_RAW')
-
-pipeline = (
-  source +
-  normalize +
-  random_location +
-  InvertIntensities(raw, inverted_raw))
-
-request = gp.BatchRequest()
-request[raw] = gp.Roi((0, 0), (128, 128))
-request[inverted_raw] = gp.Roi((0, 0), (128, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, batch[inverted_raw].data)
-
-
-
-
-_images/tutorial_batch_provider_10_0.png -
-
-

The main change compared to the earlier InvertIntensities is that we now -announce a new array in the setup() function. This is done by calling -BatchFilter.provides(). We pass it the key of the array we provide, -together with a ArraySpec. The ArraySpec describes where the -new array is defined (via a ROI), what resolution it has, what the data type -is, and a few more bits of meta-information. In the case here, we simply create -a copy of the ArraySpec of self.in_array. We have access to the -spec of self.in_array through self.spec, which acts as a dictionary -from array keys to array specs for each array that is provided upstream in the -pipeline. We can simply copy the spec here, since this is already the correct -spec for the output array. In more involved cases, it might be necessary to -change the spec accordingly.

-

Another significant difference to the earlier implementation occurs in the -process() method: Instead of changing the passing through batch in-place, -we now create a new batch, add the new array we produce to it, and return this -new batch. gunpowder will take the result of process and merge it with -the original batch. In fact, when we return None (as we did earlier), -gunpowder implicitly assumed that we returned the complete, modified batch.

-

This might seem complex at first, but there is a good reason for it: -The raw array we requested in InvertIntensities (to deliver -inverted_raw) might be different to what was requested independently -downstream. In other words, at some stages in the pipeline, there might be -different requests for the same array. gunpowder shields those conflicting -requests from you, i.e., the raw array you see in process() is exactly -the one you requested, independent of other requests that might have been made -to raw. By requiring nodes to return a new batch with whatever they -produced or changed, we simply eliminate some guesswork for gunpowder.

-

This allows us to run the following pipeline. Here we request raw in one -ROI, and inverted_raw in another, partially overlapping, ROI. Upstream of -InvertIntensities we now have two requests for raw: One to satisfy the -original request for raw, and the other one as a dependency of -InvertIntensities.

-
-
-
request = gp.BatchRequest()
-request[raw] = gp.Roi((0, 0), (128, 128))
-request[inverted_raw] = gp.Roi((64, 64), (128, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, batch[inverted_raw].data)
-
-
-
-
-_images/tutorial_batch_provider_11_0.png -
-
-
-
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/docs/tutorial_simple_pipeline.html b/docs/tutorial_simple_pipeline.html deleted file mode 100644 index 40ef2347..00000000 --- a/docs/tutorial_simple_pipeline.html +++ /dev/null @@ -1,1208 +0,0 @@ - - - - - - - - - - - Tutorial: A Simple Pipeline — gunpowder 1.2.1 documentation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - - -
- - - - - -
- -
- - - - - - - - - - - - - - - - - -
- - - - -
-
-
-
- -
-

Tutorial: A Simple Pipeline

-

The following illustrates how a pipeline like the one above is built using -gunpowder. We will build the pipeline incrementally and see what effect -each change has. Therefore, this tutorial is best read in that order. -Nevertheless, feel free to jump ahead to any of the following topics we are -covering here:

- -

To rerun the example given here yourself, have a look at the -following preliminaries (or simply head over to this tutorial’s -Colab notebook):

-
-

Tutorial Preliminaries: Data Preparation and Helpers

-

To follow the example here, install those packages:

-
pip install gunpowder
-pip install zarr
-pip install matplotlib
-
-
-
-
-
import matplotlib.pyplot as plt
-import numpy as np
-import random
-import zarr
-from skimage import data
-from skimage import filters
-
-# make sure we all see the same
-np.random.seed(19623)
-random.seed(19623)
-
-# open a sample image (channels first)
-raw_data = data.astronaut().transpose(2, 0, 1)
-
-# create some dummy "ground-truth" to train on
-gt_data = filters.gaussian(raw_data[0], sigma=3.0) > 0.75
-gt_data = gt_data[np.newaxis,:].astype(np.float32)
-
-# store image in zarr container
-f = zarr.open('sample_data.zarr', 'w')
-f['raw'] = raw_data
-f['raw'].attrs['resolution'] = (1, 1)
-f['ground_truth'] = gt_data
-f['ground_truth'].attrs['resolution'] = (1, 1)
-
-# helper function to show image(s), channels first
-def imshow(raw, ground_truth=None, prediction=None):
-  rows = 1
-  if ground_truth is not None:
-    rows += 1
-  if prediction is not None:
-    rows += 1
-  cols = raw.shape[0] if len(raw.shape) > 3 else 1
-  fig, axes = plt.subplots(rows, cols, figsize=(10, 4), sharex=True, sharey=True, squeeze=False)
-  if len(raw.shape) == 3:
-    axes[0][0].imshow(raw.transpose(1, 2, 0))
-  else:
-    for i, im in enumerate(raw):
-      axes[0][i].imshow(im.transpose(1, 2, 0))
-  row = 1
-  if ground_truth is not None:
-    if len(ground_truth.shape) == 3:
-      axes[row][0].imshow(ground_truth[0])
-    else:
-      for i, gt in enumerate(ground_truth):
-        axes[row][i].imshow(gt[0])
-    row += 1
-  if prediction is not None:
-    if len(prediction.shape) == 3:
-      axes[row][0].imshow(prediction[0])
-    else:
-      for i, gt in enumerate(prediction):
-        axes[row][i].imshow(gt[0])
-  plt.show()
-
-
-
-
-
-
-
-

The data we are working with is shown below. It is stored in a zarr -container sample_data.zarr in dataset called raw, which has one -attribute resolution = (1, 1):

-
-
-
imshow(zarr.open('sample_data.zarr')['raw'][:])
-
-
-
-
-_images/tutorial_simple_pipeline_1_0.png -
-
-
-

Note

-

The resolution attribute in the zarr dataset will be read by -gunpowder. gunpowder supports anisotropic resultions and even -datasets with different resolutions in the same pipeline. Here, it tells -gunpowder that this is a 2D dataset, with the remaining dimension to be -interpreted as channels. More on this later.

-
-
-

A minimal pipeline

-

The first step for every pipeline is to declare the arrays that will be -used. For now, we will need only one array which we call raw:

-
-
-
import gunpowder as gp
-
-# declare arrays to use in the pipeline
-raw = gp.ArrayKey('RAW')
-
-
-
-
-
-
-

Next we assemble the pipeline itself. To illustrate how gunpowder works, we -will do this step by step and look at the changes each step introduces. We -start with a “pipeline” consisting only of a data source.

-
-
-
# create "pipeline" consisting only of a data source
-source = gp.ZarrSource(
-    'sample_data.zarr',  # the zarr container
-    {raw: 'raw'},  # which dataset to associate to the array key
-    {raw: gp.ArraySpec(interpolatable=True)}  # meta-information
-)
-pipeline = source
-
-
-
-
-
-
-

The pipeline by itself does nothing until we request data from it. What exactly -is requested is specified by a BatchRequest. The following shows how -to create a request for “raw” data, starting at (0, 0) with a size of -(64, 64).

-
-
-
# formulate a request for "raw"
-request = gp.BatchRequest()
-request[raw] = gp.Roi((0, 0), (64, 64))
-
-
-
-
-
-
-

The request behaves like a dictionary, mapping each array key to a region of -interest (ROI), i.e., an offset and a size.

-

It remains to build the pipeline and request a Batch:

-
-
-
# build the pipeline...
-with gp.build(pipeline):
-
-  # ...and request a batch
-  batch = pipeline.request_batch(request)
-
-# show the content of the batch
-print(f"batch returned: {batch}")
-imshow(batch[raw].data)
-
-
-
-
-
batch returned: 
-	RAW: ROI: [0:64, 0:64] (64, 64), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: uint8, placeholder: False
-
-
-
-_images/tutorial_simple_pipeline_5_1.png -
-
-

The returned batch contains a crop of the source image, located in the top left -corner. This is indeed exactly what we requested, as an inspection of our -request reveals:

-
-
-
print(request)
-
-
-
-
-

-	RAW: ROI: [0:64, 0:64] (64, 64), voxel size: None, interpolatable: None, non-spatial: False, dtype: None, placeholder: False
-
-
-
-
-
-

As we can see, the request for RAW (the name we gave to our array key) is -for a ROI that begins at 0 and ends at 64 for each dimension, giving it a shape -of (64, 64). The ZarrSource simply delivered on exactly this -request.

-
-

Further Example: Change Request Offset

-

To create a request for data in a specific area of the source, we simply -change the offset in the request Roi:

-
-
-
request[raw] = gp.Roi((50, 150), (64, 64))
-#                     ^^^^^^^^^
-#                     changed offset
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-print(f"batch returned: {batch}")
-imshow(batch[raw].data)
-
-
-
-
-
batch returned: 
-	RAW: ROI: [50:114, 150:214] (64, 64), voxel size: (1, 1), interpolatable: True, non-spatial: False, dtype: uint8, placeholder: False
-
-
-
-_images/tutorial_simple_pipeline_7_1.png -
-
-
-
-
-

Random samples

-

In training pipelines, however, it might be useful to randomly select a -location to crop data from. Doing this manually by changing the offset of the -ROI in the request we send for every iteration would be cumbersome. It would -also require that we know the size of the data in the source.

-

Instead, gunpowder provides a node RandomLocation that does that -for us, we simply have to add it to our pipeline:

-
-
-
# add a RandomLocation node to the pipeline to randomly select a sample
-
-random_location = gp.RandomLocation()
-pipeline = source + random_location
-
-print(pipeline)
-
-
-
-
-
ZarrSource[sample_data.zarr] -> RandomLocation
-
-
-
-
-

When we now issue the same request, it will first be shifted by -random_location to a random location within the provided data.

-
-
-
with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_simple_pipeline_9_0.png -
-
-

This example illustrates two important concepts in gunpowder:

-
    -
  1. Request can (and will be) changed as they are passed upstream through the -pipeline. In this example, RandomLocation changes the offset of the -request for us, such that we get data from a random location.

  2. -
  3. gunpowder nodes know what kind of data is provided upstream, and what -its extents are. Here, RandomLocation uses this information to find -out where it can safely shift the request to.

  4. -
-
-
-

Geometric augmentation

-

gunpowder provides many more nodes to be added to a pipeline, most of them -tailored towards training pipelines. The following example shows how to add -simple random mirror and transpose augmentations:

-
-
-
simple_augment = gp.SimpleAugment()
-pipeline = source + random_location + simple_augment
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_simple_pipeline_10_0.png -
-
-

The SimpleAugment node will (by default) randomly mirror and/or -transpose batches passing through it. Notably, the transpose operation is -transparent, i.e., if we were to request data in a non-square ROI, we will -still get the size we asked for, transposed or not:

-
-
-
request[raw] = gp.Roi((0, 0), (64, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_simple_pipeline_11_0.png -
-
-

Simple augmentations like this are complemented by random rotations and elastic -deformations, which are provided by the ElasticAugment node:

-
-
-
import math
-
-elastic_augment = gp.ElasticAugment(
-  control_point_spacing=(16, 16),
-  jitter_sigma=(4.0, 4.0),
-  rotation_interval=(0, math.pi/2))
-pipeline = source + random_location + simple_augment + elastic_augment
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_simple_pipeline_12_0.png -
-
-
-
-

Intensity augmentation

-

Intensity values can be modified and random noise added in a similar fashion:

-
-
-
normalize = gp.Normalize(raw)
-intensity_augment = gp.IntensityAugment(
-  raw,
-  scale_min=0.8,
-  scale_max=1.2,
-  shift_min=-0.2,
-  shift_max=0.2)
-noise_augment = gp.NoiseAugment(raw)
-
-pipeline = (
-  source +
-  normalize +
-  random_location +
-  simple_augment +
-  elastic_augment +
-  intensity_augment +
-  noise_augment)
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_simple_pipeline_13_0.png -
-
-

We introduced two new concepts in this snippet:

-

First, we added a Normalize node for raw. This node ensures that -the data type of the given array is np.float64 from there on through the -pipeline. We have so far been agnostic about the exact datatype of raw (it -was uint8, by the way). However, in order to shift intensities and to add -random noise, it is helpful to ensure we are dealing with float values between -0 and 1. The normalization applied by Normalize is data independent, -it is based on the data type of the source (or, optionally, on a user-specified -scaling factor).

-

Second, we introduced nodes that take array keys as arguments -(Normalize, IntensityAugment, and NoiseAugment). -Those nodes limit their operation to the given keys, which is useful if our -batch also contains other arrays (like a ground-truth segmentation) that we do -not wish to modify.

-
-
-

Creating batches with multiple samples

-

So far we have seen how to request a single sample in a “batch”. Normally, -however, batches consist of several samples drawn independently. This can be -done using the Stack node:

-
-
-
stack = gp.Stack(5)
-pipeline = (
-  source +
-  normalize +
-  random_location +
-  simple_augment +
-  elastic_augment +
-  intensity_augment +
-  noise_augment +
-  stack)
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data)
-
-
-
-
-_images/tutorial_simple_pipeline_14_0.png -
-
-
-
-

Requesting multiple arrays

-

To train a model on data, we need a training signal as well. This signal can -come, for example, in the form of a binary segmentation stored alongside the -raw image data. For this tutorial, we will assume that such a binary -segmentation exists and is stored in the same zarr container in a dataset -called ground_truth. At the beginning of this tutorial, we created a dummy -segmentation to work with:

-
-
-
imshow(
-  zarr.open('sample_data.zarr')['raw'][:],
-  zarr.open('sample_data.zarr')['ground_truth'][:])
-
-
-
-
-_images/tutorial_simple_pipeline_15_0.png -
-
-

With a slight modification to the source node and our request, we can now -simultaneously request raw data and a segmentation:

-
-
-
gt = gp.ArrayKey('GROUND_TRUTH')
-
-source = gp.ZarrSource(
-    'sample_data.zarr',
-    {
-      raw: 'raw',
-      gt: 'ground_truth'
-    },
-    {
-      raw: gp.ArraySpec(interpolatable=True),
-      gt: gp.ArraySpec(interpolatable=False)
-    })
-
-request[gt] = gp.Roi((0, 0), (64, 128))
-
-pipeline = (
-  source +
-  normalize +
-  random_location +
-  simple_augment +
-  elastic_augment +
-  intensity_augment +
-  noise_augment +
-  stack)
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, batch[gt].data)
-
-
-
-
-_images/tutorial_simple_pipeline_16_0.png -
-
-

As we can see, our batch does now contain aligned data for both raw and -gt. Notably, both arrays have been transformed in the same way as they were -passed through the pipeline, except for the intensity augmentation parts that -were exclusive to raw. This works even if the requested ROIs for raw -and gt are not identical. Here we see the effect of requesting a -ground-truth ROI that is offset relative to the raw ROI:

-
-
-
# request an offset ROI for ground-truth
-odd_request = request.copy()
-odd_request[gt] = gp.Roi((20, 20), (64, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(odd_request)
-
-imshow(batch[raw].data, batch[gt].data)
-
-
-
-
-_images/tutorial_simple_pipeline_17_0.png -
-
-

This highlights another feature of gunpowder: Requests can contain ROIs -with different offsets and sizes. Internally, gunpowder will figure out -what areas in the source have to be read to satisfy those heterogeneous -requests, and will only read as much as needed to satisfy the request. This is -useful in many applications where ground-truth is not needed for the whole -input image (e.g., because of the use of valid convolutions in neural networks -and the correspondingly smaller network output).

-
-

Further Example: Multiple Sources

-

For now we assumed that both arrays we are interested in (raw and gt) -are read from the same source, i.e., they are stored in the same zarr -container in this example. This might not always be the case. gunpowder -allows you to have multiple sources for different arrays and merge them -together into one. The following example shows this functionality:

-
-
-
source_raw = gp.ZarrSource(
-    'sample_data.zarr',
-    {raw: 'raw'},
-    {raw: gp.ArraySpec(interpolatable=True)}
-)
-source_gt = gp.ZarrSource(
-    'sample_data.zarr',
-    {gt: 'ground_truth'},
-    {gt: gp.ArraySpec(interpolatable=False)}
-)
-combined_source = (source_raw, source_gt) + gp.MergeProvider()
-
-pipeline = (
-  combined_source +
-  normalize +
-  random_location +
-  simple_augment +
-  elastic_augment +
-  intensity_augment +
-  noise_augment +
-  stack)
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, batch[gt].data)
-
-
-
-
-_images/tutorial_simple_pipeline_18_0.png -
-
-
-
-
-

Training a network

-

We have seen so far how gunpowder can be used to generate training batches. -In the following we will see how to train a neural network directly in this -pipeline. For the example, we will train a 2D U-Net (model) on the binary -ground-truth using a binary cross-entropy loss (loss). We will use PyTorch, but the same can be done with a TensorFlow model as well.

-
-

Training Preliminaries: Create Model, Loss, and Optimizer

-

We will use the U-Net implemention from funlib.learn.torch, but any PyTorch model can -be used. To follow the example, install those packages:

-
pip install git+https://github.com/funkelab/funlib.learn.torch@fe60a7d9a375d64208266f96a739ab01f62a0c78
-pip install torch
-
-
-

Here, we create a very simple 2D U-Net mapping from three channels (RGB of -the raw data) to one channel (the segmentation output). The U-Net has two -downsampling modules, downsampling isotropically with a factor of two. We use -‘same’ padding here, meaning that the output size of the U-Net will be the -same as the input size. The number of feature maps will be four in the -top-most level of the U-Net, and increase with a factor of two for each of -the two following levels. The output of the U-Net is further passed through a -sigmoid function to ensure values are between 0 and 1.

-
-
-
import torch
-from funlib.learn.torch.models import UNet, ConvPass
-
-# make sure we all see the same
-torch.manual_seed(18)
-
-unet = UNet(
-  in_channels=3,
-  num_fmaps=4,
-  fmap_inc_factor=2,
-  downsample_factors=[[2, 2], [2, 2]],
-  kernel_size_down=[[[3, 3], [3, 3]]]*3,
-  kernel_size_up=[[[3, 3], [3, 3]]]*2,
-  padding='same')
-
-model = torch.nn.Sequential(
-  unet,
-  ConvPass(4, 1, [(1, 1)], activation=None),
-  torch.nn.Sigmoid())
-
-loss = torch.nn.BCELoss()
-
-optimizer = torch.optim.Adam(model.parameters())
-
-
-
-
-
-
-
-

Training itself is implemented in a gunpowder node, in this case -torch.Train. The main benefit of using this node in a -gunpowder pipeline (compared to just taking the batches we requested so far -and feeding them manually to the model) is that the output of the network -itself can be mapped to a gunpowder array, and subsequently be used in the -pipeline. In the following, we will create a new array key prediction to do -exactly that:

-
-
-
# create new array key for the network output
-prediction = gp.ArrayKey('PREDICTION')
-
-# create a train node using our model, loss, and optimizer
-train = gp.torch.Train(
-  model,
-  loss,
-  optimizer,
-  inputs = {
-    'input': raw
-  },
-  loss_inputs = {
-    0: prediction,
-    1: gt
-  },
-  outputs = {
-    0: prediction
-  })
-
-pipeline = (
-  source +
-  normalize +
-  random_location +
-  simple_augment +
-  elastic_augment +
-  intensity_augment +
-  noise_augment +
-  stack +
-  train)
-
-# add the prediction to the request
-request[prediction] = gp.Roi((0, 0), (64, 128))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, batch[gt].data, batch[prediction].data)
-
-
-
-
-_images/tutorial_simple_pipeline_20_0.png -
-
-

As we can see, our batch does now contain an array prediction, which is the -output of the torch.Train node. This illustrates another feature of -gunpowder: Arrays can be generated by any node, this functionality is not -limited to source nodes (and in fact, source nodes are in no way special, they -are simply gunpowder nodes that do not require an input and provide an -array).

-

But the train node above did not just produce a prediction: Since we also told -it which loss and optimizer to use, and since we linked the output of our -network and the ground-truth to the loss via loss_inputs, the train node -did also perform a training iteration for us. This becomes more evident if we -keep training for a few iterations:

-
-
-
with gp.build(pipeline):
-  for i in range(1000):
-    batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, batch[gt].data, batch[prediction].data)
-
-
-
-
-_images/tutorial_simple_pipeline_21_0.png -
-
-
-

Note

-

The predictions are only included in the batch because we requested them here -to visualize them. To keep the example simple, we request the predictions in -every iteration. In a production setting, however, it is advisable to request -only what is needed for each iteration. This saves a potentially expensive -copy from GPU memory.

-
-
-
-

Predicting on a whole image

-

gunpowder and its pipeline concept can not just be used for training, but -also to perform the final predictions once training is finished. The following -example shows how to assemble a pipeline to take the model we just trained and -apply it on the whole image. The main difficulty in doing that is that the -model was trained for a particular input size. Consequently, the whole image -will have to be chunked into pieces of the correct size, and the network has to -be applied to each chunk in a scanning fashion, creating predictions one chunk -at a time. Those chunks then have to be reassembled into a prediction for the -whole image. This whole procedure is orchestrated by another gunpowder -node: Scan.

-
-
-
# set model into evaluation mode
-model.eval()
-
-predict = gp.torch.Predict(
-  model,
-  inputs = {
-    'input': raw
-  },
-  outputs = {
-    0: prediction
-  })
-
-stack = gp.Stack(1)
-
-# request matching the model input and output sizes
-scan_request = gp.BatchRequest()
-scan_request[raw] = gp.Roi((0, 0), (64, 128))
-scan_request[prediction] = gp.Roi((0, 0), (64, 128))
-
-scan = gp.Scan(scan_request)
-
-pipeline = (
-  source +
-  normalize +
-  stack +
-  predict +
-  scan)
-
-# request for raw and prediction for the whole image
-request = gp.BatchRequest()
-request[raw] = gp.Roi((0, 0), (512, 512))
-request[prediction] = gp.Roi((0, 0), (512, 512))
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-imshow(batch[raw].data, None, batch[prediction].data)
-
-
-
-
-_images/tutorial_simple_pipeline_22_9.png -
-
-

The main difference to the training pipeline used earlier is that there is no -longer a need for data augmentation. We also replaced the torch.Train -node with its equivalent torch.Predict.

-
-

Further Example: Prediction in Large nD Arrays

-

Here, we make a request to Scan for the whole image and the -prediction. This is fine as long as both arrays are small enough to fit into -memory. However, gunpowder was designed to work with arbitrarily large -nD arrays. Therefore, Scan accepts empty requests as well, which -will still result in small scan_request s being performed in a scanning -fashion over the whole input range–the only difference is that Scan -does not keep the individual results and consequently that the batch returned -by Scan will be empty.

-

So how do we get access to the prediction then to store it, for example, in a -zarr container? The answer is to add a node between predict and scan, -through which every batch will pass before it is being discarded. The -ZarrWrite node will, for instance, assemble a zarr container of -all the arrays passing through it.

-

The following example illustrates that:

-
-
-
# prepare the zarr dataset to write to
-f = zarr.open('sample_data.zarr')
-ds = f.create_dataset('prediction', shape=(1, 1, 512, 512))
-ds.attrs['resolution'] = (1, 1)
-ds.attrs['offset'] = (0, 0)
-
-# create a zarr write node to store the predictions
-zarr_write = gp.ZarrWrite(
-  output_filename='sample_data.zarr',
-  dataset_names={
-    prediction: 'prediction'
-  })
-
-pipeline = (
-  source +
-  normalize +
-  stack +
-  predict +
-  zarr_write +
-  scan)
-
-# request an empty batch from scan
-request = gp.BatchRequest()
-
-with gp.build(pipeline):
-  batch = pipeline.request_batch(request)
-
-print(batch)
-imshow(
-  zarr.open('sample_data.zarr')['raw'][:],
-  None,
-  zarr.open('sample_data.zarr')['prediction'][:])
-
-
-
-
-

-
-
-
-_images/tutorial_simple_pipeline_23_14.png -
-
-
-
-
-

What next?

-

gunpowder provides much more nodes to chain together, including a -pre-cache node for easy parallel fetching of batches, -several augmentation nodes, and nodes for -profiling and inspection. -For a complete list see the API reference.

-
-
- - -
- -
-
- - - - -
- -
-

- © Copyright 2020, Jan Funke, Will Patton, Renate Krause, Julia Buhmann, Rodrigo Ceballos Lentini, William Grisaitis, Chris Barnes, Caroline Malin-Mayor, Larissa Heinrich, Philipp Hanslovsky, Sherry Ding, Andrew Champion, Arlo Sheridan, Constantin Pape. - -

-
- Built with Sphinx using a theme provided by Read the Docs. - -
- -
-
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/gunpowder/batch_request.py b/gunpowder/batch_request.py index 3a6e7bbd..326df1c3 100644 --- a/gunpowder/batch_request.py +++ b/gunpowder/batch_request.py @@ -16,9 +16,6 @@ class BatchRequest(ProviderSpec): Inherits from :class:`ProviderSpec`. - See :ref:`sec_requests_batches` for how to use a batch request to obtain a - batch. - Additional Kwargs: random_seed (``int``): diff --git a/gunpowder/jax/nodes/train.py b/gunpowder/jax/nodes/train.py index 199fb63b..4d1f17a3 100644 --- a/gunpowder/jax/nodes/train.py +++ b/gunpowder/jax/nodes/train.py @@ -85,7 +85,9 @@ class Train(GenericTrain): validate_fn (function -> Union[``float``, (``dict``, ``string`` -> ``float``)] , optional): Function to run validation on, which should has the form of + def validate_fn(model, params) + where `model` is the same provided `GenericJaxModel` model and `params` is the parameter of this model, and returns either a ``float`` (one loss) or a dictionary of losses to record in diff --git a/gunpowder/nodes/noise_augment.py b/gunpowder/nodes/noise_augment.py index d5232ca8..15b890a6 100644 --- a/gunpowder/nodes/noise_augment.py +++ b/gunpowder/nodes/noise_augment.py @@ -59,5 +59,5 @@ def process(self, batch, request): raw.data.min() >= -1 and raw.data.max() <= 1 ), "Noise augmentation expects raw values in [-1,1] or [0,1]. Consider using Normalize before." raw.data = skimage.util.random_noise( - raw.data, mode=self.mode, seed=self.seed, clip=self.clip, **self.kwargs + raw.data, mode=self.mode, rng=self.seed, clip=self.clip, **self.kwargs ).astype(raw.data.dtype) diff --git a/gunpowder/nodes/stack.py b/gunpowder/nodes/stack.py index acacac8e..c781aafc 100644 --- a/gunpowder/nodes/stack.py +++ b/gunpowder/nodes/stack.py @@ -41,7 +41,7 @@ def provide(self, request): batch[key] = Array(data, batches[0][key].spec.copy()) # copy points of first batch requested - for key, spec in request.points_specs.items(): + for key, spec in request.graph_specs.items(): batch[key] = batches[0][key] timing.stop() diff --git a/gunpowder/provider_spec.py b/gunpowder/provider_spec.py index 298a5e6b..9b463ab5 100644 --- a/gunpowder/provider_spec.py +++ b/gunpowder/provider_spec.py @@ -64,7 +64,7 @@ class ProviderSpec(Freezable): Contains all graph specs contained in this provider spec. """ - def __init__(self, array_specs=None, graph_specs=None, points_specs=None): + def __init__(self, array_specs=None, graph_specs=None): self.array_specs = {} self.graph_specs = {} self.freeze() @@ -77,17 +77,6 @@ def __init__(self, array_specs=None, graph_specs=None, points_specs=None): if graph_specs is not None: for key, spec in graph_specs.items(): self[key] = spec - if points_specs is not None: - for key, spec in points_specs.items(): - self[key] = spec - - @property - def points_specs(self): - # Alias to graphs - warnings.warn( - "points_specs are depricated. Please use graph_specs", DeprecationWarning - ) - return self.graph_specs def __setitem__(self, key, spec): assert isinstance(key, ArrayKey) or isinstance(key, GraphKey), ( diff --git a/pyproject.toml b/pyproject.toml index c17c6db4..11ab82bc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,6 +8,18 @@ description = "A library to facilitate machine learning on large, multi-dimensio authors = [ {name = "Jan Funke", email = "funkej@hhmi.org"}, {name = "William Patton", email = "pattonw@hhmi.org"}, + {name = "Renate Krause"}, + {name = "Julia Buhmann"}, + {name = "Rodrigo Ceballos Lentini"}, + {name = "William Grisaitis"}, + {name = "Chris Barnes"}, + {name = "Caroline Malin-Mayor"}, + {name = "Larissa Heinrich"}, + {name = "Philipp Hanslovsky"}, + {name = "Sherry Ding"}, + {name = "Andrew Champion"}, + {name = "Arlo Sheridan"}, + {name = "Constantin Pape"}, ] license = {text = "MIT"} readme = "README.md" @@ -38,6 +50,16 @@ dev = [ "pytest-cov", "flake8", ] +docs = [ + "sphinx", + "sphinx_rtd_theme", + "sphinx_togglebutton", + "tomli", + "jupyter_sphinx", + "ipykernel", + "matplotlib", + "torch", +] pytorch = ['torch'] tensorflow = [ # TF doesn't provide <2.0 wheels for py>=3.8 on pypi