vizzuhq__ipyvizzu METASEP

src/ipyvizzu/data/converters/spark/converter.py METASEP
"""
This module provides the `SparkDataFrameConverter` class,
which allows converting a `pyspark` `DataFrame`
into a list of dictionaries representing series.
"""

from types import ModuleType
from typing import List, Tuple

from ipyvizzu.data.converters.defaults import NAN_DIMENSION, NAN_MEASURE
from ipyvizzu.data.converters.df.defaults import MAX_ROWS
from ipyvizzu.data.converters.df.converter import DataFrameConverter
from ipyvizzu.data.infer_type import InferType
from ipyvizzu.data.type_alias import (
    DimensionValue,
    MeasureValue,
    SeriesValues,
)


class SparkDataFrameConverter(DataFrameConverter):
    """
    Converts a `pyspark` `DataFrame` into a list of dictionaries representing series.
    Each dictionary contains information about the series `name`, `values` and `type`.

    Parameters:
        df: The `pyspark` `DataFrame` to convert.
        default_measure_value:
            Default value to use for missing measure values. Defaults to 0.
        default_dimension_value:
            Default value to use for missing dimension values. Defaults to an empty string.
        max_rows: The maximum number of rows to include in the converted series list.
            If the `df` contains more rows,
            a random sample of the given number of rows will be taken.

    Example:
        Get series list from `DataFrame` columns:

            converter = SparkDataFrameConverter(df)
            series_list = converter.get_series_list()
    """

    # pylint: disable=too-few-public-methods

    def __init__(
        self,
        df: "pyspark.sql.DataFrame",  # type: ignore
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
        max_rows: int = MAX_ROWS,
    ) -> None:
        super().__init__(default_measure_value, default_dimension_value, max_rows)
        self._pyspark = self._get_pyspark()
        self._df = self._preprocess_df(df)

    def _get_pyspark(self) -> ModuleType:
        try:
            import pyspark  # pylint: disable=import-outside-toplevel

            return pyspark
        except ImportError as error:
            raise ImportError(
                "pyspark is not available. Please install pyspark to use this feature."
            ) from error

    @staticmethod
    def _get_sampled_df(
        df: "pyspark.sql.DataFrame", fraction: float  # type: ignore
    ) -> "pyspark.sql.DataFrame":  # type: ignore
        return df.sample(withReplacement=False, fraction=fraction, seed=42)

    @staticmethod
    def _get_row_number(df: "pyspark.sql.DataFrame") -> int:  # type: ignore
        return df.count()

    def _get_columns(self) -> List[str]:
        return self._df.columns

    def _convert_to_series_values_and_type(
        self, obj: str
    ) -> Tuple[SeriesValues, InferType]:
        column_name = obj
        column = self._df.select(column_name)
        integer_type = self._pyspark.sql.types.IntegerType
        double_type = self._pyspark.sql.types.DoubleType
        if isinstance(column.schema[column_name].dataType, (integer_type, double_type)):
            return self._convert_to_measure_values(column_name), InferType.MEASURE
        return self._convert_to_dimension_values(column_name), InferType.DIMENSION

    def _convert_to_measure_values(self, obj: str) -> List[MeasureValue]:
        column_name = obj
        when = self._pyspark.sql.functions.when
        col = self._pyspark.sql.functions.col
        df = self._df.withColumn(
            column_name,
            when(col(column_name).isNull(), self._default_measure_value).otherwise(
                col(column_name)
            ),
        )
        df = df.withColumn(column_name, col(column_name).cast("float"))
        return df.select(column_name).rdd.flatMap(lambda x: x).collect()

    def _convert_to_dimension_values(self, obj: str) -> List[DimensionValue]:
        column_name = obj
        when = self._pyspark.sql.functions.when
        col = self._pyspark.sql.functions.col
        df = self._df.withColumn(
            column_name,
            when(col(column_name).isNull(), self._default_dimension_value).otherwise(
                col(column_name)
            ),
        )
        df = df.withColumn(column_name, col(column_name).cast("string"))
        return df.select(column_name).rdd.flatMap(lambda x: x).collect()

src/ipyvizzu/data/converters/spark/__init__.py METASEP
"""
This module provides modules for pyspark converter.
"""

src/ipyvizzu/data/converters/pandas/converter.py METASEP
"""
This module provides the `PandasDataFrameConverter` class,
which allows converting a `pandas` `DataFrame` or `Series`
into a list of dictionaries representing series.
"""

from types import ModuleType
from typing import List, Optional, Tuple, Union

from ipyvizzu.data.converters.defaults import NAN_DIMENSION, NAN_MEASURE
from ipyvizzu.data.converters.df.defaults import MAX_ROWS
from ipyvizzu.data.converters.df.converter import DataFrameConverter
from ipyvizzu.data.infer_type import InferType
from ipyvizzu.data.type_alias import (
    DimensionValue,
    MeasureValue,
    Series,
    SeriesValues,
)


class PandasDataFrameConverter(DataFrameConverter):
    """
    Converts a `pandas` `DataFrame` or `Series` into a list of dictionaries representing series.
    Each dictionary contains information about the series `name`, `values` and `type`.

    Parameters:
        df: The `pandas` `DataFrame` or `Series` to convert.
        default_measure_value:
            Default value to use for missing measure values. Defaults to 0.
        default_dimension_value:
            Default value to use for missing dimension values. Defaults to an empty string.
        max_rows: The maximum number of rows to include in the converted series list.
            If the `df` contains more rows,
            a random sample of the given number of rows will be taken.
        include_index:
            Name for the index column to include as a series.
            If provided, the index column will be added. Defaults to None.

    Example:
        Get series list from `DataFrame` columns:

            converter = PandasDataFrameConverter(df)
            series_list = converter.get_series_list()
    """

    def __init__(
        self,
        df: Union["pandas.DataFrame", "pandas.Series"],  # type: ignore
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
        max_rows: int = MAX_ROWS,
        include_index: Optional[str] = None,
    ) -> None:
        # pylint: disable=too-many-arguments

        super().__init__(default_measure_value, default_dimension_value, max_rows)
        self._pd = self._get_pandas()
        self._df = self._preprocess_df(
            self._pd.DataFrame(df) if isinstance(df, self._pd.Series) else df
        )
        self._include_index = include_index

    def get_series_list(self) -> List[Series]:
        """
        Convert the `DataFrame` columns to a list of dictionaries representing series.

        Returns:
            A list of dictionaries representing series,
            where each dictionary has `name`, `values` and `type` keys.
        """

        series_list = super().get_series_list()
        index_series = self.get_series_from_index()
        return index_series + series_list

    def get_series_from_index(self) -> List[Series]:
        """
        Convert the `DataFrame` index to a dictionary representing a series,
        if `include_index` is provided.

        Returns:
            A dictionary representing the index series with `name`, `values` and `type` keys.
            Returns `None` if `include_index` is not provided.
        """

        if not self._include_index or self._df.index.empty:
            return []
        df = self._pd.DataFrame({self._include_index: self._df.index})
        index_series_converter = PandasDataFrameConverter(
            df, self._default_measure_value, self._default_dimension_value
        )
        return index_series_converter.get_series_list()

    def _get_pandas(self) -> ModuleType:
        try:
            import pandas as pd  # pylint: disable=import-outside-toplevel

            return pd
        except ImportError as error:
            raise ImportError(
                "pandas is not available. Please install pandas to use this feature."
            ) from error

    @staticmethod
    def _get_sampled_df(
        df: "pandas.DataFrame", fraction: float  # type: ignore
    ) -> "pandas.DataFrame":  # type: ignore
        return df.sample(withReplacement=False, fraction=fraction, seed=42)

    @staticmethod
    def _get_row_number(df: "pandas.DataFrame") -> int:  # type: ignore
        return len(df)

    def _get_columns(self) -> List[str]:
        return self._df.columns

    def _convert_to_series_values_and_type(
        self, obj: str  # type: ignore
    ) -> Tuple[SeriesValues, InferType]:
        column_name = obj
        column = self._df[column_name]
        if self._pd.api.types.is_numeric_dtype(column.dtype):
            return self._convert_to_measure_values(column), InferType.MEASURE
        return self._convert_to_dimension_values(column), InferType.DIMENSION

    def _convert_to_measure_values(
        self, obj: "pandas.DataFrame"  # type: ignore
    ) -> List[MeasureValue]:
        column = obj
        return column.fillna(self._default_measure_value).astype(float).values.tolist()

    def _convert_to_dimension_values(
        self, obj: "pandas.DataFrame"  # type: ignore
    ) -> List[DimensionValue]:
        column = obj
        return column.fillna(self._default_dimension_value).astype(str).values.tolist()

src/ipyvizzu/data/converters/pandas/__init__.py METASEP
"""
This module provides modules for pandas converter.
"""

src/ipyvizzu/data/converters/numpy/type_alias.py METASEP
"""
This module provides typing aliases for numpy converter.
"""

from typing import Dict, TypeVar, Union


Index = int
"""Represents the index of a column."""

Name = str
"""Represents the name of a column."""

DType = type
"""Represents the dtype of a column."""

ColumnName = Union[Name, Dict[Index, Name]]
"""
Represents a column name. It is a dictionary of Index:Name pairs
or for single-dimensional arrays, it can be just a Name.
"""

ColumnDtype = Union[DType, Dict[Index, DType]]
"""
Represents a column dtype. It is a dictionary of Index:DType pairs
or for single-dimensional arrays, it can be just a DType.
"""

ColumnConfig = TypeVar("ColumnConfig", Name, DType)
"""
Represents a column config. It can be Name or DType.
"""

src/ipyvizzu/data/converters/numpy/converter.py METASEP
"""
This module provides the `NumpyArrayConverter` class,
which allows converting a `numpy` `array`
into a list of dictionaries representing series.
"""

from types import ModuleType
from typing import Dict, List, Optional, Tuple, Union

from ipyvizzu.data.converters.defaults import NAN_DIMENSION, NAN_MEASURE
from ipyvizzu.data.converters.converter import ToSeriesListConverter
from ipyvizzu.data.converters.numpy.type_alias import (
    ColumnConfig,
    ColumnDtype,
    ColumnName,
    DType,
    Index,
    Name,
)
from ipyvizzu.data.infer_type import InferType
from ipyvizzu.data.type_alias import (
    DimensionValue,
    MeasureValue,
    Series,
    SeriesValues,
)


class NumpyArrayConverter(ToSeriesListConverter):
    """
    Converts a `numpy` `array` into a list of dictionaries representing series.
    Each dictionary contains information about the series `name`, `values` and `type`.

    Parameters:
        np_array: The `numpy` `array` to convert.
        column_name:
            The name of a column. By default, uses column indices. Can be set with an
            Index:Name pair or, for single-dimensional arrays, with just the Name.
        column_dtype:
            The dtype of a column. By default, uses the np_array's dtype. Can be set
            with an Index:DType pair or, for single-dimensional arrays, with just the DType.
        default_measure_value:
            Default value to use for missing measure values. Defaults to 0.
        default_dimension_value:
            Default value to use for missing dimension values. Defaults to an empty string.

    Example:
        Get series list from `numpy` `array`:

            converter = NumpyArrayConverter(np_array)
            series_list = converter.get_series_list()
    """

    # pylint: disable=too-few-public-methods

    def __init__(
        self,
        np_array: "numpy.array",  # type: ignore
        column_name: Optional[ColumnName] = None,
        column_dtype: Optional[ColumnDtype] = None,
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
    ) -> None:
        # pylint: disable=too-many-arguments

        super().__init__(default_measure_value, default_dimension_value)
        self._np = self._get_numpy()
        self._np_array = np_array
        self._column_name: Dict[Index, Name] = self._get_columns_config(column_name)
        self._column_dtype: Dict[Index, DType] = self._get_columns_config(column_dtype)

    def get_series_list(self) -> List[Series]:
        """
        Convert the `numpy` `array` to a list of dictionaries representing series.

        Returns:
            A list of dictionaries representing series,
            where each dictionary has `name`, `values` and `type` keys.
        """

        if self._np_array.ndim == 0:
            return []
        if self._np_array.ndim == 1:
            return self._get_series_list_from_array1dim()
        if self._np_array.ndim == 2:
            return self._get_series_list_from_array2dim()
        raise ValueError("arrays larger than 2D are not supported")

    def _get_series_list_from_array1dim(self) -> List[Series]:
        i = 0
        name = self._column_name.get(i, i)
        values, infer_type = self._convert_to_series_values_and_type(
            (i, self._np_array)
        )
        return [self._convert_to_series(name, values, infer_type)]

    def _get_series_list_from_array2dim(self) -> List[Series]:
        series_list = []
        for i in range(self._np_array.shape[1]):
            name = self._column_name.get(i, i)
            values, infer_type = self._convert_to_series_values_and_type(
                (i, self._np_array[:, i])
            )
            series_list.append(self._convert_to_series(name, values, infer_type))
        return series_list

    def _get_numpy(self) -> ModuleType:
        try:
            import numpy as np  # pylint: disable=import-outside-toplevel

            return np
        except ImportError as error:
            raise ImportError(
                "numpy is not available. Please install numpy to use this feature."
            ) from error

    def _get_columns_config(
        self,
        config: Optional[Union[ColumnConfig, Dict[Index, ColumnConfig]]],
    ) -> Dict[Index, ColumnConfig]:
        if config is None:
            return {}
        if not isinstance(config, dict):
            if not self._np_array.ndim == 1:
                raise ValueError("non dict value can only be used for a 1D array")
            return {0: config}
        return config

    def _convert_to_series_values_and_type(
        self, obj: Tuple[int, "numpy.array"]  # type: ignore
    ) -> Tuple[SeriesValues, InferType]:
        column = obj
        i = column[0]
        array = column[1]
        dtype = self._column_dtype.get(i, self._np_array.dtype)
        if self._np.issubdtype(dtype, self._np.number):
            return self._convert_to_measure_values(array), InferType.MEASURE
        return self._convert_to_dimension_values(array), InferType.DIMENSION

    def _convert_to_measure_values(
        self, obj: "numpy.array"  # type: ignore
    ) -> List[MeasureValue]:
        array = obj
        array_float = array.astype(float)
        return self._np.nan_to_num(
            array_float, nan=self._default_measure_value
        ).tolist()

    def _convert_to_dimension_values(
        self, obj: "numpy.array"  # type: ignore
    ) -> List[DimensionValue]:
        array = obj
        array_str = array.astype(str)
        replace_nan = "nan"
        mask = array_str == replace_nan
        array_str[mask] = self._default_dimension_value
        return array_str.tolist()

src/ipyvizzu/data/converters/numpy/__init__.py METASEP
"""
This module provides modules for numpy converter.
"""

src/ipyvizzu/data/converters/df/type_alias.py METASEP
"""
This module provides typing aliases for data frame converter.
"""

from typing import Any, TypeVar


DataFrame = TypeVar("DataFrame", Any, Any)
"""
Represents a data frame.
"""

src/ipyvizzu/data/converters/df/defaults.py METASEP
"""
This module provides default values for data frame converters.
"""

MAX_ROWS: int = 10000
"""Default maximum number of rows."""

src/ipyvizzu/data/converters/df/converter.py METASEP
"""
This module provides the `DataFrameConverter` abstract class.
"""

from abc import abstractmethod
from typing import List

from ipyvizzu.data.converters.converter import ToSeriesListConverter
from ipyvizzu.data.converters.df.type_alias import DataFrame
from ipyvizzu.data.type_alias import (
    DimensionValue,
    MeasureValue,
    Series,
)


class DataFrameConverter(ToSeriesListConverter):
    """
    Converts data frame into a list of dictionaries representing series.
    Each dictionary contains information about the series `name`, `values` and `type`.
    """

    # pylint: disable=too-few-public-methods

    def __init__(
        self,
        default_measure_value: MeasureValue,
        default_dimension_value: DimensionValue,
        max_rows: int,
    ) -> None:
        super().__init__(default_measure_value, default_dimension_value)
        self._max_rows = max_rows

    def get_series_list(self) -> List[Series]:
        """
        Convert the `DataFrame` columns to a list of dictionaries representing series.

        Returns:
            A list of dictionaries representing series,
            where each dictionary has `name`, `values` and `type` keys.
        """

        series_list = []
        for name in self._get_columns():
            series_list.append(self._get_series_from_column(name))
        return series_list

    def _get_series_from_column(self, column_name: str) -> Series:
        values, infer_type = self._convert_to_series_values_and_type(column_name)
        return self._convert_to_series(column_name, values, infer_type)

    def _preprocess_df(self, df: DataFrame) -> DataFrame:
        rows = self._get_row_number(df)
        if rows > self._max_rows:
            return self._get_sampled_df(df, min(self._max_rows / rows, 1.0))
        return df

    @staticmethod
    @abstractmethod
    def _get_row_number(df: DataFrame) -> int:
        """
        Return row number of a data frame.
        """

    @staticmethod
    @abstractmethod
    def _get_sampled_df(df: DataFrame, fraction: float) -> DataFrame:
        """
        Return a sampled data frame by fraction.
        """

    @abstractmethod
    def _get_columns(self) -> List[str]:
        """
        Return column names of the data frame.
        """

src/ipyvizzu/data/converters/df/__init__.py METASEP
"""
This module provides modules for data frame converter.
"""

tools/docs/overrides/mike/redirect.html METASEP
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta property="og:type" content="website" />
    <meta property="og:type" content="website" />
    <meta property="og:site_name" content="ipyvizzu" />
    <meta property="og:title" content="ipyvizzu" />
    <meta
      property="og:description"
      content="ipyvizzu - Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax"
    />
    <meta property="og:url" content="https://ipyvizzu.vizzuhq.com" />
    <meta
      property="og:image"
      content="https://vizzuhq.com/images/logo/vizzu-twitter.png"
    />
    <meta property="og:image:type" content="image/png" />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="630" />
    <meta
      property="og:video"
      content="https://vizzuhq.com/images/logo/social-image-big.mp4"
    />
    <meta name="twitter:title" content="ipyvizzu" />
    <meta
      name="twitter:description"
      content="ipyvizzu - Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax"
    />
    <meta name="twitter:card" content="summary_large_image" />
    <meta name="twitter:site" content="@VizzuHQ" />
    <meta name="twitter:creator" content="@VizzuHQ" />
    <meta
      name="twitter:image"
      content="https://vizzuhq.com/images/logo/vizzu-twitter.png"
    />
    <title>Redirecting</title>
    <noscript>
      <meta http-equiv="refresh" content="1; url={{href}}" />
    </noscript>
    <script>
      window.location.replace(
        "{{href}}" + window.location.search + window.location.hash,
      );
    </script>
  </head>
  <body>
    Redirecting to <a href="{{href}}">{{href}}</a>...
  </body>
</html>

docs/assets/javascripts/iframe/click.js METASEP
const collection = document.getElementsByClassName("showcase");
if (collection) {
  collection[0].addEventListener("click", () => {
    const iframe = document.getElementById("showcase");
    iframe.src = iframe.src; // eslint-disable-line no-self-assign
  });
}

docs/assets/javascripts/iframe/autoscale.js METASEP
const parent = window.frameElement;
if (parent) {
  window.addEventListener("resize", () => {
    const zoomElement = document.getElementById("zoom");
    let availableWidth = parent.clientWidth;
    if (parent.clientWidth / parent.clientHeight > 1280 / 720) {
      availableWidth = (1280 * parent.clientHeight) / 720;
    }
    const scale = availableWidth / 1280;
    const translateY = (100 * (scale - 1)) / 2;
    const translateX = (100 * (parent.clientWidth / 1280 - 1)) / 2;
    const transform = `translate(${translateX}%, ${translateY}%) scale(${
      scale - 0.01
    })`;
    zoomElement.style.transform = transform;
    zoomElement.style.height = `${720 * scale}px`;
    if (window.autoAdjustHeight) {
      window.autoAdjustHeight();
    }
  });
}

docs/assets/javascripts/iframe/autoheight.js METASEP
const iframe = document.getElementById("showcase");

iframe.addEventListener("load", function () {
  const childBody = iframe.contentWindow.document.body;

  function resizeIframe() {
    const childHeight = childBody.scrollHeight;
    iframe.style.height = childHeight + 50 + "px"; // todo: get showcase explorers size correctly
  }

  resizeIframe();

  iframe.contentWindow.addEventListener("resize", resizeIframe);
});

docs/assets/javascripts/analytics/head.js METASEP
const plausibleBasic = document.createElement("script");
plausibleBasic.setAttribute("defer", "");
plausibleBasic.setAttribute("data-domain", "ipyvizzu.vizzuhq.com");
plausibleBasic.src = "https://plausible.io/js/script.outbound-links.js";

const plausibleOutboundLinkTracking = document.createElement("script");
plausibleOutboundLinkTracking.textContent =
  "window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }";

const documentHeadElement = document.getElementsByTagName("head")[0];
documentHeadElement.appendChild(plausibleBasic);
documentHeadElement.appendChild(plausibleOutboundLinkTracking);

src/ipyvizzu/data/converters/defaults.py METASEP
"""
This module provides default values for converters.
"""

from ipyvizzu.data.type_alias import DimensionValue, MeasureValue


NAN_DIMENSION: DimensionValue = ""
"""Default dimension value to replace nan values."""

NAN_MEASURE: MeasureValue = 0
"""Default measure value to replace nan values."""

src/ipyvizzu/data/converters/converter.py METASEP
"""
This module provides the `ToSeriesListConverter` abstract class.
"""

from abc import ABC, abstractmethod
from typing import Any, List, Tuple, Union

from ipyvizzu.data.infer_type import InferType
from ipyvizzu.data.type_alias import (
    DimensionValue,
    MeasureValue,
    Series,
    SeriesValues,
)


class ToSeriesListConverter(ABC):
    """
    Converts data into a list of dictionaries representing series.
    Each dictionary contains information about the series `name`, `values` and `type`.
    """

    # pylint: disable=too-few-public-methods

    def __init__(
        self,
        default_measure_value: MeasureValue,
        default_dimension_value: DimensionValue,
    ) -> None:
        self._default_measure_value = default_measure_value
        self._default_dimension_value = default_dimension_value

    @abstractmethod
    def get_series_list(self) -> List[Series]:
        """
        Convert data to a list of dictionaries representing series.

        Returns:
            A list of dictionaries representing series,
            where each dictionary has `name`, `values` and `type` keys.
        """

    @abstractmethod
    def _convert_to_series_values_and_type(
        self, obj: Any
    ) -> Tuple[SeriesValues, InferType]:
        """
        Convert object to SeriesValues and InferType.
        """

    @abstractmethod
    def _convert_to_measure_values(self, obj: Any) -> List[MeasureValue]:
        """
        Convert object to a list of MeasureValue.
        """

    @abstractmethod
    def _convert_to_dimension_values(self, obj: Any) -> List[DimensionValue]:
        """
        Convert object to a list of DimensionValue.
        """

    def _convert_to_series(
        self, name: Union[str, int], values: SeriesValues, infer_type: InferType
    ) -> Series:
        return {
            "name": str(name),
            "values": values,
            "type": infer_type.value,
        }

src/ipyvizzu/data/converters/__init__.py METASEP
"""
This module contains converter classes that offer a user-friendly interface for data conversion,
enabling users to effortlessly transform various data formats into a standardized representation
of series compatible with `ipyvizzu`.
"""

tools/docs/style/get_style_reference.mjs METASEP
const div = document.createElement("div");
const chart = new Vizzu(div).initializing; // eslint-disable-line no-undef
const style = chart.then((chart) => {
  return chart.getComputedStyle();
});
style.then((style) => {
  const para = document.createElement("p");
  const node = document.createTextNode(JSON.stringify(style));
  para.appendChild(node);
  document.getElementById("style").appendChild(para);
});

tools/docs/style/gen_style_reference.mjs METASEP
import fs from "fs/promises";
import puppeteer from "puppeteer";
import path from "path";
import { fileURLToPath } from "url";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const repoPath = __dirname + "/../../..";
const mkdocsPath = `${repoPath}/tools/docs`;
const genPath = `${mkdocsPath}/style`;
const jsAssetsPath = "../../assets/javascripts";

function appendContent(obj, level) {
  const tab = "&emsp;";
  let content = "";
  if (level) {
    content += `<div class="collapsible-style-content">`;
  }
  for (const [key, value] of Object.entries(obj)) {
    if (typeof value === "object") {
      content += `<p class="collapsible-style"><button type="button">${tab.repeat(
        level,
      )}+&nbsp;${key}</button></p>`;
      content += appendContent(value, level + 1);
    } else {
      content += `<p class="not-collapsible-style">${tab.repeat(
        level,
      )}${key}: <code>${value}</code></p>`;
    }
  }
  if (level) {
    content += `</div>`;
  }
  return content;
}

const Vizzu = process.argv[2];

const browserLaunched = puppeteer.launch({ headless: "new" });

const pageCreated = browserLaunched.then((browser) => {
  return browser.newPage();
});

const getStyleScriptLoaded = fs.readFile(`${genPath}/get_style_reference.mjs`, {
  encoding: "utf8",
});

const pageModified = Promise.all([pageCreated, getStyleScriptLoaded]).then(
  (results) => {
    const page = results[0];
    const getStyleScript = results[1];
    return page.goto(`data:text/html,<script id="style" type="module">
import Vizzu from "${Vizzu}";
${getStyleScript}
</script>`);
  },
);

const selectorLoaded = Promise.all([pageCreated, pageModified]).then(
  (results) => {
    const page = results[0];
    return page.waitForSelector("p");
  },
);

const element = Promise.all([pageCreated, selectorLoaded]).then((results) => {
  const page = results[0];
  return page.$("p");
});

const elementValue = Promise.all([browserLaunched, pageCreated, element]).then(
  (results) => {
    const page = results[1];
    const element = results[2];
    return page.evaluate((el) => el.textContent, element);
  },
);

Promise.all([browserLaunched, elementValue]).then((results) => {
  const browser = results[0];
  browser.close();
});

elementValue.then((elementValue) => {
  let content = "";
  content += `<p id="allbtn-style" class="allbtn-style"><button type="button">+&nbsp;expand all</button></p>`;
  content += appendContent(JSON.parse(elementValue), 0);
  content += `<script src="${jsAssetsPath}/style_ref_allbtn.js"></script>`;
  content += `<script src="${jsAssetsPath}/style_ref_clickevent.js"></script>`;
  console.log(content);
});

tools/docs/overrides/main.html METASEP
{% extends "base.html" %} {% block extrahead %}
<script src="{{ base_url }}/assets/javascripts/analytics/head.js"></script>
<meta property="og:type" content="website" />
<meta property="og:site_name" content="ipyvizzu" />
<meta property="og:title" content="ipyvizzu" />
<meta
  property="og:description"
  content="ipyvizzu - Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax"
/>
<meta property="og:url" content="{{ page.canonical_url }}" />
<meta
  property="og:image"
  content="https://vizzuhq.com/images/logo/vizzu-twitter.png"
/>
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta
  property="og:video"
  content="https://vizzuhq.com/images/logo/social-image-big.mp4"
/>
<meta name="twitter:title" content="ipyvizzu" />
<meta
  name="twitter:description"
  content="ipyvizzu - Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax"
/>
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@VizzuHQ" />
<meta name="twitter:creator" content="@VizzuHQ" />
<meta
  name="twitter:image"
  content="https://vizzuhq.com/images/logo/vizzu-twitter.png"
/>
{% endblock %} {% block outdated %} You're not viewing the latest version.
<a href="{{ '../' ~ base_url }}">
  <strong>Click here to go to latest.</strong>
</a>
{% endblock %} {% block content %} {% if page.meta.data_url %}
<a
  href="{{ page.meta.data_url }}"
  title="Download data"
  class="md-content__button md-icon"
>
  {% include ".icons/material/database.svg" %}
</a>
{% endif %} {% if page.meta.csv_url %}
<a
  href="{{ page.meta.csv_url }}"
  title="Download data"
  class="md-content__button md-icon"
>
  {% include ".icons/fontawesome/solid/file-csv.svg" %}
</a>
{% endif %}{{ super() }} {% endblock content %}

tools/docs/examples/mjs2md.mjs METASEP
class PresetsMock {
  constructor() {
    return new Proxy(this, {
      get: (target, prop) => {
        return function (obj) {
          return `Config.${prop}(${JSON.stringify(obj, null, 2)})`;
        };
      },
    });
  }
}

class VizzuMock {
  constructor(title, description, data, assetsPath, dataFileName, dataName) {
    this.description = "";
    if (description) {
      this.description = description;
    }
    this.data = data;
    if (dataName !== "data") {
      dataFileName = dataFileName + "_" + dataName;
    }

    this.code = `---
csv_url: ${assetsPath}/assets/data/${dataFileName}.csv
---

# ${title}

<div id="example_01"></div>

??? info "Info - How to setup Chart"
    \`\`\`python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config, Style

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/${dataFileName}.csv",
        dtype={"Year": str, "Timeseries": str},
    )
    data = Data()
    data.add_df(df)

    chart = Chart()
    chart.animate(data)
    \`\`\`

${this.description}

\`\`\`python
`;

    this.end = `
\`\`\`

<script src="./main.js"></script>
`;
  }

  animate(chart, animOptions) {
    const params = [];

    if (chart.data && chart.data.filter) {
      if (JSON.stringify(chart.data) !== JSON.stringify(this.data)) {
        const fnCode = chart.data.filter
          .toString()
          .replace(/\s*record\s*=>\s*/, "");
        params.push(`data.filter("""\n${fnCode.replace(/^\s*/gm, "")}\n""")`);
      }
    }
    if (chart.config) {
      if (
        typeof chart.config === "string" &&
        chart.config.startsWith("Config.")
      ) {
        params.push(chart.config);
      } else {
        params.push("Config(" + JSON.stringify(chart.config, null, 2) + ")");
      }
    }
    if (chart.style) {
      params.push("Style(" + JSON.stringify(chart.style, null, 2) + ")");
    }
    if (animOptions) {
      if (typeof animOptions === "object") {
        for (const key in animOptions) {
          params.push(`${key} = ${JSON.stringify(animOptions[key])}`);
        }
      } else {
        params.push(`duration = "${animOptions}"`);
      }
    }

    const args = params.join(",\n");
    const callCode = `chart.animate(\n${args}`;
    const fullCode = callCode.replace(/\n/g, "\n  ") + "\n)\n\n";
    this.code += fullCode;
  }

  feature(name, enabled) {
    this.code += `chart.feature("${name}", ${enabled})\n\n`;
  }

  on(eventName, handler) {
    const entire = handler.toString();
    const body = entire.slice(entire.indexOf("{") + 1, entire.lastIndexOf("}"));
    this.code += `method = """${body}"""\n`;
    this.code += `handler = chart.on("${eventName}", method)\n\n`;
  }

  static get presets() {
    return new PresetsMock();
  }

  getCode() {
    return (
      this.code
        .replace(/\bnull\b/g, "None")
        .replace(/\btrue\b/g, "True")
        .replace(/\bfalse\b/g, "False") + this.end
    );
  }
}

const inputFileName = process.argv[2];
const dataFilePath = process.argv[3];
const assetsPath = process.argv[4];
const dataFileName = process.argv[5];
const dataName = process.argv[6];
let title = process.argv[7];
const inputFileLoaded = import(inputFileName);
const dataFileLoaded = import(dataFilePath + "/" + dataFileName + ".mjs");
Promise.all([inputFileLoaded, dataFileLoaded]).then((results) => {
  const module = results[0];
  const description = module.description;
  if (module.title) {
    title = module.title;
  }
  const data = results[1][dataName];
  const chart = new VizzuMock(
    title,
    description,
    data,
    assetsPath,
    dataFileName,
    dataName,
  );
  for (const testStep of module.default) {
    testStep(chart);
  }
  console.log(chart.getCode());
});

tools/docs/examples/mjs2js.mjs METASEP
const inputFileName = process.argv[2];
const assetsPath = process.argv[3];
const dataFileName = process.argv[4];
const dataName = process.argv[5];

import(inputFileName).then((module) => {
  const test = `
const dataLoaded = import("${assetsPath}/assets/data/${dataFileName}.js");
const mdChartLoaded = import("${assetsPath}/assets/javascripts/mdchart.js");
  
Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const ${dataName} = results[0].${dataName};
  const MdChart = results[1].default;
  const mdchart = new MdChart(${dataName}, "./vizzu.js", "example");

  mdchart.create([
    {
      anims: [
        ${module.default}
      ]
    }
  ]);
});
`;
  console.log(test);
});

tools/docs/examples/mjs2csv.mjs METASEP
class Js2csv {
  constructor(data) {
    this.data = data;
  }

  getHeaderLine() {
    const header = [];
    for (const series in this.data.series) {
      header.push(this.data.series[series].name);
    }
    return header.join(",") + "\n";
  }

  getDataLine(i) {
    const line = [];
    const record = {};
    for (const j in this.data.series) {
      record[this.data.series[j].name] = this.data.series[j].values[i];
      line.push(this.data.series[j].values[i]);
    }
    if (this.data.filter) {
      if (!this.data.filter(record)) {
        return "";
      }
    }
    return line.join(",") + "\n";
  }

  getRecordLine(i) {
    const line = this.data.records[i];
    const record = {};
    for (const j in this.data.series) {
      record[this.data.series[j].name] = this.data.records[i][j];
    }
    if (this.data.filter) {
      if (!this.data.filter(record)) {
        return "";
      }
    }
    return line.join(",") + "\n";
  }

  convert() {
    let csv = "";
    csv += this.getHeaderLine();
    if (this.data.series[0].values) {
      for (let i = 0; i < this.data.series[0].values.length; i++) {
        csv += this.getDataLine(i);
      }
    } else {
      for (let i = 0; i < this.data.records.length; i++) {
        csv += this.getRecordLine(i);
      }
    }
    return csv;
  }
}

const inputFilename = process.argv[2];
const dataName = process.argv[3];

import(inputFilename).then((module) => {
  const js2csv = new Js2csv(module[dataName]);
  console.log(js2csv.convert());
});

src/ipyvizzu/templates/ipyvizzu.js METASEP
class IpyVizzu {
  static version = "__version__";
  static analytics = undefined;
  static inhibitScroll = false;

  constructor() {
    document.addEventListener(
      "wheel",
      (evt) => {
        IpyVizzu.inhibitScroll = true;
      },
      true,
    );
    document.addEventListener(
      "keydown",
      (evt) => {
        IpyVizzu.inhibitScroll = true;
      },
      true,
    );
    document.addEventListener(
      "touchstart",
      (evt) => {
        IpyVizzu.inhibitScroll = true;
      },
      true,
    );

    this.elements = {};
    this.charts = {};
    this.controls = {};

    this.storage = {};
    this.displays = {};

    this.events = {};
    this.loaded = {};
    this.libs = {};
  }

  static clearInhibitScroll(element) {
    IpyVizzu.inhibitScroll = false;
  }

  createChart(element, chartId, vizzulib, divWidth, divHeight) {
    this.elements[chartId] = document.createElement("div");
    this.elements[
      chartId
    ].style.cssText = `width: ${divWidth}; height: ${divHeight};`;
    this.loaded[chartId] = import(vizzulib);
    this.charts[chartId] = this.loaded[chartId].then((Vizzu) => {
      this.libs[chartId] = Vizzu.default;
      const VizzuConstructor = Vizzu.default;
      return new VizzuConstructor(this.elements[chartId]).initializing;
    });
    this._moveHere(chartId, element);
  }

  animate(
    element,
    chartId,
    animId,
    displayTarget,
    scrollEnabled,
    getChartTarget,
    chartAnimOpts,
  ) {
    if (displayTarget === "end") this._moveHere(chartId, element);
    this.controls[chartId] = this.charts[chartId];
    this.charts[chartId] = this.charts[chartId].then((chart) => {
      if (displayTarget === "actual") this._moveHere(chartId, element);
      this._scroll(chartId, scrollEnabled);
      let chartTarget = getChartTarget(this.libs[chartId]);
      if (typeof chartTarget === "string") {
        chartTarget = this.storage[chartTarget];
      } else if (Array.isArray(chartTarget)) {
        for (let i = 0; i < chartTarget.length; i++) {
          const target = chartTarget[i].target;
          if (typeof target === "string") {
            chartTarget[i].target = this.storage[target];
          }
        }
      }
      chart = chart.animate(chartTarget, chartAnimOpts);
      this.controls[animId] = chart;
      return chart;
    });
  }

  store(element, chartId, id) {
    this.charts[chartId] = this.charts[chartId].then((chart) => {
      this.storage[id] = chart.store();
      return chart;
    });
  }

  feature(element, chartId, name, enabled) {
    this.charts[chartId] = this.charts[chartId].then((chart) => {
      chart.feature(name, enabled);
      return chart;
    });
  }

  setEvent(element, chartId, id, event, handler) {
    this.charts[chartId] = this.charts[chartId].then((chart) => {
      this.events[id] = handler;
      chart.on(event, this.events[id]);
      return chart;
    });
  }

  clearEvent(element, chartId, id, event) {
    this.charts[chartId] = this.charts[chartId].then((chart) => {
      chart.off(event, this.events[id]);
      return chart;
    });
  }

  log(element, chartId, chartProperty) {
    this.charts[chartId] = this.charts[chartId].then((chart) => {
      console.log(chart[chartProperty]);
      return chart;
    });
  }

  control(element, method, prevId, lastId, ...params) {
    this.controls[prevId].then(() => {
      this.controls[lastId].activated.then((control) => {
        if (method === "seek") {
          const value = params[0];
          control[method](value);
          return;
        }
        if (method === "store") {
          const id = params[0];
          this.storage[id] = control[method]();
          return;
        }
        control[method]();
      });
    });
  }

  _moveHere(chartId, element) {
    element.append(this.elements[chartId]);
  }

  _scroll(chartId, enabled) {
    if (!IpyVizzu.inhibitScroll && enabled) {
      this.elements[chartId].scrollIntoView({
        behavior: "auto",
        block: "center",
      });
    }
  }

  static _hide(element) {
    document.getElementById(
      element.selector.substring(1),
    ).parentNode.style.display = "none";
  }

  static _display(prevElement, element) {
    if (prevElement.parentNode) {
      prevElement.parentNode.style.display = "none";
    }
    document.getElementById(
      element.selector.substring(1),
    ).parentNode.style.display = "flex";
    document.getElementById(
      element.selector.substring(1),
    ).parentNode.style.margin = "auto";
  }

  static changeAnalyticsTo(analytics) {
    if (IpyVizzu.analytics !== analytics) {
      console.log("ipyvizzu gather usage stats:", analytics);
      IpyVizzu.analytics = analytics;
    }
    if (analytics) {
      IpyVizzu._addHeadScript();
    } else {
      IpyVizzu._removeScript("ipyvizzu-analytics-head");
    }
  }

  static _addHeadScript() {
    const scriptId = "ipyvizzu-analytics-head";
    if (!IpyVizzu._isScriptAppended(scriptId)) {
      const script = document.createElement("script");
      script.defer = true;
      script.src = "https://plausible.io/js/script.local.js";
      script.dataset.domain = "usage.ipyvizzu.com";
      script.id = scriptId;
      document.getElementsByTagName("head")[0].appendChild(script);
    }
  }

  static _isScriptAppended(id) {
    return document.querySelector(`script[id="${id}"]`) !== null;
  }

  static _removeScript(id) {
    const script = document.getElementById(id);
    if (script) script.remove();
  }
}

if (IpyVizzu.version !== window.IpyVizzu?.version) {
  window.IpyVizzu = IpyVizzu;
  console.log(`ipyvizzu ${IpyVizzu.version}`);
  window.ipyvizzu = new window.IpyVizzu();
}

docs/showcases/titanic/titanic.csv METASEP
Count,PassengerId,Survived,Pclass,Name,Sex,Age,SibSp,Parch,Ticket,Fare,Cabin,Embarked
1,1,Died,3,"Braund, Mr. Owen Harris",male,22,1,0,A/5 21171,7.25,,S
1,2,Survived,1,"Cumings, Mrs. John Bradley (Florence Briggs Thayer)",female,38,1,0,PC 17599,71.2833,C85,C
1,3,Survived,3,"Heikkinen, Miss. Laina",female,26,0,0,STON/O2. 3101282,7.925,,S
1,4,Survived,1,"Futrelle, Mrs. Jacques Heath (Lily May Peel)",female,35,1,0,113803,53.1,C123,S
1,5,Died,3,"Allen, Mr. William Henry",male,35,0,0,373450,8.05,,S
1,6,Died,3,"Moran, Mr. James",male,,0,0,330877,8.4583,,Q
1,7,Died,1,"McCarthy, Mr. Timothy J",male,54,0,0,17463,51.8625,E46,S
1,8,Died,3,"Palsson, Master. Gosta Leonard",male,2,3,1,349909,21.075,,S
1,9,Survived,3,"Johnson, Mrs. Oscar W (Elisabeth Vilhelmina Berg)",female,27,0,2,347742,11.1333,,S
1,10,Survived,2,"Nasser, Mrs. Nicholas (Adele Achem)",female,14,1,0,237736,30.0708,,C
1,11,Survived,3,"Sandstrom, Miss. Marguerite Rut",female,4,1,1,PP 9549,16.7,G6,S
1,12,Survived,1,"Bonnell, Miss. Elizabeth",female,58,0,0,113783,26.55,C103,S
1,13,Died,3,"Saundercock, Mr. William Henry",male,20,0,0,A/5. 2151,8.05,,S
1,14,Died,3,"Andersson, Mr. Anders Johan",male,39,1,5,347082,31.275,,S
1,15,Died,3,"Vestrom, Miss. Hulda Amanda Adolfina",female,14,0,0,350406,7.8542,,S
1,16,Survived,2,"Hewlett, Mrs. (Mary D Kingcome) ",female,55,0,0,248706,16,,S
1,17,Died,3,"Rice, Master. Eugene",male,2,4,1,382652,29.125,,Q
1,18,Survived,2,"Williams, Mr. Charles Eugene",male,,0,0,244373,13,,S
1,19,Died,3,"Vander Planke, Mrs. Julius (Emelia Maria Vandemoortele)",female,31,1,0,345763,18,,S
1,20,Survived,3,"Masselmani, Mrs. Fatima",female,,0,0,2649,7.225,,C
1,21,Died,2,"Fynney, Mr. Joseph J",male,35,0,0,239865,26,,S
1,22,Survived,2,"Beesley, Mr. Lawrence",male,34,0,0,248698,13,D56,S
1,23,Survived,3,"McGowan, Miss. Anna ""Annie""",female,15,0,0,330923,8.0292,,Q
1,24,Survived,1,"Sloper, Mr. William Thompson",male,28,0,0,113788,35.5,A6,S
1,25,Died,3,"Palsson, Miss. Torborg Danira",female,8,3,1,349909,21.075,,S
1,26,Survived,3,"Asplund, Mrs. Carl Oscar (Selma Augusta Emilia Johansson)",female,38,1,5,347077,31.3875,,S
1,27,Died,3,"Emir, Mr. Farred Chehab",male,,0,0,2631,7.225,,C
1,28,Died,1,"Fortune, Mr. Charles Alexander",male,19,3,2,19950,263,C23 C25 C27,S
1,29,Survived,3,"O'Dwyer, Miss. Ellen ""Nellie""",female,,0,0,330959,7.8792,,Q
1,30,Died,3,"Todoroff, Mr. Lalio",male,,0,0,349216,7.8958,,S
1,31,Died,1,"Uruchurtu, Don. Manuel E",male,40,0,0,PC 17601,27.7208,,C
1,32,Survived,1,"Spencer, Mrs. William Augustus (Marie Eugenie)",female,,1,0,PC 17569,146.5208,B78,C
1,33,Survived,3,"Glynn, Miss. Mary Agatha",female,,0,0,335677,7.75,,Q
1,34,Died,2,"Wheadon, Mr. Edward H",male,66,0,0,C.A. 24579,10.5,,S
1,35,Died,1,"Meyer, Mr. Edgar Joseph",male,28,1,0,PC 17604,82.1708,,C
1,36,Died,1,"Holverson, Mr. Alexander Oskar",male,42,1,0,113789,52,,S
1,37,Survived,3,"Mamee, Mr. Hanna",male,,0,0,2677,7.2292,,C
1,38,Died,3,"Cann, Mr. Ernest Charles",male,21,0,0,A./5. 2152,8.05,,S
1,39,Died,3,"Vander Planke, Miss. Augusta Maria",female,18,2,0,345764,18,,S
1,40,Survived,3,"Nicola-Yarred, Miss. Jamila",female,14,1,0,2651,11.2417,,C
1,41,Died,3,"Ahlin, Mrs. Johan (Johanna Persdotter Larsson)",female,40,1,0,7546,9.475,,S
1,42,Died,2,"Turpin, Mrs. William John Robert (Dorothy Ann Wonnacott)",female,27,1,0,11668,21,,S
1,43,Died,3,"Kraeff, Mr. Theodor",male,,0,0,349253,7.8958,,C
1,44,Survived,2,"Laroche, Miss. Simonne Marie Anne Andree",female,3,1,2,SC/Paris 2123,41.5792,,C
1,45,Survived,3,"Devaney, Miss. Margaret Delia",female,19,0,0,330958,7.8792,,Q
1,46,Died,3,"Rogers, Mr. William John",male,,0,0,S.C./A.4. 23567,8.05,,S
1,47,Died,3,"Lennon, Mr. Denis",male,,1,0,370371,15.5,,Q
1,48,Survived,3,"O'Driscoll, Miss. Bridget",female,,0,0,14311,7.75,,Q
1,49,Died,3,"Samaan, Mr. Youssef",male,,2,0,2662,21.6792,,C
1,50,Died,3,"Arnold-Franchi, Mrs. Josef (Josefine Franchi)",female,18,1,0,349237,17.8,,S
1,51,Died,3,"Panula, Master. Juha Niilo",male,7,4,1,3101295,39.6875,,S
1,52,Died,3,"Nosworthy, Mr. Richard Cater",male,21,0,0,A/4. 39886,7.8,,S
1,53,Survived,1,"Harper, Mrs. Henry Sleeper (Myna Haxtun)",female,49,1,0,PC 17572,76.7292,D33,C
1,54,Survived,2,"Faunthorpe, Mrs. Lizzie (Elizabeth Anne Wilkinson)",female,29,1,0,2926,26,,S
1,55,Died,1,"Ostby, Mr. Engelhart Cornelius",male,65,0,1,113509,61.9792,B30,C
1,56,Survived,1,"Woolner, Mr. Hugh",male,,0,0,19947,35.5,C52,S
1,57,Survived,2,"Rugg, Miss. Emily",female,21,0,0,C.A. 31026,10.5,,S
1,58,Died,3,"Novel, Mr. Mansouer",male,28.5,0,0,2697,7.2292,,C
1,59,Survived,2,"West, Miss. Constance Mirium",female,5,1,2,C.A. 34651,27.75,,S
1,60,Died,3,"Goodwin, Master. William Frederick",male,11,5,2,CA 2144,46.9,,S
1,61,Died,3,"Sirayanian, Mr. Orsen",male,22,0,0,2669,7.2292,,C
1,62,Survived,1,"Icard, Miss. Amelie",female,38,0,0,113572,80,B28,
1,63,Died,1,"Harris, Mr. Henry Birkhardt",male,45,1,0,36973,83.475,C83,S
1,64,Died,3,"Skoog, Master. Harald",male,4,3,2,347088,27.9,,S
1,65,Died,1,"Stewart, Mr. Albert A",male,,0,0,PC 17605,27.7208,,C
1,66,Survived,3,"Moubarek, Master. Gerios",male,,1,1,2661,15.2458,,C
1,67,Survived,2,"Nye, Mrs. (Elizabeth Ramell)",female,29,0,0,C.A. 29395,10.5,F33,S
1,68,Died,3,"Crease, Mr. Ernest James",male,19,0,0,S.P. 3464,8.1583,,S
1,69,Survived,3,"Andersson, Miss. Erna Alexandra",female,17,4,2,3101281,7.925,,S
1,70,Died,3,"Kink, Mr. Vincenz",male,26,2,0,315151,8.6625,,S
1,71,Died,2,"Jenkin, Mr. Stephen Curnow",male,32,0,0,C.A. 33111,10.5,,S
1,72,Died,3,"Goodwin, Miss. Lillian Amy",female,16,5,2,CA 2144,46.9,,S
1,73,Died,2,"Hood, Mr. Ambrose Jr",male,21,0,0,S.O.C. 14879,73.5,,S
1,74,Died,3,"Chronopoulos, Mr. Apostolos",male,26,1,0,2680,14.4542,,C
1,75,Survived,3,"Bing, Mr. Lee",male,32,0,0,1601,56.4958,,S
1,76,Died,3,"Moen, Mr. Sigurd Hansen",male,25,0,0,348123,7.65,F G73,S
1,77,Died,3,"Staneff, Mr. Ivan",male,,0,0,349208,7.8958,,S
1,78,Died,3,"Moutal, Mr. Rahamin Haim",male,,0,0,374746,8.05,,S
1,79,Survived,2,"Caldwell, Master. Alden Gates",male,0.83,0,2,248738,29,,S
1,80,Survived,3,"Dowdell, Miss. Elizabeth",female,30,0,0,364516,12.475,,S
1,81,Died,3,"Waelens, Mr. Achille",male,22,0,0,345767,9,,S
1,82,Survived,3,"Sheerlinck, Mr. Jan Baptist",male,29,0,0,345779,9.5,,S
1,83,Survived,3,"McDermott, Miss. Brigdet Delia",female,,0,0,330932,7.7875,,Q
1,84,Died,1,"Carrau, Mr. Francisco M",male,28,0,0,113059,47.1,,S
1,85,Survived,2,"Ilett, Miss. Bertha",female,17,0,0,SO/C 14885,10.5,,S
1,86,Survived,3,"Backstrom, Mrs. Karl Alfred (Maria Mathilda Gustafsson)",female,33,3,0,3101278,15.85,,S
1,87,Died,3,"Ford, Mr. William Neal",male,16,1,3,W./C. 6608,34.375,,S
1,88,Died,3,"Slocovski, Mr. Selman Francis",male,,0,0,SOTON/OQ 392086,8.05,,S
1,89,Survived,1,"Fortune, Miss. Mabel Helen",female,23,3,2,19950,263,C23 C25 C27,S
1,90,Died,3,"Celotti, Mr. Francesco",male,24,0,0,343275,8.05,,S
1,91,Died,3,"Christmann, Mr. Emil",male,29,0,0,343276,8.05,,S
1,92,Died,3,"Andreasson, Mr. Paul Edvin",male,20,0,0,347466,7.8542,,S
1,93,Died,1,"Chaffee, Mr. Herbert Fuller",male,46,1,0,W.E.P. 5734,61.175,E31,S
1,94,Died,3,"Dean, Mr. Bertram Frank",male,26,1,2,C.A. 2315,20.575,,S
1,95,Died,3,"Coxon, Mr. Daniel",male,59,0,0,364500,7.25,,S
1,96,Died,3,"Shorney, Mr. Charles Joseph",male,,0,0,374910,8.05,,S
1,97,Died,1,"Goldschmidt, Mr. George B",male,71,0,0,PC 17754,34.6542,A5,C
1,98,Survived,1,"Greenfield, Mr. William Bertram",male,23,0,1,PC 17759,63.3583,D10 D12,C
1,99,Survived,2,"Doling, Mrs. John T (Ada Julia Bone)",female,34,0,1,231919,23,,S
1,100,Died,2,"Kantor, Mr. Sinai",male,34,1,0,244367,26,,S
1,101,Died,3,"Petranec, Miss. Matilda",female,28,0,0,349245,7.8958,,S
1,102,Died,3,"Petroff, Mr. Pastcho (""Pentcho"")",male,,0,0,349215,7.8958,,S
1,103,Died,1,"White, Mr. Richard Frasar",male,21,0,1,35281,77.2875,D26,S
1,104,Died,3,"Johansson, Mr. Gustaf Joel",male,33,0,0,7540,8.6542,,S
1,105,Died,3,"Gustafsson, Mr. Anders Vilhelm",male,37,2,0,3101276,7.925,,S
1,106,Died,3,"Mionoff, Mr. Stoytcho",male,28,0,0,349207,7.8958,,S
1,107,Survived,3,"Salkjelsvik, Miss. Anna Kristine",female,21,0,0,343120,7.65,,S
1,108,Survived,3,"Moss, Mr. Albert Johan",male,,0,0,312991,7.775,,S
1,109,Died,3,"Rekic, Mr. Tido",male,38,0,0,349249,7.8958,,S
1,110,Survived,3,"Moran, Miss. Bertha",female,,1,0,371110,24.15,,Q
1,111,Died,1,"Porter, Mr. Walter Chamberlain",male,47,0,0,110465,52,C110,S
1,112,Died,3,"Zabour, Miss. Hileni",female,14.5,1,0,2665,14.4542,,C
1,113,Died,3,"Barton, Mr. David John",male,22,0,0,324669,8.05,,S
1,114,Died,3,"Jussila, Miss. Katriina",female,20,1,0,4136,9.825,,S
1,115,Died,3,"Attalah, Miss. Malake",female,17,0,0,2627,14.4583,,C
1,116,Died,3,"Pekoniemi, Mr. Edvard",male,21,0,0,STON/O 2. 3101294,7.925,,S
1,117,Died,3,"Connors, Mr. Patrick",male,70.5,0,0,370369,7.75,,Q
1,118,Died,2,"Turpin, Mr. William John Robert",male,29,1,0,11668,21,,S
1,119,Died,1,"Baxter, Mr. Quigg Edmond",male,24,0,1,PC 17558,247.5208,B58 B60,C
1,120,Died,3,"Andersson, Miss. Ellis Anna Maria",female,2,4,2,347082,31.275,,S
1,121,Died,2,"Hickman, Mr. Stanley George",male,21,2,0,S.O.C. 14879,73.5,,S
1,122,Died,3,"Moore, Mr. Leonard Charles",male,,0,0,A4. 54510,8.05,,S
1,123,Died,2,"Nasser, Mr. Nicholas",male,32.5,1,0,237736,30.0708,,C
1,124,Survived,2,"Webber, Miss. Susan",female,32.5,0,0,27267,13,E101,S
1,125,Died,1,"White, Mr. Percival Wayland",male,54,0,1,35281,77.2875,D26,S
1,126,Survived,3,"Nicola-Yarred, Master. Elias",male,12,1,0,2651,11.2417,,C
1,127,Died,3,"McMahon, Mr. Martin",male,,0,0,370372,7.75,,Q
1,128,Survived,3,"Madsen, Mr. Fridtjof Arne",male,24,0,0,C 17369,7.1417,,S
1,129,Survived,3,"Peter, Miss. Anna",female,,1,1,2668,22.3583,F E69,C
1,130,Died,3,"Ekstrom, Mr. Johan",male,45,0,0,347061,6.975,,S
1,131,Died,3,"Drazenoic, Mr. Jozef",male,33,0,0,349241,7.8958,,C
1,132,Died,3,"Coelho, Mr. Domingos Fernandeo",male,20,0,0,SOTON/O.Q. 3101307,7.05,,S
1,133,Died,3,"Robins, Mrs. Alexander A (Grace Charity Laury)",female,47,1,0,A/5. 3337,14.5,,S
1,134,Survived,2,"Weisz, Mrs. Leopold (Mathilde Francoise Pede)",female,29,1,0,228414,26,,S
1,135,Died,2,"Sobey, Mr. Samuel James Hayden",male,25,0,0,C.A. 29178,13,,S
1,136,Died,2,"Richard, Mr. Emile",male,23,0,0,SC/PARIS 2133,15.0458,,C
1,137,Survived,1,"Newsom, Miss. Helen Monypeny",female,19,0,2,11752,26.2833,D47,S
1,138,Died,1,"Futrelle, Mr. Jacques Heath",male,37,1,0,113803,53.1,C123,S
1,139,Died,3,"Osen, Mr. Olaf Elon",male,16,0,0,7534,9.2167,,S
1,140,Died,1,"Giglio, Mr. Victor",male,24,0,0,PC 17593,79.2,B86,C
1,141,Died,3,"Boulos, Mrs. Joseph (Sultana)",female,,0,2,2678,15.2458,,C
1,142,Survived,3,"Nysten, Miss. Anna Sofia",female,22,0,0,347081,7.75,,S
1,143,Survived,3,"Hakkarainen, Mrs. Pekka Pietari (Elin Matilda Dolck)",female,24,1,0,STON/O2. 3101279,15.85,,S
1,144,Died,3,"Burke, Mr. Jeremiah",male,19,0,0,365222,6.75,,Q
1,145,Died,2,"Andrew, Mr. Edgardo Samuel",male,18,0,0,231945,11.5,,S
1,146,Died,2,"Nicholls, Mr. Joseph Charles",male,19,1,1,C.A. 33112,36.75,,S
1,147,Survived,3,"Andersson, Mr. August Edvard (""Wennerstrom"")",male,27,0,0,350043,7.7958,,S
1,148,Died,3,"Ford, Miss. Robina Maggie ""Ruby""",female,9,2,2,W./C. 6608,34.375,,S
1,149,Died,2,"Navratil, Mr. Michel (""Louis M Hoffman"")",male,36.5,0,2,230080,26,F2,S
1,150,Died,2,"Byles, Rev. Thomas Roussel Davids",male,42,0,0,244310,13,,S
1,151,Died,2,"Bateman, Rev. Robert James",male,51,0,0,S.O.P. 1166,12.525,,S
1,152,Survived,1,"Pears, Mrs. Thomas (Edith Wearne)",female,22,1,0,113776,66.6,C2,S
1,153,Died,3,"Meo, Mr. Alfonzo",male,55.5,0,0,A.5. 11206,8.05,,S
1,154,Died,3,"van Billiard, Mr. Austin Blyler",male,40.5,0,2,A/5. 851,14.5,,S
1,155,Died,3,"Olsen, Mr. Ole Martin",male,,0,0,Fa 265302,7.3125,,S
1,156,Died,1,"Williams, Mr. Charles Duane",male,51,0,1,PC 17597,61.3792,,C
1,157,Survived,3,"Gilnagh, Miss. Katherine ""Katie""",female,16,0,0,35851,7.7333,,Q
1,158,Died,3,"Corn, Mr. Harry",male,30,0,0,SOTON/OQ 392090,8.05,,S
1,159,Died,3,"Smiljanic, Mr. Mile",male,,0,0,315037,8.6625,,S
1,160,Died,3,"Sage, Master. Thomas Henry",male,,8,2,CA. 2343,69.55,,S
1,161,Died,3,"Cribb, Mr. John Hatfield",male,44,0,1,371362,16.1,,S
1,162,Survived,2,"Watt, Mrs. James (Elizabeth ""Bessie"" Inglis Milne)",female,40,0,0,C.A. 33595,15.75,,S
1,163,Died,3,"Bengtsson, Mr. John Viktor",male,26,0,0,347068,7.775,,S
1,164,Died,3,"Calic, Mr. Jovo",male,17,0,0,315093,8.6625,,S
1,165,Died,3,"Panula, Master. Eino Viljami",male,1,4,1,3101295,39.6875,,S
1,166,Survived,3,"Goldsmith, Master. Frank John William ""Frankie""",male,9,0,2,363291,20.525,,S
1,167,Survived,1,"Chibnall, Mrs. (Edith Martha Bowerman)",female,,0,1,113505,55,E33,S
1,168,Died,3,"Skoog, Mrs. William (Anna Bernhardina Karlsson)",female,45,1,4,347088,27.9,,S
1,169,Died,1,"Baumann, Mr. John D",male,,0,0,PC 17318,25.925,,S
1,170,Died,3,"Ling, Mr. Lee",male,28,0,0,1601,56.4958,,S
1,171,Died,1,"Van der hoef, Mr. Wyckoff",male,61,0,0,111240,33.5,B19,S
1,172,Died,3,"Rice, Master. Arthur",male,4,4,1,382652,29.125,,Q
1,173,Survived,3,"Johnson, Miss. Eleanor Ileen",female,1,1,1,347742,11.1333,,S
1,174,Died,3,"Sivola, Mr. Antti Wilhelm",male,21,0,0,STON/O 2. 3101280,7.925,,S
1,175,Died,1,"Smith, Mr. James Clinch",male,56,0,0,17764,30.6958,A7,C
1,176,Died,3,"Klasen, Mr. Klas Albin",male,18,1,1,350404,7.8542,,S
1,177,Died,3,"Lefebre, Master. Henry Forbes",male,,3,1,4133,25.4667,,S
1,178,Died,1,"Isham, Miss. Ann Elizabeth",female,50,0,0,PC 17595,28.7125,C49,C
1,179,Died,2,"Hale, Mr. Reginald",male,30,0,0,250653,13,,S
1,180,Died,3,"Leonard, Mr. Lionel",male,36,0,0,LINE,0,,S
1,181,Died,3,"Sage, Miss. Constance Gladys",female,,8,2,CA. 2343,69.55,,S
1,182,Died,2,"Pernot, Mr. Rene",male,,0,0,SC/PARIS 2131,15.05,,C
1,183,Died,3,"Asplund, Master. Clarence Gustaf Hugo",male,9,4,2,347077,31.3875,,S
1,184,Survived,2,"Becker, Master. Richard F",male,1,2,1,230136,39,F4,S
1,185,Survived,3,"Kink-Heilmann, Miss. Luise Gretchen",female,4,0,2,315153,22.025,,S
1,186,Died,1,"Rood, Mr. Hugh Roscoe",male,,0,0,113767,50,A32,S
1,187,Survived,3,"O'Brien, Mrs. Thomas (Johanna ""Hannah"" Godfrey)",female,,1,0,370365,15.5,,Q
1,188,Survived,1,"Romaine, Mr. Charles Hallace (""Mr C Rolmane"")",male,45,0,0,111428,26.55,,S
1,189,Died,3,"Bourke, Mr. John",male,40,1,1,364849,15.5,,Q
1,190,Died,3,"Turcin, Mr. Stjepan",male,36,0,0,349247,7.8958,,S
1,191,Survived,2,"Pinsky, Mrs. (Rosa)",female,32,0,0,234604,13,,S
1,192,Died,2,"Carbines, Mr. William",male,19,0,0,28424,13,,S
1,193,Survived,3,"Andersen-Jensen, Miss. Carla Christine Nielsine",female,19,1,0,350046,7.8542,,S
1,194,Survived,2,"Navratil, Master. Michel M",male,3,1,1,230080,26,F2,S
1,195,Survived,1,"Brown, Mrs. James Joseph (Margaret Tobin)",female,44,0,0,PC 17610,27.7208,B4,C
1,196,Survived,1,"Lurette, Miss. Elise",female,58,0,0,PC 17569,146.5208,B80,C
1,197,Died,3,"Mernagh, Mr. Robert",male,,0,0,368703,7.75,,Q
1,198,Died,3,"Olsen, Mr. Karl Siegwart Andreas",male,42,0,1,4579,8.4042,,S
1,199,Survived,3,"Madigan, Miss. Margaret ""Maggie""",female,,0,0,370370,7.75,,Q
1,200,Died,2,"Yrois, Miss. Henriette (""Mrs Harbeck"")",female,24,0,0,248747,13,,S
1,201,Died,3,"Vande Walle, Mr. Nestor Cyriel",male,28,0,0,345770,9.5,,S
1,202,Died,3,"Sage, Mr. Frederick",male,,8,2,CA. 2343,69.55,,S
1,203,Died,3,"Johanson, Mr. Jakob Alfred",male,34,0,0,3101264,6.4958,,S
1,204,Died,3,"Youseff, Mr. Gerious",male,45.5,0,0,2628,7.225,,C
1,205,Survived,3,"Cohen, Mr. Gurshon ""Gus""",male,18,0,0,A/5 3540,8.05,,S
1,206,Died,3,"Strom, Miss. Telma Matilda",female,2,0,1,347054,10.4625,G6,S
1,207,Died,3,"Backstrom, Mr. Karl Alfred",male,32,1,0,3101278,15.85,,S
1,208,Survived,3,"Albimona, Mr. Nassef Cassem",male,26,0,0,2699,18.7875,,C
1,209,Survived,3,"Carr, Miss. Helen ""Ellen""",female,16,0,0,367231,7.75,,Q
1,210,Survived,1,"Blank, Mr. Henry",male,40,0,0,112277,31,A31,C
1,211,Died,3,"Ali, Mr. Ahmed",male,24,0,0,SOTON/O.Q. 3101311,7.05,,S
1,212,Survived,2,"Cameron, Miss. Clear Annie",female,35,0,0,F.C.C. 13528,21,,S
1,213,Died,3,"Perkin, Mr. John Henry",male,22,0,0,A/5 21174,7.25,,S
1,214,Died,2,"Givard, Mr. Hans Kristensen",male,30,0,0,250646,13,,S
1,215,Died,3,"Kiernan, Mr. Philip",male,,1,0,367229,7.75,,Q
1,216,Survived,1,"Newell, Miss. Madeleine",female,31,1,0,35273,113.275,D36,C
1,217,Survived,3,"Honkanen, Miss. Eliina",female,27,0,0,STON/O2. 3101283,7.925,,S
1,218,Died,2,"Jacobsohn, Mr. Sidney Samuel",male,42,1,0,243847,27,,S
1,219,Survived,1,"Bazzani, Miss. Albina",female,32,0,0,11813,76.2917,D15,C
1,220,Died,2,"Harris, Mr. Walter",male,30,0,0,W/C 14208,10.5,,S
1,221,Survived,3,"Sunderland, Mr. Victor Francis",male,16,0,0,SOTON/OQ 392089,8.05,,S
1,222,Died,2,"Bracken, Mr. James H",male,27,0,0,220367,13,,S
1,223,Died,3,"Green, Mr. George Henry",male,51,0,0,21440,8.05,,S
1,224,Died,3,"Nenkoff, Mr. Christo",male,,0,0,349234,7.8958,,S
1,225,Survived,1,"Hoyt, Mr. Frederick Maxfield",male,38,1,0,19943,90,C93,S
1,226,Died,3,"Berglund, Mr. Karl Ivar Sven",male,22,0,0,PP 4348,9.35,,S
1,227,Survived,2,"Mellors, Mr. William John",male,19,0,0,SW/PP 751,10.5,,S
1,228,Died,3,"Lovell, Mr. John Hall (""Henry"")",male,20.5,0,0,A/5 21173,7.25,,S
1,229,Died,2,"Fahlstrom, Mr. Arne Jonas",male,18,0,0,236171,13,,S
1,230,Died,3,"Lefebre, Miss. Mathilde",female,,3,1,4133,25.4667,,S
1,231,Survived,1,"Harris, Mrs. Henry Birkhardt (Irene Wallach)",female,35,1,0,36973,83.475,C83,S
1,232,Died,3,"Larsson, Mr. Bengt Edvin",male,29,0,0,347067,7.775,,S
1,233,Died,2,"Sjostedt, Mr. Ernst Adolf",male,59,0,0,237442,13.5,,S
1,234,Survived,3,"Asplund, Miss. Lillian Gertrud",female,5,4,2,347077,31.3875,,S
1,235,Died,2,"Leyson, Mr. Robert William Norman",male,24,0,0,C.A. 29566,10.5,,S
1,236,Died,3,"Harknett, Miss. Alice Phoebe",female,,0,0,W./C. 6609,7.55,,S
1,237,Died,2,"Hold, Mr. Stephen",male,44,1,0,26707,26,,S
1,238,Survived,2,"Collyer, Miss. Marjorie ""Lottie""",female,8,0,2,C.A. 31921,26.25,,S
1,239,Died,2,"Pengelly, Mr. Frederick William",male,19,0,0,28665,10.5,,S
1,240,Died,2,"Hunt, Mr. George Henry",male,33,0,0,SCO/W 1585,12.275,,S
1,241,Died,3,"Zabour, Miss. Thamine",female,,1,0,2665,14.4542,,C
1,242,Survived,3,"Murphy, Miss. Katherine ""Kate""",female,,1,0,367230,15.5,,Q
1,243,Died,2,"Coleridge, Mr. Reginald Charles",male,29,0,0,W./C. 14263,10.5,,S
1,244,Died,3,"Maenpaa, Mr. Matti Alexanteri",male,22,0,0,STON/O 2. 3101275,7.125,,S
1,245,Died,3,"Attalah, Mr. Sleiman",male,30,0,0,2694,7.225,,C
1,246,Died,1,"Minahan, Dr. William Edward",male,44,2,0,19928,90,C78,Q
1,247,Died,3,"Lindahl, Miss. Agda Thorilda Viktoria",female,25,0,0,347071,7.775,,S
1,248,Survived,2,"Hamalainen, Mrs. William (Anna)",female,24,0,2,250649,14.5,,S
1,249,Survived,1,"Beckwith, Mr. Richard Leonard",male,37,1,1,11751,52.5542,D35,S
1,250,Died,2,"Carter, Rev. Ernest Courtenay",male,54,1,0,244252,26,,S
1,251,Died,3,"Reed, Mr. James George",male,,0,0,362316,7.25,,S
1,252,Died,3,"Strom, Mrs. Wilhelm (Elna Matilda Persson)",female,29,1,1,347054,10.4625,G6,S
1,253,Died,1,"Stead, Mr. William Thomas",male,62,0,0,113514,26.55,C87,S
1,254,Died,3,"Lobb, Mr. William Arthur",male,30,1,0,A/5. 3336,16.1,,S
1,255,Died,3,"Rosblom, Mrs. Viktor (Helena Wilhelmina)",female,41,0,2,370129,20.2125,,S
1,256,Survived,3,"Touma, Mrs. Darwis (Hanne Youssef Razi)",female,29,0,2,2650,15.2458,,C
1,257,Survived,1,"Thorne, Mrs. Gertrude Maybelle",female,,0,0,PC 17585,79.2,,C
1,258,Survived,1,"Cherry, Miss. Gladys",female,30,0,0,110152,86.5,B77,S
1,259,Survived,1,"Ward, Miss. Anna",female,35,0,0,PC 17755,512.3292,,C
1,260,Survived,2,"Parrish, Mrs. (Lutie Davis)",female,50,0,1,230433,26,,S
1,261,Died,3,"Smith, Mr. Thomas",male,,0,0,384461,7.75,,Q
1,262,Survived,3,"Asplund, Master. Edvin Rojj Felix",male,3,4,2,347077,31.3875,,S
1,263,Died,1,"Taussig, Mr. Emil",male,52,1,1,110413,79.65,E67,S
1,264,Died,1,"Harrison, Mr. William",male,40,0,0,112059,0,B94,S
1,265,Died,3,"Henry, Miss. Delia",female,,0,0,382649,7.75,,Q
1,266,Died,2,"Reeves, Mr. David",male,36,0,0,C.A. 17248,10.5,,S
1,267,Died,3,"Panula, Mr. Ernesti Arvid",male,16,4,1,3101295,39.6875,,S
1,268,Survived,3,"Persson, Mr. Ernst Ulrik",male,25,1,0,347083,7.775,,S
1,269,Survived,1,"Graham, Mrs. William Thompson (Edith Junkins)",female,58,0,1,PC 17582,153.4625,C125,S
1,270,Survived,1,"Bissette, Miss. Amelia",female,35,0,0,PC 17760,135.6333,C99,S
1,271,Died,1,"Cairns, Mr. Alexander",male,,0,0,113798,31,,S
1,272,Survived,3,"Tornquist, Mr. William Henry",male,25,0,0,LINE,0,,S
1,273,Survived,2,"Mellinger, Mrs. (Elizabeth Anne Maidment)",female,41,0,1,250644,19.5,,S
1,274,Died,1,"Natsch, Mr. Charles H",male,37,0,1,PC 17596,29.7,C118,C
1,275,Survived,3,"Healy, Miss. Hanora ""Nora""",female,,0,0,370375,7.75,,Q
1,276,Survived,1,"Andrews, Miss. Kornelia Theodosia",female,63,1,0,13502,77.9583,D7,S
1,277,Died,3,"Lindblom, Miss. Augusta Charlotta",female,45,0,0,347073,7.75,,S
1,278,Died,2,"Parkes, Mr. Francis ""Frank""",male,,0,0,239853,0,,S
1,279,Died,3,"Rice, Master. Eric",male,7,4,1,382652,29.125,,Q
1,280,Survived,3,"Abbott, Mrs. Stanton (Rosa Hunt)",female,35,1,1,C.A. 2673,20.25,,S
1,281,Died,3,"Duane, Mr. Frank",male,65,0,0,336439,7.75,,Q
1,282,Died,3,"Olsson, Mr. Nils Johan Goransson",male,28,0,0,347464,7.8542,,S
1,283,Died,3,"de Pelsmaeker, Mr. Alfons",male,16,0,0,345778,9.5,,S
1,284,Survived,3,"Dorking, Mr. Edward Arthur",male,19,0,0,A/5. 10482,8.05,,S
1,285,Died,1,"Smith, Mr. Richard William",male,,0,0,113056,26,A19,S
1,286,Died,3,"Stankovic, Mr. Ivan",male,33,0,0,349239,8.6625,,C
1,287,Survived,3,"de Mulder, Mr. Theodore",male,30,0,0,345774,9.5,,S
1,288,Died,3,"Naidenoff, Mr. Penko",male,22,0,0,349206,7.8958,,S
1,289,Survived,2,"Hosono, Mr. Masabumi",male,42,0,0,237798,13,,S
1,290,Survived,3,"Connolly, Miss. Kate",female,22,0,0,370373,7.75,,Q
1,291,Survived,1,"Barber, Miss. Ellen ""Nellie""",female,26,0,0,19877,78.85,,S
1,292,Survived,1,"Bishop, Mrs. Dickinson H (Helen Walton)",female,19,1,0,11967,91.0792,B49,C
1,293,Died,2,"Levy, Mr. Rene Jacques",male,36,0,0,SC/Paris 2163,12.875,D,C
1,294,Died,3,"Haas, Miss. Aloisia",female,24,0,0,349236,8.85,,S
1,295,Died,3,"Mineff, Mr. Ivan",male,24,0,0,349233,7.8958,,S
1,296,Died,1,"Lewy, Mr. Ervin G",male,,0,0,PC 17612,27.7208,,C
1,297,Died,3,"Hanna, Mr. Mansour",male,23.5,0,0,2693,7.2292,,C
1,298,Died,1,"Allison, Miss. Helen Loraine",female,2,1,2,113781,151.55,C22 C26,S
1,299,Survived,1,"Saalfeld, Mr. Adolphe",male,,0,0,19988,30.5,C106,S
1,300,Survived,1,"Baxter, Mrs. James (Helene DeLaudeniere Chaput)",female,50,0,1,PC 17558,247.5208,B58 B60,C
1,301,Survived,3,"Kelly, Miss. Anna Katherine ""Annie Kate""",female,,0,0,9234,7.75,,Q
1,302,Survived,3,"McCoy, Mr. Bernard",male,,2,0,367226,23.25,,Q
1,303,Died,3,"Johnson, Mr. William Cahoone Jr",male,19,0,0,LINE,0,,S
1,304,Survived,2,"Keane, Miss. Nora A",female,,0,0,226593,12.35,E101,Q
1,305,Died,3,"Williams, Mr. Howard Hugh ""Harry""",male,,0,0,A/5 2466,8.05,,S
1,306,Survived,1,"Allison, Master. Hudson Trevor",male,0.92,1,2,113781,151.55,C22 C26,S
1,307,Survived,1,"Fleming, Miss. Margaret",female,,0,0,17421,110.8833,,C
1,308,Survived,1,"Penasco y Castellana, Mrs. Victor de Satode (Maria Josefa Perez de Soto y Vallejo)",female,17,1,0,PC 17758,108.9,C65,C
1,309,Died,2,"Abelson, Mr. Samuel",male,30,1,0,P/PP 3381,24,,C
1,310,Survived,1,"Francatelli, Miss. Laura Mabel",female,30,0,0,PC 17485,56.9292,E36,C
1,311,Survived,1,"Hays, Miss. Margaret Bechstein",female,24,0,0,11767,83.1583,C54,C
1,312,Survived,1,"Ryerson, Miss. Emily Borie",female,18,2,2,PC 17608,262.375,B57 B59 B63 B66,C
1,313,Died,2,"Lahtinen, Mrs. William (Anna Sylfven)",female,26,1,1,250651,26,,S
1,314,Died,3,"Hendekovic, Mr. Ignjac",male,28,0,0,349243,7.8958,,S
1,315,Died,2,"Hart, Mr. Benjamin",male,43,1,1,F.C.C. 13529,26.25,,S
1,316,Survived,3,"Nilsson, Miss. Helmina Josefina",female,26,0,0,347470,7.8542,,S
1,317,Survived,2,"Kantor, Mrs. Sinai (Miriam Sternin)",female,24,1,0,244367,26,,S
1,318,Died,2,"Moraweck, Dr. Ernest",male,54,0,0,29011,14,,S
1,319,Survived,1,"Wick, Miss. Mary Natalie",female,31,0,2,36928,164.8667,C7,S
1,320,Survived,1,"Spedden, Mrs. Frederic Oakley (Margaretta Corning Stone)",female,40,1,1,16966,134.5,E34,C
1,321,Died,3,"Dennis, Mr. Samuel",male,22,0,0,A/5 21172,7.25,,S
1,322,Died,3,"Danoff, Mr. Yoto",male,27,0,0,349219,7.8958,,S
1,323,Survived,2,"Slayter, Miss. Hilda Mary",female,30,0,0,234818,12.35,,Q
1,324,Survived,2,"Caldwell, Mrs. Albert Francis (Sylvia Mae Harbaugh)",female,22,1,1,248738,29,,S
1,325,Died,3,"Sage, Mr. George John Jr",male,,8,2,CA. 2343,69.55,,S
1,326,Survived,1,"Young, Miss. Marie Grice",female,36,0,0,PC 17760,135.6333,C32,C
1,327,Died,3,"Nysveen, Mr. Johan Hansen",male,61,0,0,345364,6.2375,,S
1,328,Survived,2,"Ball, Mrs. (Ada E Hall)",female,36,0,0,28551,13,D,S
1,329,Survived,3,"Goldsmith, Mrs. Frank John (Emily Alice Brown)",female,31,1,1,363291,20.525,,S
1,330,Survived,1,"Hippach, Miss. Jean Gertrude",female,16,0,1,111361,57.9792,B18,C
1,331,Survived,3,"McCoy, Miss. Agnes",female,,2,0,367226,23.25,,Q
1,332,Died,1,"Partner, Mr. Austen",male,45.5,0,0,113043,28.5,C124,S
1,333,Died,1,"Graham, Mr. George Edward",male,38,0,1,PC 17582,153.4625,C91,S
1,334,Died,3,"Vander Planke, Mr. Leo Edmondus",male,16,2,0,345764,18,,S
1,335,Survived,1,"Frauenthal, Mrs. Henry William (Clara Heinsheimer)",female,,1,0,PC 17611,133.65,,S
1,336,Died,3,"Denkoff, Mr. Mitto",male,,0,0,349225,7.8958,,S
1,337,Died,1,"Pears, Mr. Thomas Clinton",male,29,1,0,113776,66.6,C2,S
1,338,Survived,1,"Burns, Miss. Elizabeth Margaret",female,41,0,0,16966,134.5,E40,C
1,339,Survived,3,"Dahl, Mr. Karl Edwart",male,45,0,0,7598,8.05,,S
1,340,Died,1,"Blackwell, Mr. Stephen Weart",male,45,0,0,113784,35.5,T,S
1,341,Survived,2,"Navratil, Master. Edmond Roger",male,2,1,1,230080,26,F2,S
1,342,Survived,1,"Fortune, Miss. Alice Elizabeth",female,24,3,2,19950,263,C23 C25 C27,S
1,343,Died,2,"Collander, Mr. Erik Gustaf",male,28,0,0,248740,13,,S
1,344,Died,2,"Sedgwick, Mr. Charles Frederick Waddington",male,25,0,0,244361,13,,S
1,345,Died,2,"Fox, Mr. Stanley Hubert",male,36,0,0,229236,13,,S
1,346,Survived,2,"Brown, Miss. Amelia ""Mildred""",female,24,0,0,248733,13,F33,S
1,347,Survived,2,"Smith, Miss. Marion Elsie",female,40,0,0,31418,13,,S
1,348,Survived,3,"Davison, Mrs. Thomas Henry (Mary E Finck)",female,,1,0,386525,16.1,,S
1,349,Survived,3,"Coutts, Master. William Loch ""William""",male,3,1,1,C.A. 37671,15.9,,S
1,350,Died,3,"Dimic, Mr. Jovan",male,42,0,0,315088,8.6625,,S
1,351,Died,3,"Odahl, Mr. Nils Martin",male,23,0,0,7267,9.225,,S
1,352,Died,1,"Williams-Lambert, Mr. Fletcher Fellows",male,,0,0,113510,35,C128,S
1,353,Died,3,"Elias, Mr. Tannous",male,15,1,1,2695,7.2292,,C
1,354,Died,3,"Arnold-Franchi, Mr. Josef",male,25,1,0,349237,17.8,,S
1,355,Died,3,"Yousif, Mr. Wazli",male,,0,0,2647,7.225,,C
1,356,Died,3,"Vanden Steen, Mr. Leo Peter",male,28,0,0,345783,9.5,,S
1,357,Survived,1,"Bowerman, Miss. Elsie Edith",female,22,0,1,113505,55,E33,S
1,358,Died,2,"Funk, Miss. Annie Clemmer",female,38,0,0,237671,13,,S
1,359,Survived,3,"McGovern, Miss. Mary",female,,0,0,330931,7.8792,,Q
1,360,Survived,3,"Mockler, Miss. Helen Mary ""Ellie""",female,,0,0,330980,7.8792,,Q
1,361,Died,3,"Skoog, Mr. Wilhelm",male,40,1,4,347088,27.9,,S
1,362,Died,2,"del Carlo, Mr. Sebastiano",male,29,1,0,SC/PARIS 2167,27.7208,,C
1,363,Died,3,"Barbara, Mrs. (Catherine David)",female,45,0,1,2691,14.4542,,C
1,364,Died,3,"Asim, Mr. Adola",male,35,0,0,SOTON/O.Q. 3101310,7.05,,S
1,365,Died,3,"O'Brien, Mr. Thomas",male,,1,0,370365,15.5,,Q
1,366,Died,3,"Adahl, Mr. Mauritz Nils Martin",male,30,0,0,C 7076,7.25,,S
1,367,Survived,1,"Warren, Mrs. Frank Manley (Anna Sophia Atkinson)",female,60,1,0,110813,75.25,D37,C
1,368,Survived,3,"Moussa, Mrs. (Mantoura Boulos)",female,,0,0,2626,7.2292,,C
1,369,Survived,3,"Jermyn, Miss. Annie",female,,0,0,14313,7.75,,Q
1,370,Survived,1,"Aubart, Mme. Leontine Pauline",female,24,0,0,PC 17477,69.3,B35,C
1,371,Survived,1,"Harder, Mr. George Achilles",male,25,1,0,11765,55.4417,E50,C
1,372,Died,3,"Wiklund, Mr. Jakob Alfred",male,18,1,0,3101267,6.4958,,S
1,373,Died,3,"Beavan, Mr. William Thomas",male,19,0,0,323951,8.05,,S
1,374,Died,1,"Ringhini, Mr. Sante",male,22,0,0,PC 17760,135.6333,,C
1,375,Died,3,"Palsson, Miss. Stina Viola",female,3,3,1,349909,21.075,,S
1,376,Survived,1,"Meyer, Mrs. Edgar Joseph (Leila Saks)",female,,1,0,PC 17604,82.1708,,C
1,377,Survived,3,"Landergren, Miss. Aurora Adelia",female,22,0,0,C 7077,7.25,,S
1,378,Died,1,"Widener, Mr. Harry Elkins",male,27,0,2,113503,211.5,C82,C
1,379,Died,3,"Betros, Mr. Tannous",male,20,0,0,2648,4.0125,,C
1,380,Died,3,"Gustafsson, Mr. Karl Gideon",male,19,0,0,347069,7.775,,S
1,381,Survived,1,"Bidois, Miss. Rosalie",female,42,0,0,PC 17757,227.525,,C
1,382,Survived,3,"Nakid, Miss. Maria (""Mary"")",female,1,0,2,2653,15.7417,,C
1,383,Died,3,"Tikkanen, Mr. Juho",male,32,0,0,STON/O 2. 3101293,7.925,,S
1,384,Survived,1,"Holverson, Mrs. Alexander Oskar (Mary Aline Towner)",female,35,1,0,113789,52,,S
1,385,Died,3,"Plotcharsky, Mr. Vasil",male,,0,0,349227,7.8958,,S
1,386,Died,2,"Davies, Mr. Charles Henry",male,18,0,0,S.O.C. 14879,73.5,,S
1,387,Died,3,"Goodwin, Master. Sidney Leonard",male,1,5,2,CA 2144,46.9,,S
1,388,Survived,2,"Buss, Miss. Kate",female,36,0,0,27849,13,,S
1,389,Died,3,"Sadlier, Mr. Matthew",male,,0,0,367655,7.7292,,Q
1,390,Survived,2,"Lehmann, Miss. Bertha",female,17,0,0,SC 1748,12,,C
1,391,Survived,1,"Carter, Mr. William Ernest",male,36,1,2,113760,120,B96 B98,S
1,392,Survived,3,"Jansson, Mr. Carl Olof",male,21,0,0,350034,7.7958,,S
1,393,Died,3,"Gustafsson, Mr. Johan Birger",male,28,2,0,3101277,7.925,,S
1,394,Survived,1,"Newell, Miss. Marjorie",female,23,1,0,35273,113.275,D36,C
1,395,Survived,3,"Sandstrom, Mrs. Hjalmar (Agnes Charlotta Bengtsson)",female,24,0,2,PP 9549,16.7,G6,S
1,396,Died,3,"Johansson, Mr. Erik",male,22,0,0,350052,7.7958,,S
1,397,Died,3,"Olsson, Miss. Elina",female,31,0,0,350407,7.8542,,S
1,398,Died,2,"McKane, Mr. Peter David",male,46,0,0,28403,26,,S
1,399,Died,2,"Pain, Dr. Alfred",male,23,0,0,244278,10.5,,S
1,400,Survived,2,"Trout, Mrs. William H (Jessie L)",female,28,0,0,240929,12.65,,S
1,401,Survived,3,"Niskanen, Mr. Juha",male,39,0,0,STON/O 2. 3101289,7.925,,S
1,402,Died,3,"Adams, Mr. John",male,26,0,0,341826,8.05,,S
1,403,Died,3,"Jussila, Miss. Mari Aina",female,21,1,0,4137,9.825,,S
1,404,Died,3,"Hakkarainen, Mr. Pekka Pietari",male,28,1,0,STON/O2. 3101279,15.85,,S
1,405,Died,3,"Oreskovic, Miss. Marija",female,20,0,0,315096,8.6625,,S
1,406,Died,2,"Gale, Mr. Shadrach",male,34,1,0,28664,21,,S
1,407,Died,3,"Widegren, Mr. Carl/Charles Peter",male,51,0,0,347064,7.75,,S
1,408,Survived,2,"Richards, Master. William Rowe",male,3,1,1,29106,18.75,,S
1,409,Died,3,"Birkeland, Mr. Hans Martin Monsen",male,21,0,0,312992,7.775,,S
1,410,Died,3,"Lefebre, Miss. Ida",female,,3,1,4133,25.4667,,S
1,411,Died,3,"Sdycoff, Mr. Todor",male,,0,0,349222,7.8958,,S
1,412,Died,3,"Hart, Mr. Henry",male,,0,0,394140,6.8583,,Q
1,413,Survived,1,"Minahan, Miss. Daisy E",female,33,1,0,19928,90,C78,Q
1,414,Died,2,"Cunningham, Mr. Alfred Fleming",male,,0,0,239853,0,,S
1,415,Survived,3,"Sundman, Mr. Johan Julian",male,44,0,0,STON/O 2. 3101269,7.925,,S
1,416,Died,3,"Meek, Mrs. Thomas (Annie Louise Rowley)",female,,0,0,343095,8.05,,S
1,417,Survived,2,"Drew, Mrs. James Vivian (Lulu Thorne Christian)",female,34,1,1,28220,32.5,,S
1,418,Survived,2,"Silven, Miss. Lyyli Karoliina",female,18,0,2,250652,13,,S
1,419,Died,2,"Matthews, Mr. William John",male,30,0,0,28228,13,,S
1,420,Died,3,"Van Impe, Miss. Catharina",female,10,0,2,345773,24.15,,S
1,421,Died,3,"Gheorgheff, Mr. Stanio",male,,0,0,349254,7.8958,,C
1,422,Died,3,"Charters, Mr. David",male,21,0,0,A/5. 13032,7.7333,,Q
1,423,Died,3,"Zimmerman, Mr. Leo",male,29,0,0,315082,7.875,,S
1,424,Died,3,"Danbom, Mrs. Ernst Gilbert (Anna Sigrid Maria Brogren)",female,28,1,1,347080,14.4,,S
1,425,Died,3,"Rosblom, Mr. Viktor Richard",male,18,1,1,370129,20.2125,,S
1,426,Died,3,"Wiseman, Mr. Phillippe",male,,0,0,A/4. 34244,7.25,,S
1,427,Survived,2,"Clarke, Mrs. Charles V (Ada Maria Winfield)",female,28,1,0,2003,26,,S
1,428,Survived,2,"Phillips, Miss. Kate Florence (""Mrs Kate Louise Phillips Marshall"")",female,19,0,0,250655,26,,S
1,429,Died,3,"Flynn, Mr. James",male,,0,0,364851,7.75,,Q
1,430,Survived,3,"Pickard, Mr. Berk (Berk Trembisky)",male,32,0,0,SOTON/O.Q. 392078,8.05,E10,S
1,431,Survived,1,"Bjornstrom-Steffansson, Mr. Mauritz Hakan",male,28,0,0,110564,26.55,C52,S
1,432,Survived,3,"Thorneycroft, Mrs. Percival (Florence Kate White)",female,,1,0,376564,16.1,,S
1,433,Survived,2,"Louch, Mrs. Charles Alexander (Alice Adelaide Slow)",female,42,1,0,SC/AH 3085,26,,S
1,434,Died,3,"Kallio, Mr. Nikolai Erland",male,17,0,0,STON/O 2. 3101274,7.125,,S
1,435,Died,1,"Silvey, Mr. William Baird",male,50,1,0,13507,55.9,E44,S
1,436,Survived,1,"Carter, Miss. Lucile Polk",female,14,1,2,113760,120,B96 B98,S
1,437,Died,3,"Ford, Miss. Doolina Margaret ""Daisy""",female,21,2,2,W./C. 6608,34.375,,S
1,438,Survived,2,"Richards, Mrs. Sidney (Emily Hocking)",female,24,2,3,29106,18.75,,S
1,439,Died,1,"Fortune, Mr. Mark",male,64,1,4,19950,263,C23 C25 C27,S
1,440,Died,2,"Kvillner, Mr. Johan Henrik Johannesson",male,31,0,0,C.A. 18723,10.5,,S
1,441,Survived,2,"Hart, Mrs. Benjamin (Esther Ada Bloomfield)",female,45,1,1,F.C.C. 13529,26.25,,S
1,442,Died,3,"Hampe, Mr. Leon",male,20,0,0,345769,9.5,,S
1,443,Died,3,"Petterson, Mr. Johan Emil",male,25,1,0,347076,7.775,,S
1,444,Survived,2,"Reynaldo, Ms. Encarnacion",female,28,0,0,230434,13,,S
1,445,Survived,3,"Johannesen-Bratthammer, Mr. Bernt",male,,0,0,65306,8.1125,,S
1,446,Survived,1,"Dodge, Master. Washington",male,4,0,2,33638,81.8583,A34,S
1,447,Survived,2,"Mellinger, Miss. Madeleine Violet",female,13,0,1,250644,19.5,,S
1,448,Survived,1,"Seward, Mr. Frederic Kimber",male,34,0,0,113794,26.55,,S
1,449,Survived,3,"Baclini, Miss. Marie Catherine",female,5,2,1,2666,19.2583,,C
1,450,Survived,1,"Peuchen, Major. Arthur Godfrey",male,52,0,0,113786,30.5,C104,S
1,451,Died,2,"West, Mr. Edwy Arthur",male,36,1,2,C.A. 34651,27.75,,S
1,452,Died,3,"Hagland, Mr. Ingvald Olai Olsen",male,,1,0,65303,19.9667,,S
1,453,Died,1,"Foreman, Mr. Benjamin Laventall",male,30,0,0,113051,27.75,C111,C
1,454,Survived,1,"Goldenberg, Mr. Samuel L",male,49,1,0,17453,89.1042,C92,C
1,455,Died,3,"Peduzzi, Mr. Joseph",male,,0,0,A/5 2817,8.05,,S
1,456,Survived,3,"Jalsevac, Mr. Ivan",male,29,0,0,349240,7.8958,,C
1,457,Died,1,"Millet, Mr. Francis Davis",male,65,0,0,13509,26.55,E38,S
1,458,Survived,1,"Kenyon, Mrs. Frederick R (Marion)",female,,1,0,17464,51.8625,D21,S
1,459,Survived,2,"Toomey, Miss. Ellen",female,50,0,0,F.C.C. 13531,10.5,,S
1,460,Died,3,"O'Connor, Mr. Maurice",male,,0,0,371060,7.75,,Q
1,461,Survived,1,"Anderson, Mr. Harry",male,48,0,0,19952,26.55,E12,S
1,462,Died,3,"Morley, Mr. William",male,34,0,0,364506,8.05,,S
1,463,Died,1,"Gee, Mr. Arthur H",male,47,0,0,111320,38.5,E63,S
1,464,Died,2,"Milling, Mr. Jacob Christian",male,48,0,0,234360,13,,S
1,465,Died,3,"Maisner, Mr. Simon",male,,0,0,A/S 2816,8.05,,S
1,466,Died,3,"Goncalves, Mr. Manuel Estanslas",male,38,0,0,SOTON/O.Q. 3101306,7.05,,S
1,467,Died,2,"Campbell, Mr. William",male,,0,0,239853,0,,S
1,468,Died,1,"Smart, Mr. John Montgomery",male,56,0,0,113792,26.55,,S
1,469,Died,3,"Scanlan, Mr. James",male,,0,0,36209,7.725,,Q
1,470,Survived,3,"Baclini, Miss. Helene Barbara",female,0.75,2,1,2666,19.2583,,C
1,471,Died,3,"Keefe, Mr. Arthur",male,,0,0,323592,7.25,,S
1,472,Died,3,"Cacic, Mr. Luka",male,38,0,0,315089,8.6625,,S
1,473,Survived,2,"West, Mrs. Edwy Arthur (Ada Mary Worth)",female,33,1,2,C.A. 34651,27.75,,S
1,474,Survived,2,"Jerwan, Mrs. Amin S (Marie Marthe Thuillard)",female,23,0,0,SC/AH Basle 541,13.7917,D,C
1,475,Died,3,"Strandberg, Miss. Ida Sofia",female,22,0,0,7553,9.8375,,S
1,476,Died,1,"Clifford, Mr. George Quincy",male,,0,0,110465,52,A14,S
1,477,Died,2,"Renouf, Mr. Peter Henry",male,34,1,0,31027,21,,S
1,478,Died,3,"Braund, Mr. Lewis Richard",male,29,1,0,3460,7.0458,,S
1,479,Died,3,"Karlsson, Mr. Nils August",male,22,0,0,350060,7.5208,,S
1,480,Survived,3,"Hirvonen, Miss. Hildur E",female,2,0,1,3101298,12.2875,,S
1,481,Died,3,"Goodwin, Master. Harold Victor",male,9,5,2,CA 2144,46.9,,S
1,482,Died,2,"Frost, Mr. Anthony Wood ""Archie""",male,,0,0,239854,0,,S
1,483,Died,3,"Rouse, Mr. Richard Henry",male,50,0,0,A/5 3594,8.05,,S
1,484,Survived,3,"Turkula, Mrs. (Hedwig)",female,63,0,0,4134,9.5875,,S
1,485,Survived,1,"Bishop, Mr. Dickinson H",male,25,1,0,11967,91.0792,B49,C
1,486,Died,3,"Lefebre, Miss. Jeannie",female,,3,1,4133,25.4667,,S
1,487,Survived,1,"Hoyt, Mrs. Frederick Maxfield (Jane Anne Forby)",female,35,1,0,19943,90,C93,S
1,488,Died,1,"Kent, Mr. Edward Austin",male,58,0,0,11771,29.7,B37,C
1,489,Died,3,"Somerton, Mr. Francis William",male,30,0,0,A.5. 18509,8.05,,S
1,490,Survived,3,"Coutts, Master. Eden Leslie ""Neville""",male,9,1,1,C.A. 37671,15.9,,S
1,491,Died,3,"Hagland, Mr. Konrad Mathias Reiersen",male,,1,0,65304,19.9667,,S
1,492,Died,3,"Windelov, Mr. Einar",male,21,0,0,SOTON/OQ 3101317,7.25,,S
1,493,Died,1,"Molson, Mr. Harry Markland",male,55,0,0,113787,30.5,C30,S
1,494,Died,1,"Artagaveytia, Mr. Ramon",male,71,0,0,PC 17609,49.5042,,C
1,495,Died,3,"Stanley, Mr. Edward Roland",male,21,0,0,A/4 45380,8.05,,S
1,496,Died,3,"Yousseff, Mr. Gerious",male,,0,0,2627,14.4583,,C
1,497,Survived,1,"Eustis, Miss. Elizabeth Mussey",female,54,1,0,36947,78.2667,D20,C
1,498,Died,3,"Shellard, Mr. Frederick William",male,,0,0,C.A. 6212,15.1,,S
1,499,Died,1,"Allison, Mrs. Hudson J C (Bessie Waldo Daniels)",female,25,1,2,113781,151.55,C22 C26,S
1,500,Died,3,"Svensson, Mr. Olof",male,24,0,0,350035,7.7958,,S
1,501,Died,3,"Calic, Mr. Petar",male,17,0,0,315086,8.6625,,S
1,502,Died,3,"Canavan, Miss. Mary",female,21,0,0,364846,7.75,,Q
1,503,Died,3,"O'Sullivan, Miss. Bridget Mary",female,,0,0,330909,7.6292,,Q
1,504,Died,3,"Laitinen, Miss. Kristina Sofia",female,37,0,0,4135,9.5875,,S
1,505,Survived,1,"Maioni, Miss. Roberta",female,16,0,0,110152,86.5,B79,S
1,506,Died,1,"Penasco y Castellana, Mr. Victor de Satode",male,18,1,0,PC 17758,108.9,C65,C
1,507,Survived,2,"Quick, Mrs. Frederick Charles (Jane Richards)",female,33,0,2,26360,26,,S
1,508,Survived,1,"Bradley, Mr. George (""George Arthur Brayton"")",male,,0,0,111427,26.55,,S
1,509,Died,3,"Olsen, Mr. Henry Margido",male,28,0,0,C 4001,22.525,,S
1,510,Survived,3,"Lang, Mr. Fang",male,26,0,0,1601,56.4958,,S
1,511,Survived,3,"Daly, Mr. Eugene Patrick",male,29,0,0,382651,7.75,,Q
1,512,Died,3,"Webber, Mr. James",male,,0,0,SOTON/OQ 3101316,8.05,,S
1,513,Survived,1,"McGough, Mr. James Robert",male,36,0,0,PC 17473,26.2875,E25,S
1,514,Survived,1,"Rothschild, Mrs. Martin (Elizabeth L. Barrett)",female,54,1,0,PC 17603,59.4,,C
1,515,Died,3,"Coleff, Mr. Satio",male,24,0,0,349209,7.4958,,S
1,516,Died,1,"Walker, Mr. William Anderson",male,47,0,0,36967,34.0208,D46,S
1,517,Survived,2,"Lemore, Mrs. (Amelia Milley)",female,34,0,0,C.A. 34260,10.5,F33,S
1,518,Died,3,"Ryan, Mr. Patrick",male,,0,0,371110,24.15,,Q
1,519,Survived,2,"Angle, Mrs. William A (Florence ""Mary"" Agnes Hughes)",female,36,1,0,226875,26,,S
1,520,Died,3,"Pavlovic, Mr. Stefo",male,32,0,0,349242,7.8958,,S
1,521,Survived,1,"Perreault, Miss. Anne",female,30,0,0,12749,93.5,B73,S
1,522,Died,3,"Vovk, Mr. Janko",male,22,0,0,349252,7.8958,,S
1,523,Died,3,"Lahoud, Mr. Sarkis",male,,0,0,2624,7.225,,C
1,524,Survived,1,"Hippach, Mrs. Louis Albert (Ida Sophia Fischer)",female,44,0,1,111361,57.9792,B18,C
1,525,Died,3,"Kassem, Mr. Fared",male,,0,0,2700,7.2292,,C
1,526,Died,3,"Farrell, Mr. James",male,40.5,0,0,367232,7.75,,Q
1,527,Survived,2,"Ridsdale, Miss. Lucy",female,50,0,0,W./C. 14258,10.5,,S
1,528,Died,1,"Farthing, Mr. John",male,,0,0,PC 17483,221.7792,C95,S
1,529,Died,3,"Salonen, Mr. Johan Werner",male,39,0,0,3101296,7.925,,S
1,530,Died,2,"Hocking, Mr. Richard George",male,23,2,1,29104,11.5,,S
1,531,Survived,2,"Quick, Miss. Phyllis May",female,2,1,1,26360,26,,S
1,532,Died,3,"Toufik, Mr. Nakli",male,,0,0,2641,7.2292,,C
1,533,Died,3,"Elias, Mr. Joseph Jr",male,17,1,1,2690,7.2292,,C
1,534,Survived,3,"Peter, Mrs. Catherine (Catherine Rizk)",female,,0,2,2668,22.3583,,C
1,535,Died,3,"Cacic, Miss. Marija",female,30,0,0,315084,8.6625,,S
1,536,Survived,2,"Hart, Miss. Eva Miriam",female,7,0,2,F.C.C. 13529,26.25,,S
1,537,Died,1,"Butt, Major. Archibald Willingham",male,45,0,0,113050,26.55,B38,S
1,538,Survived,1,"LeRoy, Miss. Bertha",female,30,0,0,PC 17761,106.425,,C
1,539,Died,3,"Risien, Mr. Samuel Beard",male,,0,0,364498,14.5,,S
1,540,Survived,1,"Frolicher, Miss. Hedwig Margaritha",female,22,0,2,13568,49.5,B39,C
1,541,Survived,1,"Crosby, Miss. Harriet R",female,36,0,2,WE/P 5735,71,B22,S
1,542,Died,3,"Andersson, Miss. Ingeborg Constanzia",female,9,4,2,347082,31.275,,S
1,543,Died,3,"Andersson, Miss. Sigrid Elisabeth",female,11,4,2,347082,31.275,,S
1,544,Survived,2,"Beane, Mr. Edward",male,32,1,0,2908,26,,S
1,545,Died,1,"Douglas, Mr. Walter Donald",male,50,1,0,PC 17761,106.425,C86,C
1,546,Died,1,"Nicholson, Mr. Arthur Ernest",male,64,0,0,693,26,,S
1,547,Survived,2,"Beane, Mrs. Edward (Ethel Clarke)",female,19,1,0,2908,26,,S
1,548,Survived,2,"Padro y Manent, Mr. Julian",male,,0,0,SC/PARIS 2146,13.8625,,C
1,549,Died,3,"Goldsmith, Mr. Frank John",male,33,1,1,363291,20.525,,S
1,550,Survived,2,"Davies, Master. John Morgan Jr",male,8,1,1,C.A. 33112,36.75,,S
1,551,Survived,1,"Thayer, Mr. John Borland Jr",male,17,0,2,17421,110.8833,C70,C
1,552,Died,2,"Sharp, Mr. Percival James R",male,27,0,0,244358,26,,S
1,553,Died,3,"O'Brien, Mr. Timothy",male,,0,0,330979,7.8292,,Q
1,554,Survived,3,"Leeni, Mr. Fahim (""Philip Zenni"")",male,22,0,0,2620,7.225,,C
1,555,Survived,3,"Ohman, Miss. Velin",female,22,0,0,347085,7.775,,S
1,556,Died,1,"Wright, Mr. George",male,62,0,0,113807,26.55,,S
1,557,Survived,1,"Duff Gordon, Lady. (Lucille Christiana Sutherland) (""Mrs Morgan"")",female,48,1,0,11755,39.6,A16,C
1,558,Died,1,"Robbins, Mr. Victor",male,,0,0,PC 17757,227.525,,C
1,559,Survived,1,"Taussig, Mrs. Emil (Tillie Mandelbaum)",female,39,1,1,110413,79.65,E67,S
1,560,Survived,3,"de Messemaeker, Mrs. Guillaume Joseph (Emma)",female,36,1,0,345572,17.4,,S
1,561,Died,3,"Morrow, Mr. Thomas Rowan",male,,0,0,372622,7.75,,Q
1,562,Died,3,"Sivic, Mr. Husein",male,40,0,0,349251,7.8958,,S
1,563,Died,2,"Norman, Mr. Robert Douglas",male,28,0,0,218629,13.5,,S
1,564,Died,3,"Simmons, Mr. John",male,,0,0,SOTON/OQ 392082,8.05,,S
1,565,Died,3,"Meanwell, Miss. (Marion Ogden)",female,,0,0,SOTON/O.Q. 392087,8.05,,S
1,566,Died,3,"Davies, Mr. Alfred J",male,24,2,0,A/4 48871,24.15,,S
1,567,Died,3,"Stoytcheff, Mr. Ilia",male,19,0,0,349205,7.8958,,S
1,568,Died,3,"Palsson, Mrs. Nils (Alma Cornelia Berglund)",female,29,0,4,349909,21.075,,S
1,569,Died,3,"Doharr, Mr. Tannous",male,,0,0,2686,7.2292,,C
1,570,Survived,3,"Jonsson, Mr. Carl",male,32,0,0,350417,7.8542,,S
1,571,Survived,2,"Harris, Mr. George",male,62,0,0,S.W./PP 752,10.5,,S
1,572,Survived,1,"Appleton, Mrs. Edward Dale (Charlotte Lamson)",female,53,2,0,11769,51.4792,C101,S
1,573,Survived,1,"Flynn, Mr. John Irwin (""Irving"")",male,36,0,0,PC 17474,26.3875,E25,S
1,574,Survived,3,"Kelly, Miss. Mary",female,,0,0,14312,7.75,,Q
1,575,Died,3,"Rush, Mr. Alfred George John",male,16,0,0,A/4. 20589,8.05,,S
1,576,Died,3,"Patchett, Mr. George",male,19,0,0,358585,14.5,,S
1,577,Survived,2,"Garside, Miss. Ethel",female,34,0,0,243880,13,,S
1,578,Survived,1,"Silvey, Mrs. William Baird (Alice Munger)",female,39,1,0,13507,55.9,E44,S
1,579,Died,3,"Caram, Mrs. Joseph (Maria Elias)",female,,1,0,2689,14.4583,,C
1,580,Survived,3,"Jussila, Mr. Eiriik",male,32,0,0,STON/O 2. 3101286,7.925,,S
1,581,Survived,2,"Christy, Miss. Julie Rachel",female,25,1,1,237789,30,,S
1,582,Survived,1,"Thayer, Mrs. John Borland (Marian Longstreth Morris)",female,39,1,1,17421,110.8833,C68,C
1,583,Died,2,"Downton, Mr. William James",male,54,0,0,28403,26,,S
1,584,Died,1,"Ross, Mr. John Hugo",male,36,0,0,13049,40.125,A10,C
1,585,Died,3,"Paulner, Mr. Uscher",male,,0,0,3411,8.7125,,C
1,586,Survived,1,"Taussig, Miss. Ruth",female,18,0,2,110413,79.65,E68,S
1,587,Died,2,"Jarvis, Mr. John Denzil",male,47,0,0,237565,15,,S
1,588,Survived,1,"Frolicher-Stehli, Mr. Maxmillian",male,60,1,1,13567,79.2,B41,C
1,589,Died,3,"Gilinski, Mr. Eliezer",male,22,0,0,14973,8.05,,S
1,590,Died,3,"Murdlin, Mr. Joseph",male,,0,0,A./5. 3235,8.05,,S
1,591,Died,3,"Rintamaki, Mr. Matti",male,35,0,0,STON/O 2. 3101273,7.125,,S
1,592,Survived,1,"Stephenson, Mrs. Walter Bertram (Martha Eustis)",female,52,1,0,36947,78.2667,D20,C
1,593,Died,3,"Elsbury, Mr. William James",male,47,0,0,A/5 3902,7.25,,S
1,594,Died,3,"Bourke, Miss. Mary",female,,0,2,364848,7.75,,Q
1,595,Died,2,"Chapman, Mr. John Henry",male,37,1,0,SC/AH 29037,26,,S
1,596,Died,3,"Van Impe, Mr. Jean Baptiste",male,36,1,1,345773,24.15,,S
1,597,Survived,2,"Leitch, Miss. Jessie Wills",female,,0,0,248727,33,,S
1,598,Died,3,"Johnson, Mr. Alfred",male,49,0,0,LINE,0,,S
1,599,Died,3,"Boulos, Mr. Hanna",male,,0,0,2664,7.225,,C
1,600,Survived,1,"Duff Gordon, Sir. Cosmo Edmund (""Mr Morgan"")",male,49,1,0,PC 17485,56.9292,A20,C
1,601,Survived,2,"Jacobsohn, Mrs. Sidney Samuel (Amy Frances Christy)",female,24,2,1,243847,27,,S
1,602,Died,3,"Slabenoff, Mr. Petco",male,,0,0,349214,7.8958,,S
1,603,Died,1,"Harrington, Mr. Charles H",male,,0,0,113796,42.4,,S
1,604,Died,3,"Torber, Mr. Ernst William",male,44,0,0,364511,8.05,,S
1,605,Survived,1,"Homer, Mr. Harry (""Mr E Haven"")",male,35,0,0,111426,26.55,,C
1,606,Died,3,"Lindell, Mr. Edvard Bengtsson",male,36,1,0,349910,15.55,,S
1,607,Died,3,"Karaic, Mr. Milan",male,30,0,0,349246,7.8958,,S
1,608,Survived,1,"Daniel, Mr. Robert Williams",male,27,0,0,113804,30.5,,S
1,609,Survived,2,"Laroche, Mrs. Joseph (Juliette Marie Louise Lafargue)",female,22,1,2,SC/Paris 2123,41.5792,,C
1,610,Survived,1,"Shutes, Miss. Elizabeth W",female,40,0,0,PC 17582,153.4625,C125,S
1,611,Died,3,"Andersson, Mrs. Anders Johan (Alfrida Konstantia Brogren)",female,39,1,5,347082,31.275,,S
1,612,Died,3,"Jardin, Mr. Jose Neto",male,,0,0,SOTON/O.Q. 3101305,7.05,,S
1,613,Survived,3,"Murphy, Miss. Margaret Jane",female,,1,0,367230,15.5,,Q
1,614,Died,3,"Horgan, Mr. John",male,,0,0,370377,7.75,,Q
1,615,Died,3,"Brocklebank, Mr. William Alfred",male,35,0,0,364512,8.05,,S
1,616,Survived,2,"Herman, Miss. Alice",female,24,1,2,220845,65,,S
1,617,Died,3,"Danbom, Mr. Ernst Gilbert",male,34,1,1,347080,14.4,,S
1,618,Died,3,"Lobb, Mrs. William Arthur (Cordelia K Stanlick)",female,26,1,0,A/5. 3336,16.1,,S
1,619,Survived,2,"Becker, Miss. Marion Louise",female,4,2,1,230136,39,F4,S
1,620,Died,2,"Gavey, Mr. Lawrence",male,26,0,0,31028,10.5,,S
1,621,Died,3,"Yasbeck, Mr. Antoni",male,27,1,0,2659,14.4542,,C
1,622,Survived,1,"Kimball, Mr. Edwin Nelson Jr",male,42,1,0,11753,52.5542,D19,S
1,623,Survived,3,"Nakid, Mr. Sahid",male,20,1,1,2653,15.7417,,C
1,624,Died,3,"Hansen, Mr. Henry Damsgaard",male,21,0,0,350029,7.8542,,S
1,625,Died,3,"Bowen, Mr. David John ""Dai""",male,21,0,0,54636,16.1,,S
1,626,Died,1,"Sutton, Mr. Frederick",male,61,0,0,36963,32.3208,D50,S
1,627,Died,2,"Kirkland, Rev. Charles Leonard",male,57,0,0,219533,12.35,,Q
1,628,Survived,1,"Longley, Miss. Gretchen Fiske",female,21,0,0,13502,77.9583,D9,S
1,629,Died,3,"Bostandyeff, Mr. Guentcho",male,26,0,0,349224,7.8958,,S
1,630,Died,3,"O'Connell, Mr. Patrick D",male,,0,0,334912,7.7333,,Q
1,631,Survived,1,"Barkworth, Mr. Algernon Henry Wilson",male,80,0,0,27042,30,A23,S
1,632,Died,3,"Lundahl, Mr. Johan Svensson",male,51,0,0,347743,7.0542,,S
1,633,Survived,1,"Stahelin-Maeglin, Dr. Max",male,32,0,0,13214,30.5,B50,C
1,634,Died,1,"Parr, Mr. William Henry Marsh",male,,0,0,112052,0,,S
1,635,Died,3,"Skoog, Miss. Mabel",female,9,3,2,347088,27.9,,S
1,636,Survived,2,"Davis, Miss. Mary",female,28,0,0,237668,13,,S
1,637,Died,3,"Leinonen, Mr. Antti Gustaf",male,32,0,0,STON/O 2. 3101292,7.925,,S
1,638,Died,2,"Collyer, Mr. Harvey",male,31,1,1,C.A. 31921,26.25,,S
1,639,Died,3,"Panula, Mrs. Juha (Maria Emilia Ojala)",female,41,0,5,3101295,39.6875,,S
1,640,Died,3,"Thorneycroft, Mr. Percival",male,,1,0,376564,16.1,,S
1,641,Died,3,"Jensen, Mr. Hans Peder",male,20,0,0,350050,7.8542,,S
1,642,Survived,1,"Sagesser, Mlle. Emma",female,24,0,0,PC 17477,69.3,B35,C
1,643,Died,3,"Skoog, Miss. Margit Elizabeth",female,2,3,2,347088,27.9,,S
1,644,Survived,3,"Foo, Mr. Choong",male,,0,0,1601,56.4958,,S
1,645,Survived,3,"Baclini, Miss. Eugenie",female,0.75,2,1,2666,19.2583,,C
1,646,Survived,1,"Harper, Mr. Henry Sleeper",male,48,1,0,PC 17572,76.7292,D33,C
1,647,Died,3,"Cor, Mr. Liudevit",male,19,0,0,349231,7.8958,,S
1,648,Survived,1,"Simonius-Blumer, Col. Oberst Alfons",male,56,0,0,13213,35.5,A26,C
1,649,Died,3,"Willey, Mr. Edward",male,,0,0,S.O./P.P. 751,7.55,,S
1,650,Survived,3,"Stanley, Miss. Amy Zillah Elsie",female,23,0,0,CA. 2314,7.55,,S
1,651,Died,3,"Mitkoff, Mr. Mito",male,,0,0,349221,7.8958,,S
1,652,Survived,2,"Doling, Miss. Elsie",female,18,0,1,231919,23,,S
1,653,Died,3,"Kalvik, Mr. Johannes Halvorsen",male,21,0,0,8475,8.4333,,S
1,654,Survived,3,"O'Leary, Miss. Hanora ""Norah""",female,,0,0,330919,7.8292,,Q
1,655,Died,3,"Hegarty, Miss. Hanora ""Nora""",female,18,0,0,365226,6.75,,Q
1,656,Died,2,"Hickman, Mr. Leonard Mark",male,24,2,0,S.O.C. 14879,73.5,,S
1,657,Died,3,"Radeff, Mr. Alexander",male,,0,0,349223,7.8958,,S
1,658,Died,3,"Bourke, Mrs. John (Catherine)",female,32,1,1,364849,15.5,,Q
1,659,Died,2,"Eitemiller, Mr. George Floyd",male,23,0,0,29751,13,,S
1,660,Died,1,"Newell, Mr. Arthur Webster",male,58,0,2,35273,113.275,D48,C
1,661,Survived,1,"Frauenthal, Dr. Henry William",male,50,2,0,PC 17611,133.65,,S
1,662,Died,3,"Badt, Mr. Mohamed",male,40,0,0,2623,7.225,,C
1,663,Died,1,"Colley, Mr. Edward Pomeroy",male,47,0,0,5727,25.5875,E58,S
1,664,Died,3,"Coleff, Mr. Peju",male,36,0,0,349210,7.4958,,S
1,665,Survived,3,"Lindqvist, Mr. Eino William",male,20,1,0,STON/O 2. 3101285,7.925,,S
1,666,Died,2,"Hickman, Mr. Lewis",male,32,2,0,S.O.C. 14879,73.5,,S
1,667,Died,2,"Butler, Mr. Reginald Fenton",male,25,0,0,234686,13,,S
1,668,Died,3,"Rommetvedt, Mr. Knud Paust",male,,0,0,312993,7.775,,S
1,669,Died,3,"Cook, Mr. Jacob",male,43,0,0,A/5 3536,8.05,,S
1,670,Survived,1,"Taylor, Mrs. Elmer Zebley (Juliet Cummins Wright)",female,,1,0,19996,52,C126,S
1,671,Survived,2,"Brown, Mrs. Thomas William Solomon (Elizabeth Catherine Ford)",female,40,1,1,29750,39,,S
1,672,Died,1,"Davidson, Mr. Thornton",male,31,1,0,F.C. 12750,52,B71,S
1,673,Died,2,"Mitchell, Mr. Henry Michael",male,70,0,0,C.A. 24580,10.5,,S
1,674,Survived,2,"Wilhelms, Mr. Charles",male,31,0,0,244270,13,,S
1,675,Died,2,"Watson, Mr. Ennis Hastings",male,,0,0,239856,0,,S
1,676,Died,3,"Edvardsson, Mr. Gustaf Hjalmar",male,18,0,0,349912,7.775,,S
1,677,Died,3,"Sawyer, Mr. Frederick Charles",male,24.5,0,0,342826,8.05,,S
1,678,Survived,3,"Turja, Miss. Anna Sofia",female,18,0,0,4138,9.8417,,S
1,679,Died,3,"Goodwin, Mrs. Frederick (Augusta Tyler)",female,43,1,6,CA 2144,46.9,,S
1,680,Survived,1,"Cardeza, Mr. Thomas Drake Martinez",male,36,0,1,PC 17755,512.3292,B51 B53 B55,C
1,681,Died,3,"Peters, Miss. Katie",female,,0,0,330935,8.1375,,Q
1,682,Survived,1,"Hassab, Mr. Hammad",male,27,0,0,PC 17572,76.7292,D49,C
1,683,Died,3,"Olsvigen, Mr. Thor Anderson",male,20,0,0,6563,9.225,,S
1,684,Died,3,"Goodwin, Mr. Charles Edward",male,14,5,2,CA 2144,46.9,,S
1,685,Died,2,"Brown, Mr. Thomas William Solomon",male,60,1,1,29750,39,,S
1,686,Died,2,"Laroche, Mr. Joseph Philippe Lemercier",male,25,1,2,SC/Paris 2123,41.5792,,C
1,687,Died,3,"Panula, Mr. Jaako Arnold",male,14,4,1,3101295,39.6875,,S
1,688,Died,3,"Dakic, Mr. Branko",male,19,0,0,349228,10.1708,,S
1,689,Died,3,"Fischer, Mr. Eberhard Thelander",male,18,0,0,350036,7.7958,,S
1,690,Survived,1,"Madill, Miss. Georgette Alexandra",female,15,0,1,24160,211.3375,B5,S
1,691,Survived,1,"Dick, Mr. Albert Adrian",male,31,1,0,17474,57,B20,S
1,692,Survived,3,"Karun, Miss. Manca",female,4,0,1,349256,13.4167,,C
1,693,Survived,3,"Lam, Mr. Ali",male,,0,0,1601,56.4958,,S
1,694,Died,3,"Saad, Mr. Khalil",male,25,0,0,2672,7.225,,C
1,695,Died,1,"Weir, Col. John",male,60,0,0,113800,26.55,,S
1,696,Died,2,"Chapman, Mr. Charles Henry",male,52,0,0,248731,13.5,,S
1,697,Died,3,"Kelly, Mr. James",male,44,0,0,363592,8.05,,S
1,698,Survived,3,"Mullens, Miss. Katherine ""Katie""",female,,0,0,35852,7.7333,,Q
1,699,Died,1,"Thayer, Mr. John Borland",male,49,1,1,17421,110.8833,C68,C
1,700,Died,3,"Humblen, Mr. Adolf Mathias Nicolai Olsen",male,42,0,0,348121,7.65,F G63,S
1,701,Survived,1,"Astor, Mrs. John Jacob (Madeleine Talmadge Force)",female,18,1,0,PC 17757,227.525,C62 C64,C
1,702,Survived,1,"Silverthorne, Mr. Spencer Victor",male,35,0,0,PC 17475,26.2875,E24,S
1,703,Died,3,"Barbara, Miss. Saiide",female,18,0,1,2691,14.4542,,C
1,704,Died,3,"Gallagher, Mr. Martin",male,25,0,0,36864,7.7417,,Q
1,705,Died,3,"Hansen, Mr. Henrik Juul",male,26,1,0,350025,7.8542,,S
1,706,Died,2,"Morley, Mr. Henry Samuel (""Mr Henry Marshall"")",male,39,0,0,250655,26,,S
1,707,Survived,2,"Kelly, Mrs. Florence ""Fannie""",female,45,0,0,223596,13.5,,S
1,708,Survived,1,"Calderhead, Mr. Edward Pennington",male,42,0,0,PC 17476,26.2875,E24,S
1,709,Survived,1,"Cleaver, Miss. Alice",female,22,0,0,113781,151.55,,S
1,710,Survived,3,"Moubarek, Master. Halim Gonios (""William George"")",male,,1,1,2661,15.2458,,C
1,711,Survived,1,"Mayne, Mlle. Berthe Antonine (""Mrs de Villiers"")",female,24,0,0,PC 17482,49.5042,C90,C
1,712,Died,1,"Klaber, Mr. Herman",male,,0,0,113028,26.55,C124,S
1,713,Survived,1,"Taylor, Mr. Elmer Zebley",male,48,1,0,19996,52,C126,S
1,714,Died,3,"Larsson, Mr. August Viktor",male,29,0,0,7545,9.4833,,S
1,715,Died,2,"Greenberg, Mr. Samuel",male,52,0,0,250647,13,,S
1,716,Died,3,"Soholt, Mr. Peter Andreas Lauritz Andersen",male,19,0,0,348124,7.65,F G73,S
1,717,Survived,1,"Endres, Miss. Caroline Louise",female,38,0,0,PC 17757,227.525,C45,C
1,718,Survived,2,"Troutt, Miss. Edwina Celia ""Winnie""",female,27,0,0,34218,10.5,E101,S
1,719,Died,3,"McEvoy, Mr. Michael",male,,0,0,36568,15.5,,Q
1,720,Died,3,"Johnson, Mr. Malkolm Joackim",male,33,0,0,347062,7.775,,S
1,721,Survived,2,"Harper, Miss. Annie Jessie ""Nina""",female,6,0,1,248727,33,,S
1,722,Died,3,"Jensen, Mr. Svend Lauritz",male,17,1,0,350048,7.0542,,S
1,723,Died,2,"Gillespie, Mr. William Henry",male,34,0,0,12233,13,,S
1,724,Died,2,"Hodges, Mr. Henry Price",male,50,0,0,250643,13,,S
1,725,Survived,1,"Chambers, Mr. Norman Campbell",male,27,1,0,113806,53.1,E8,S
1,726,Died,3,"Oreskovic, Mr. Luka",male,20,0,0,315094,8.6625,,S
1,727,Survived,2,"Renouf, Mrs. Peter Henry (Lillian Jefferys)",female,30,3,0,31027,21,,S
1,728,Survived,3,"Mannion, Miss. Margareth",female,,0,0,36866,7.7375,,Q
1,729,Died,2,"Bryhl, Mr. Kurt Arnold Gottfrid",male,25,1,0,236853,26,,S
1,730,Died,3,"Ilmakangas, Miss. Pieta Sofia",female,25,1,0,STON/O2. 3101271,7.925,,S
1,731,Survived,1,"Allen, Miss. Elisabeth Walton",female,29,0,0,24160,211.3375,B5,S
1,732,Died,3,"Hassan, Mr. Houssein G N",male,11,0,0,2699,18.7875,,C
1,733,Died,2,"Knight, Mr. Robert J",male,,0,0,239855,0,,S
1,734,Died,2,"Berriman, Mr. William John",male,23,0,0,28425,13,,S
1,735,Died,2,"Troupiansky, Mr. Moses Aaron",male,23,0,0,233639,13,,S
1,736,Died,3,"Williams, Mr. Leslie",male,28.5,0,0,54636,16.1,,S
1,737,Died,3,"Ford, Mrs. Edward (Margaret Ann Watson)",female,48,1,3,W./C. 6608,34.375,,S
1,738,Survived,1,"Lesurer, Mr. Gustave J",male,35,0,0,PC 17755,512.3292,B101,C
1,739,Died,3,"Ivanoff, Mr. Kanio",male,,0,0,349201,7.8958,,S
1,740,Died,3,"Nankoff, Mr. Minko",male,,0,0,349218,7.8958,,S
1,741,Survived,1,"Hawksford, Mr. Walter James",male,,0,0,16988,30,D45,S
1,742,Died,1,"Cavendish, Mr. Tyrell William",male,36,1,0,19877,78.85,C46,S
1,743,Survived,1,"Ryerson, Miss. Susan Parker ""Suzette""",female,21,2,2,PC 17608,262.375,B57 B59 B63 B66,C
1,744,Died,3,"McNamee, Mr. Neal",male,24,1,0,376566,16.1,,S
1,745,Survived,3,"Stranden, Mr. Juho",male,31,0,0,STON/O 2. 3101288,7.925,,S
1,746,Died,1,"Crosby, Capt. Edward Gifford",male,70,1,1,WE/P 5735,71,B22,S
1,747,Died,3,"Abbott, Mr. Rossmore Edward",male,16,1,1,C.A. 2673,20.25,,S
1,748,Survived,2,"Sinkkonen, Miss. Anna",female,30,0,0,250648,13,,S
1,749,Died,1,"Marvin, Mr. Daniel Warner",male,19,1,0,113773,53.1,D30,S
1,750,Died,3,"Connaghton, Mr. Michael",male,31,0,0,335097,7.75,,Q
1,751,Survived,2,"Wells, Miss. Joan",female,4,1,1,29103,23,,S
1,752,Survived,3,"Moor, Master. Meier",male,6,0,1,392096,12.475,E121,S
1,753,Died,3,"Vande Velde, Mr. Johannes Joseph",male,33,0,0,345780,9.5,,S
1,754,Died,3,"Jonkoff, Mr. Lalio",male,23,0,0,349204,7.8958,,S
1,755,Survived,2,"Herman, Mrs. Samuel (Jane Laver)",female,48,1,2,220845,65,,S
1,756,Survived,2,"Hamalainen, Master. Viljo",male,0.67,1,1,250649,14.5,,S
1,757,Died,3,"Carlsson, Mr. August Sigfrid",male,28,0,0,350042,7.7958,,S
1,758,Died,2,"Bailey, Mr. Percy Andrew",male,18,0,0,29108,11.5,,S
1,759,Died,3,"Theobald, Mr. Thomas Leonard",male,34,0,0,363294,8.05,,S
1,760,Survived,1,"Rothes, the Countess. of (Lucy Noel Martha Dyer-Edwards)",female,33,0,0,110152,86.5,B77,S
1,761,Died,3,"Garfirth, Mr. John",male,,0,0,358585,14.5,,S
1,762,Died,3,"Nirva, Mr. Iisakki Antino Aijo",male,41,0,0,SOTON/O2 3101272,7.125,,S
1,763,Survived,3,"Barah, Mr. Hanna Assi",male,20,0,0,2663,7.2292,,C
1,764,Survived,1,"Carter, Mrs. William Ernest (Lucile Polk)",female,36,1,2,113760,120,B96 B98,S
1,765,Died,3,"Eklund, Mr. Hans Linus",male,16,0,0,347074,7.775,,S
1,766,Survived,1,"Hogeboom, Mrs. John C (Anna Andrews)",female,51,1,0,13502,77.9583,D11,S
1,767,Died,1,"Brewe, Dr. Arthur Jackson",male,,0,0,112379,39.6,,C
1,768,Died,3,"Mangan, Miss. Mary",female,30.5,0,0,364850,7.75,,Q
1,769,Died,3,"Moran, Mr. Daniel J",male,,1,0,371110,24.15,,Q
1,770,Died,3,"Gronnestad, Mr. Daniel Danielsen",male,32,0,0,8471,8.3625,,S
1,771,Died,3,"Lievens, Mr. Rene Aime",male,24,0,0,345781,9.5,,S
1,772,Died,3,"Jensen, Mr. Niels Peder",male,48,0,0,350047,7.8542,,S
1,773,Died,2,"Mack, Mrs. (Mary)",female,57,0,0,S.O./P.P. 3,10.5,E77,S
1,774,Died,3,"Elias, Mr. Dibo",male,,0,0,2674,7.225,,C
1,775,Survived,2,"Hocking, Mrs. Elizabeth (Eliza Needs)",female,54,1,3,29105,23,,S
1,776,Died,3,"Myhrman, Mr. Pehr Fabian Oliver Malkolm",male,18,0,0,347078,7.75,,S
1,777,Died,3,"Tobin, Mr. Roger",male,,0,0,383121,7.75,F38,Q
1,778,Survived,3,"Emanuel, Miss. Virginia Ethel",female,5,0,0,364516,12.475,,S
1,779,Died,3,"Kilgannon, Mr. Thomas J",male,,0,0,36865,7.7375,,Q
1,780,Survived,1,"Robert, Mrs. Edward Scott (Elisabeth Walton McMillan)",female,43,0,1,24160,211.3375,B3,S
1,781,Survived,3,"Ayoub, Miss. Banoura",female,13,0,0,2687,7.2292,,C
1,782,Survived,1,"Dick, Mrs. Albert Adrian (Vera Gillespie)",female,17,1,0,17474,57,B20,S
1,783,Died,1,"Long, Mr. Milton Clyde",male,29,0,0,113501,30,D6,S
1,784,Died,3,"Johnston, Mr. Andrew G",male,,1,2,W./C. 6607,23.45,,S
1,785,Died,3,"Ali, Mr. William",male,25,0,0,SOTON/O.Q. 3101312,7.05,,S
1,786,Died,3,"Harmer, Mr. Abraham (David Lishin)",male,25,0,0,374887,7.25,,S
1,787,Survived,3,"Sjoblom, Miss. Anna Sofia",female,18,0,0,3101265,7.4958,,S
1,788,Died,3,"Rice, Master. George Hugh",male,8,4,1,382652,29.125,,Q
1,789,Survived,3,"Dean, Master. Bertram Vere",male,1,1,2,C.A. 2315,20.575,,S
1,790,Died,1,"Guggenheim, Mr. Benjamin",male,46,0,0,PC 17593,79.2,B82 B84,C
1,791,Died,3,"Keane, Mr. Andrew ""Andy""",male,,0,0,12460,7.75,,Q
1,792,Died,2,"Gaskell, Mr. Alfred",male,16,0,0,239865,26,,S
1,793,Died,3,"Sage, Miss. Stella Anna",female,,8,2,CA. 2343,69.55,,S
1,794,Died,1,"Hoyt, Mr. William Fisher",male,,0,0,PC 17600,30.6958,,C
1,795,Died,3,"Dantcheff, Mr. Ristiu",male,25,0,0,349203,7.8958,,S
1,796,Died,2,"Otter, Mr. Richard",male,39,0,0,28213,13,,S
1,797,Survived,1,"Leader, Dr. Alice (Farnham)",female,49,0,0,17465,25.9292,D17,S
1,798,Survived,3,"Osman, Mrs. Mara",female,31,0,0,349244,8.6833,,S
1,799,Died,3,"Ibrahim Shawah, Mr. Yousseff",male,30,0,0,2685,7.2292,,C
1,800,Died,3,"Van Impe, Mrs. Jean Baptiste (Rosalie Paula Govaert)",female,30,1,1,345773,24.15,,S
1,801,Died,2,"Ponesell, Mr. Martin",male,34,0,0,250647,13,,S
1,802,Survived,2,"Collyer, Mrs. Harvey (Charlotte Annie Tate)",female,31,1,1,C.A. 31921,26.25,,S
1,803,Survived,1,"Carter, Master. William Thornton II",male,11,1,2,113760,120,B96 B98,S
1,804,Survived,3,"Thomas, Master. Assad Alexander",male,0.42,0,1,2625,8.5167,,C
1,805,Survived,3,"Hedman, Mr. Oskar Arvid",male,27,0,0,347089,6.975,,S
1,806,Died,3,"Johansson, Mr. Karl Johan",male,31,0,0,347063,7.775,,S
1,807,Died,1,"Andrews, Mr. Thomas Jr",male,39,0,0,112050,0,A36,S
1,808,Died,3,"Pettersson, Miss. Ellen Natalia",female,18,0,0,347087,7.775,,S
1,809,Died,2,"Meyer, Mr. August",male,39,0,0,248723,13,,S
1,810,Survived,1,"Chambers, Mrs. Norman Campbell (Bertha Griggs)",female,33,1,0,113806,53.1,E8,S
1,811,Died,3,"Alexander, Mr. William",male,26,0,0,3474,7.8875,,S
1,812,Died,3,"Lester, Mr. James",male,39,0,0,A/4 48871,24.15,,S
1,813,Died,2,"Slemen, Mr. Richard James",male,35,0,0,28206,10.5,,S
1,814,Died,3,"Andersson, Miss. Ebba Iris Alfrida",female,6,4,2,347082,31.275,,S
1,815,Died,3,"Tomlin, Mr. Ernest Portage",male,30.5,0,0,364499,8.05,,S
1,816,Died,1,"Fry, Mr. Richard",male,,0,0,112058,0,B102,S
1,817,Died,3,"Heininen, Miss. Wendla Maria",female,23,0,0,STON/O2. 3101290,7.925,,S
1,818,Died,2,"Mallet, Mr. Albert",male,31,1,1,S.C./PARIS 2079,37.0042,,C
1,819,Died,3,"Holm, Mr. John Fredrik Alexander",male,43,0,0,C 7075,6.45,,S
1,820,Died,3,"Skoog, Master. Karl Thorsten",male,10,3,2,347088,27.9,,S
1,821,Survived,1,"Hays, Mrs. Charles Melville (Clara Jennings Gregg)",female,52,1,1,12749,93.5,B69,S
1,822,Survived,3,"Lulic, Mr. Nikola",male,27,0,0,315098,8.6625,,S
1,823,Died,1,"Reuchlin, Jonkheer. John George",male,38,0,0,19972,0,,S
1,824,Survived,3,"Moor, Mrs. (Beila)",female,27,0,1,392096,12.475,E121,S
1,825,Died,3,"Panula, Master. Urho Abraham",male,2,4,1,3101295,39.6875,,S
1,826,Died,3,"Flynn, Mr. John",male,,0,0,368323,6.95,,Q
1,827,Died,3,"Lam, Mr. Len",male,,0,0,1601,56.4958,,S
1,828,Survived,2,"Mallet, Master. Andre",male,1,0,2,S.C./PARIS 2079,37.0042,,C
1,829,Survived,3,"McCormack, Mr. Thomas Joseph",male,,0,0,367228,7.75,,Q
1,830,Survived,1,"Stone, Mrs. George Nelson (Martha Evelyn)",female,62,0,0,113572,80,B28,
1,831,Survived,3,"Yasbeck, Mrs. Antoni (Selini Alexander)",female,15,1,0,2659,14.4542,,C
1,832,Survived,2,"Richards, Master. George Sibley",male,0.83,1,1,29106,18.75,,S
1,833,Died,3,"Saad, Mr. Amin",male,,0,0,2671,7.2292,,C
1,834,Died,3,"Augustsson, Mr. Albert",male,23,0,0,347468,7.8542,,S
1,835,Died,3,"Allum, Mr. Owen George",male,18,0,0,2223,8.3,,S
1,836,Survived,1,"Compton, Miss. Sara Rebecca",female,39,1,1,PC 17756,83.1583,E49,C
1,837,Died,3,"Pasic, Mr. Jakob",male,21,0,0,315097,8.6625,,S
1,838,Died,3,"Sirota, Mr. Maurice",male,,0,0,392092,8.05,,S
1,839,Survived,3,"Chip, Mr. Chang",male,32,0,0,1601,56.4958,,S
1,840,Survived,1,"Marechal, Mr. Pierre",male,,0,0,11774,29.7,C47,C
1,841,Died,3,"Alhomaki, Mr. Ilmari Rudolf",male,20,0,0,SOTON/O2 3101287,7.925,,S
1,842,Died,2,"Mudd, Mr. Thomas Charles",male,16,0,0,S.O./P.P. 3,10.5,,S
1,843,Survived,1,"Serepeca, Miss. Augusta",female,30,0,0,113798,31,,C
1,844,Died,3,"Lemberopolous, Mr. Peter L",male,34.5,0,0,2683,6.4375,,C
1,845,Died,3,"Culumovic, Mr. Jeso",male,17,0,0,315090,8.6625,,S
1,846,Died,3,"Abbing, Mr. Anthony",male,42,0,0,C.A. 5547,7.55,,S
1,847,Died,3,"Sage, Mr. Douglas Bullen",male,,8,2,CA. 2343,69.55,,S
1,848,Died,3,"Markoff, Mr. Marin",male,35,0,0,349213,7.8958,,C
1,849,Died,2,"Harper, Rev. John",male,28,0,1,248727,33,,S
1,850,Survived,1,"Goldenberg, Mrs. Samuel L (Edwiga Grabowska)",female,,1,0,17453,89.1042,C92,C
1,851,Died,3,"Andersson, Master. Sigvard Harald Elias",male,4,4,2,347082,31.275,,S
1,852,Died,3,"Svensson, Mr. Johan",male,74,0,0,347060,7.775,,S
1,853,Died,3,"Boulos, Miss. Nourelain",female,9,1,1,2678,15.2458,,C
1,854,Survived,1,"Lines, Miss. Mary Conover",female,16,0,1,PC 17592,39.4,D28,S
1,855,Died,2,"Carter, Mrs. Ernest Courtenay (Lilian Hughes)",female,44,1,0,244252,26,,S
1,856,Survived,3,"Aks, Mrs. Sam (Leah Rosen)",female,18,0,1,392091,9.35,,S
1,857,Survived,1,"Wick, Mrs. George Dennick (Mary Hitchcock)",female,45,1,1,36928,164.8667,,S
1,858,Survived,1,"Daly, Mr. Peter Denis ",male,51,0,0,113055,26.55,E17,S
1,859,Survived,3,"Baclini, Mrs. Solomon (Latifa Qurban)",female,24,0,3,2666,19.2583,,C
1,860,Died,3,"Razi, Mr. Raihed",male,,0,0,2629,7.2292,,C
1,861,Died,3,"Hansen, Mr. Claus Peter",male,41,2,0,350026,14.1083,,S
1,862,Died,2,"Giles, Mr. Frederick Edward",male,21,1,0,28134,11.5,,S
1,863,Survived,1,"Swift, Mrs. Frederick Joel (Margaret Welles Barron)",female,48,0,0,17466,25.9292,D17,S
1,864,Died,3,"Sage, Miss. Dorothy Edith ""Dolly""",female,,8,2,CA. 2343,69.55,,S
1,865,Died,2,"Gill, Mr. John William",male,24,0,0,233866,13,,S
1,866,Survived,2,"Bystrom, Mrs. (Karolina)",female,42,0,0,236852,13,,S
1,867,Survived,2,"Duran y More, Miss. Asuncion",female,27,1,0,SC/PARIS 2149,13.8583,,C
1,868,Died,1,"Roebling, Mr. Washington Augustus II",male,31,0,0,PC 17590,50.4958,A24,S
1,869,Died,3,"van Melkebeke, Mr. Philemon",male,,0,0,345777,9.5,,S
1,870,Survived,3,"Johnson, Master. Harold Theodor",male,4,1,1,347742,11.1333,,S
1,871,Died,3,"Balkic, Mr. Cerin",male,26,0,0,349248,7.8958,,S
1,872,Survived,1,"Beckwith, Mrs. Richard Leonard (Sallie Monypeny)",female,47,1,1,11751,52.5542,D35,S
1,873,Died,1,"Carlsson, Mr. Frans Olof",male,33,0,0,695,5,B51 B53 B55,S
1,874,Died,3,"Vander Cruyssen, Mr. Victor",male,47,0,0,345765,9,,S
1,875,Survived,2,"Abelson, Mrs. Samuel (Hannah Wizosky)",female,28,1,0,P/PP 3381,24,,C
1,876,Survived,3,"Najib, Miss. Adele Kiamie ""Jane""",female,15,0,0,2667,7.225,,C
1,877,Died,3,"Gustafsson, Mr. Alfred Ossian",male,20,0,0,7534,9.8458,,S
1,878,Died,3,"Petroff, Mr. Nedelio",male,19,0,0,349212,7.8958,,S
1,879,Died,3,"Laleff, Mr. Kristo",male,,0,0,349217,7.8958,,S
1,880,Survived,1,"Potter, Mrs. Thomas Jr (Lily Alexenia Wilson)",female,56,0,1,11767,83.1583,C50,C
1,881,Survived,2,"Shelley, Mrs. William (Imanita Parrish Hall)",female,25,0,1,230433,26,,S
1,882,Died,3,"Markun, Mr. Johann",male,33,0,0,349257,7.8958,,S
1,883,Died,3,"Dahlberg, Miss. Gerda Ulrika",female,22,0,0,7552,10.5167,,S
1,884,Died,2,"Banfield, Mr. Frederick James",male,28,0,0,C.A./SOTON 34068,10.5,,S
1,885,Died,3,"Sutehall, Mr. Henry Jr",male,25,0,0,SOTON/OQ 392076,7.05,,S
1,886,Died,3,"Rice, Mrs. William (Margaret Norton)",female,39,0,5,382652,29.125,,Q
1,887,Died,2,"Montvila, Rev. Juozas",male,27,0,0,211536,13,,S
1,888,Survived,1,"Graham, Miss. Margaret Edith",female,19,0,0,112053,30,B42,S
1,889,Died,3,"Johnston, Miss. Catherine Helen ""Carrie""",female,,1,2,W./C. 6607,23.45,,S
1,890,Survived,1,"Behr, Mr. Karl Howell",male,26,0,0,111369,30,C148,C
1,891,Died,3,"Dooley, Mr. Patrick",male,32,0,0,370376,7.75,,Q
docs/showcases/titanic/main.js METASEP
const csv2JsLoaded = import("../../assets/javascripts/csv2js.js");
const vizzuLoaded = import("../../assets/javascripts/vizzu.js").then(
  (vizzuUrl) => {
    return import(vizzuUrl.default);
  },
);

Promise.all([csv2JsLoaded, vizzuLoaded]).then((results) => {
  const Csv2Js = results[0].default;
  const Vizzu = results[1].default;

  const dataLoaded = Csv2Js.csv("./titanic.csv");

  dataLoaded.then((data) => {
    new Vizzu("testVizzuCanvas", { data }).initializing.then((chart) => {
      chart.animate({
        config: {
          x: "Count",
          y: "Sex",
          label: "Count",
          title: "Passengers of the Titanic",
        },
      });

      chart.animate({
        config: {
          x: ["Count", "Survived"],
          label: ["Count", "Survived"],
          color: "Survived",
        },
      });

      chart.animate({
        config: { x: "Count", y: ["Sex", "Survived"] },
      });

      chart.animate({
        config: {
          x: ["Count", "Sex", "Survived"],
          y: null,
          coordSystem: "polar",
        },
      });
    });
  });
});

docs/showcases/titanic/main.html METASEP
<!doctype html>
<html>
  <head>
    <title>Vizzu - Passengers of the Titanic</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preload" href="../../assets/stylesheets/iframe.css" as="style" />
    <link rel="stylesheet" href="../../assets/stylesheets/iframe.css" />
    <script
      type="text/javascript"
      src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.4.2/tinycolor.min.js"
    ></script>
  </head>
  <body>
    <div id="zoom" style="width: 100%">
      <canvas id="testVizzuCanvas" width="1280" height="720"></canvas>
    </div>
    <script
      src="../../assets/javascripts/iframe/autoscale.js"
      type="text/javascript"
    ></script>
    <script src="main.js" type="module"></script>
  </body>
</html>

docs/showcases/sales/sales.csv METASEP
Region,Product,Sales,Revenue [$]
North,Shoes,4500,202500
North,Handbags,7400,296000
North,Gloves,2350,70500
North,Accessories,8200,147600
South,Shoes,3850,173250
South,Handbags,6200,248000
South,Gloves,3100,93000
South,Accessories,10500,189000
East,Shoes,2300,103500
East,Handbags,3800,152000
East,Gloves,7250,217500
East,Accessories,5600,100800
West,Shoes,4100,184500
West,Handbags,6800,272000
West,Gloves,3650,109500
West,Accessories,7600,136800
docs/showcases/sales/main.js METASEP
const csv2JsLoaded = import("../../assets/javascripts/csv2js.js");
const vizzuLoaded = import("../../assets/javascripts/vizzu.js").then(
  (vizzuUrl) => {
    return import(vizzuUrl.default);
  },
);

Promise.all([csv2JsLoaded, vizzuLoaded]).then((results) => {
  const Csv2Js = results[0].default;
  const Vizzu = results[1].default;

  const dataLoaded = Csv2Js.csv("./sales.csv");

  dataLoaded.then((data) => {
    new Vizzu("testVizzuCanvas", { data }).initializing.then((chart) => {
      chart.animate({
        data: {
          filter: (record) => {
            return record.Product === "Shoes";
          },
        },
        config: {
          x: "Region",
          y: ["Sales", "Product"],
          label: "Sales",
          color: "Product",
          title: "Sales of Shoes",
        },
      });

      chart.animate(
        {
          data: {
            filter: (record) => {
              return (
                record.Product === "Shoes" || record.Product === "Handbags"
              );
            },
          },
          config: { title: "Sales of Shoes & Handbags" },
        },
        { delay: 1 },
      );

      chart.animate(
        {
          data: {
            filter: (record) => {
              return record.Product !== "Accessories";
            },
          },
          config: { title: "Sales of Shoes, Handbags & Gloves" },
        },
        { delay: 1 },
      );

      chart.animate(
        {
          data: { filter: null },
          config: { title: "Sales of All Products" },
        },
        { delay: 1 },
      );

      chart.animate(
        {
          config: {
            y: ["Revenue [$]", "Product"],
            label: "Revenue [$]",
            title: "Revenue of All Products",
          },
        },
        { delay: 1 },
      );

      chart.animate(
        {
          config: { x: ["Region", "Revenue [$]"], y: "Product" },
        },
        { delay: 2 },
      );

      chart.animate({
        config: { x: "Revenue [$]", y: "Product" },
      });

      chart.animate(
        {
          config: { coordSystem: "polar", sort: "byValue" },
        },
        { delay: 1 },
      );
    });
  });
});

docs/showcases/sales/main.html METASEP
<!doctype html>
<html>
  <head>
    <title>Vizzu - Sales</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preload" href="../../assets/stylesheets/iframe.css" as="style" />
    <link rel="stylesheet" href="../../assets/stylesheets/iframe.css" />
    <script
      type="text/javascript"
      src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.4.2/tinycolor.min.js"
    ></script>
  </head>
  <body>
    <div id="zoom" style="width: 100%">
      <canvas id="testVizzuCanvas" width="1280" height="720"></canvas>
    </div>
    <script
      src="../../assets/javascripts/iframe/autoscale.js"
      type="text/javascript"
    ></script>
    <script src="main.js" type="module"></script>
  </body>
</html>

docs/showcases/nadal/nadal.csv METASEP
Year,Result,Result_Num,Round,Round2,Sets,Opponent,Won,Lost,Bagel,Final,Count,Novak,Roger,Tournament,Player,Level,3SetWin,Straightwin,Order_GS,Order_all,Total_GS,Top
2005,Won,1,R128,First round,3,Lars Burgsmuller,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2005,Won,1,R64,Second round,3,Xavier Malisse,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2005,Won,1,R32,Third round,3,Richard Gasquet,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2005,Won,1,R16,Fourth round,4,Sebastien Grosjean,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2005,Won,1,QF,Quarter-final,3,David Ferrer,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2005,Won,1,SF,Semi-final,4,Roger Federer,1,0,0,0,1,0,1,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2005,Won,1,F,Final,4,Mariano Puerta,1,0,0,1,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2006,Won,1,F,Final,4,Roger Federer,1,0,0,1,1,0,1,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2006,Won,1,SF,Semi-final,3,Ivan Ljubicic,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2006,Won,1,QF,Quarter-final,2,Novak Djokovic,1,0,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2006,Won,1,R16,Fourth round,4,Lleyton Hewitt,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2006,Won,1,R32,Third round,4,Paul Henri Mathieu,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2006,Won,1,R64,Second round,3,Kevin Kim,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2006,Won,1,R128,First round,3,Robin Soderling,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2007,Won,1,F,Final,4,Roger Federer,1,0,0,1,1,0,1,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2007,Won,1,SF,Semi-final,3,Novak Djokovic,1,0,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2007,Won,1,QF,Quarter-final,3,Carlos Moya,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2007,Won,1,R16,Fourth round,3,Lleyton Hewitt,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2007,Won,1,R32,Third round,3,Albert Montanes,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2007,Won,1,R64,Second round,3,Flavio Cipolla,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2007,Won,1,R128,First round,3,Juan Martin Del Potro,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2008,Won,1,F,Final,3,Roger Federer,1,0,1,1,1,0,1,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2008,Won,1,SF,Semi-final,3,Novak Djokovic,1,0,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2008,Won,1,QF,Quarter-final,3,Nicolas Almagro,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2008,Won,1,R16,Fourth round,3,Fernando Verdasco,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2008,Won,1,R32,Third round,3,Jarkko Nieminen,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2008,Won,1,R64,Second round,3,Nicolas Devilder,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2008,Won,1,R128,First round,3,Thomaz Bellucci,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2009,Won,1,R32,Third round,3,Lleyton Hewitt,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2009,Won,1,R64,Second round,3,Teymuraz Gabashvili,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2009,Won,1,R128,First round,3,Marcos Daniel,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2010,Won,1,F,Final,3,Robin Soderling,1,0,0,1,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2010,Won,1,SF,Semi-final,3,Jurgen Melzer,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2010,Won,1,QF,Quarter-final,3,Nicolas Almagro,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2010,Won,1,R16,Fourth round,3,Thomaz Bellucci,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2010,Won,1,R32,Third round,3,Lleyton Hewitt,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2010,Won,1,R64,Second round,3,Horacio Zeballos,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2010,Won,1,R128,First round,3,Gianni Mina,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2011,Won,1,F,Final,4,Roger Federer,1,0,0,1,1,0,1,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2011,Won,1,SF,Semi-final,3,Andy Murray,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2011,Won,1,QF,Quarter-final,3,Robin Soderling,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2011,Won,1,R16,Fourth round,3,Ivan Ljubicic,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2011,Won,1,R32,Third round,3,Antonio Veic,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2011,Won,1,R64,Second round,3,Pablo Andujar,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2011,Won,1,R128,First round,5,John Isner,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2012,Won,1,F,Final,4,Novak Djokovic,1,0,0,1,1,1,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2012,Won,1,SF,Semi-final,3,David Ferrer,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2012,Won,1,QF,Quarter-final,3,Nicolas Almagro,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2012,Won,1,R16,Fourth round,3,Juan Monaco,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2012,Won,1,R32,Third round,3,Eduardo Schwank,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2012,Won,1,R64,Second round,3,Denis Istomin,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2012,Won,1,R128,First round,3,Simone Bolelli,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2013,Won,1,F,Final,3,David Ferrer,1,0,0,1,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2013,Won,1,SF,Semi-final,5,Novak Djokovic,1,0,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2013,Won,1,QF,Quarter-final,3,Stan Wawrinka,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2013,Won,1,R16,Fourth round,3,Kei Nishikori,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2013,Won,1,R32,Third round,3,Fabio Fognini,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2013,Won,1,R64,Second round,4,Martin Klizan,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2013,Won,1,R128,First round,4,Daniel Brands,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2014,Won,1,F,Final,4,Novak Djokovic,1,0,0,1,1,1,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2014,Won,1,SF,Semi-final,3,Andy Murray,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2014,Won,1,QF,Quarter-final,4,David Ferrer,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2014,Won,1,R16,Fourth round,3,Dusan Lajovic,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2014,Won,1,R32,Third round,3,Leonardo Mayer,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2014,Won,1,R64,Second round,3,Dominic Thiem,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2014,Won,1,R128,First round,3,Robby Ginepri,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2015,Won,1,R16,Fourth round,4,Jack Sock,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2015,Won,1,R32,Third round,3,Andrey Kuznetsov,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2015,Won,1,R64,Second round,3,Nicolas Almagro,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2015,Won,1,R128,First round,3,Quentin Halys,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2016,Won,1,R64,Second round,3,Facundo Bagnis,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2016,Won,1,R128,First round,3,Samuel Groth,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2017,Won,1,F,Final,3,Stan Wawrinka,1,0,0,1,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2017,Won,1,SF,Semi-final,3,Dominic Thiem,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2017,Won,1,QF,Quarter-final,2,Pablo Carreno Busta,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2017,Won,1,R16,Fourth round,3,Roberto Bautista Agut,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2017,Won,1,R32,Third round,3,Nikoloz Basilashvili,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2017,Won,1,R64,Second round,3,Robin Haase,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2017,Won,1,R128,First round,3,Benoit Paire,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2018,Won,1,F,Final,3,Dominic Thiem,1,0,0,1,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2018,Won,1,SF,Semi-final,3,Juan Martin Del Potro,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2018,Won,1,QF,Quarter-final,4,Diego Sebastian Schwartzman,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2018,Won,1,R16,Fourth round,3,Maximilian Marterer,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2018,Won,1,R32,Third round,3,Richard Gasquet,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2018,Won,1,R64,Second round,3,Guido Pella,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2018,Won,1,R128,First round,3,Simone Bolelli,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2019,Won,1,F,Final,4,Dominic Thiem,1,0,0,1,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2019,Won,1,SF,Semi-final,3,Roger Federer,1,0,0,0,1,0,1,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2019,Won,1,QF,Quarter-final,3,Kei Nishikori,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2019,Won,1,R16,Fourth round,3,Juan Ignacio Londero,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2019,Won,1,R32,Third round,4,David Goffin,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2019,Won,1,R64,Second round,3,Yannick Maden,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2019,Won,1,R128,First round,3,Yannick Hanfmann,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2020,Won,1,F,Final,3,Novak Djokovic,1,0,1,1,1,1,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2020,Won,1,SF,Semi-final,3,Diego Sebastian Schwartzman,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2020,Won,1,QF,Quarter-final,3,Jannik Sinner,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2020,Won,1,R16,Fourth round,3,Sebastian Korda,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2020,Won,1,R32,Third round,3,Stefano Travaglia,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2020,Won,1,R64,Second round,3,Mackenzie Mcdonald,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2020,Won,1,R128,First round,3,Egor Gerasimov,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,1,1,1,,
2021,Won,1,QF,Quarter-final,4,Diego Sebastian Schwartzman,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2021,Won,1,R16,Fourth round,3,Jannik Sinner,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2021,Won,1,R32,Third round,3,Cameron Norrie,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2021,Won,1,R64,Second round,3,Richard Gasquet,1,0,1,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2021,Won,1,R128,First round,3,Alexei Popyrin,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2022,Won,1,R128,First round,3,Jordan Thompson,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2022,Won,1,R64,Second round,3,Corentin Moutet,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2022,Won,1,R32,Third round,3,Botic van de Zandschulp,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2022,Won,1,R16,Fourth round,5,Felix Auger-Aliassime,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2022,Won,1,QF,Quarter-final,4,Novak Djokovic,1,0,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2022,Won,1,SF,Semi-final,2,Alexander Zverev,1,0,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2022,Won,1,F,Final,3,Casper Ruud,1,0,1,1,1,0,0,Roland Garros,Nadal,Roland Garros,1,0,1,1,,
2021,Lost,0,SF,Semi-final,4,Novak Djokovic,0,1,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2015,Lost,0,QF,Quarter-final,3,Novak Djokovic,0,1,0,0,1,1,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2009,Lost,0,R16,Fourth round,4,Robin Soderling,0,1,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
2016,Retired,-1,R32,Third round,0,Marcel Granollers,0,1,0,0,1,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,9,0,0,Australian Open,Djokovic,Australian Open,0,0,2,5,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,14,0,0,Roland Garros,Nadal,Roland Garros,0,0,1,1,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,5,0,0,US Open,Connors,US Open,0,0,6,0,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,8,0,0,Wimbledon,Federer,Wimbledon,0,0,3,6,Federer - 20,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,7,0,0,Cincinnati,Federer,Masters,0,0,0,7,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,10,0,0,Basel,Federer,ATP 500,0,0,0,4,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,7,0,0,Buenos Aires,Vilas,ATP 250,0,0,0,7,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,12,0,0,Barcelona,Nadal,ATP 500,0,0,0,2,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,10,0,0,Halle,Federer,ATP 500,0,0,0,4,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,10,0,0,Rome,Nadal,Masters,0,0,0,4,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,8,0,0,Dubai,Federer,ATP 500,0,0,0,6,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,6,0,0,Australian Open,Federer,Australian Open,0,0,5,8,,1
Total,Won,1,F,Final,0,Nobody,1,0,0,1,11,0,0,Monte Carlo,Nadal,Masters,0,0,0,3,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,6,0,0,Roland Garros,Borg,Roland Garros,0,0,5,8,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,5,0,0,US Open,Sampras,US Open,0,0,6,0,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,5,0,0,US Open,Federer,US Open,0,0,6,0,,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,7,0,0,Wimbledon,Sampras,Wimbledon,0,0,4,7,Sampras - 14,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,6,0,0,Wimbledon,Djokovic,Wimbledon,0,0,5,8,Djokovic - 20,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,5,0,0,Wimbledon,Borg,Wimbledon,0,0,6,0,Borg - 11,1
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,4,0,0,Australian Open,Agassi,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,Australian Open,Wilander,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Australian Open,Sampras,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Australian Open,Nadal,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Australian Open,Lendl,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Australian Open,Edberg,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Australian Open,Becker,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,1,0,0,Australian Open,Connors,Australian Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,Roland Garros,Wilander,Roland Garros,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,Roland Garros,Lendl,Roland Garros,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Roland Garros,Djokovic,Roland Garros,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,1,0,0,Roland Garros,Federer,Roland Garros,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,1,0,0,Roland Garros,Agassi,Roland Garros,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,4,0,0,US Open,Nadal,US Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,4,0,0,US Open,McEnroe,US Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,US Open,Lendl,US Open,0,0,0,0,Lendl - 8,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,US Open,Djokovic,US Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,US Open,Edberg,US Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,US Open,Agassi,US Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,1,0,0,US Open,Wilander,US Open,0,0,0,0,Wilander - 7,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,1,0,0,US Open,Becker,US Open,0,0,0,0,,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,Wimbledon,McEnroe,Wimbledon,0,0,0,0,McEnroe - 7,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,3,0,0,Wimbledon,Becker,Wimbledon,0,0,0,0,Becker - 6,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Wimbledon,Nadal,Wimbledon,0,0,0,0,Nadal - 22,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Wimbledon,Edberg,Wimbledon,0,0,0,0,Edberg - 6,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,2,0,0,Wimbledon,Connors,Wimbledon,0,0,0,0,Connors - 8,
Total,Won,1,GS,Grand Slam,0,Nobody,1,0,0,0,1,0,0,Wimbledon,Agassi,Wimbledon,0,0,0,0,Agassi - 8,
docs/showcases/nadal/main.js METASEP
const csv2JsLoaded = import("../../assets/javascripts/csv2js.js");
const vizzuLoaded = import("../../assets/javascripts/vizzu.js").then(
  (vizzuUrl) => {
    return import(vizzuUrl.default);
  },
);

Promise.all([csv2JsLoaded, vizzuLoaded]).then((results) => {
  const Csv2Js = results[0].default;
  const Vizzu = results[1].default;

  const dataLoaded = Csv2Js.csv("./nadal.csv", [
    "Year",
    "Round",
    "Round2",
    "Order_GS",
    "Order_all",
    "Total_GS",
    "Top",
  ]);

  dataLoaded.then((data) => {
    new Vizzu("testVizzuCanvas", { data }).initializing.then((chart) => {
      chart.animate({
        data: {
          filter: (record) => {
            return record.Year !== "Total";
          },
        },
        config: {
          x: "Year",
          y: "Round2",
          color: { set: "Result_Num", range: { min: -1, max: 1 } },
          size: null,
          orientation: "horizontal",
          geometry: "rectangle",
          title: "Rafael Nadal's matches at the Roland Garros",
          legend: "size",
        },
        style: {
          title: {
            paddingTop: 50,
            paddingBottom: 0,
          },
          plot: {
            marker: {
              borderWidth: 3,
              borderOpacity: 0,
              colorPalette: "#1EB55FFF #AD0000FF #AEAEAEFF",
              colorGradient:
                "#AEAEAEFF 0.000000, #AD0000FF 0.500000, #1EB55FFF 1.000000",
            },
            paddingLeft: 20,
            paddingBottom: "3.5em",
            paddingTop: "2.5em",
            xAxis: { interlacing: { color: "#ffffff00" } },
            yAxis: { label: { fontSize: "120%" } },
          },
          logo: { width: 100 },
        },
      });

      chart.animate(
        {
          config: {
            lightness: "Won",
            title: "Won 112 out of 116 (96.5%)",
          },
          style: {
            plot: { marker: { maxLightness: 0, minLightness: 0.8 } },
          },
        },
        { delay: 4 },
      );

      chart.animate(
        {
          config: {
            lightness: "Lost",
            title: "Lost 3 times, retired once",
          },
        },
        { delay: 4 },
      );

      chart.animate(
        {
          config: { lightness: null, title: "" },
          style: {
            plot: { marker: { maxLightness: null, minLightness: null } },
          },
        },
        { delay: 4 },
      );

      chart.animate({
        config: {
          lightness: "3SetWin",
          title: "90 wins (80%) in straight sets",
        },
        style: {
          plot: { marker: { maxLightness: 0, minLightness: 0.8 } },
        },
      });

      chart.animate(
        {
          config: {
            lightness: "Straightwin",
            title: "Won 4 titles without dropping a set",
          },
        },
        { delay: 3 },
      );

      chart.animate(
        {
          config: { lightness: null, title: "" },
          style: {
            plot: { marker: { maxLightness: null, minLightness: null } },
          },
        },
        { delay: 4 },
      );

      chart.animate({
        config: {
          lightness: "Novak",
          title: "Played the most times against Djokovic - 10 matches",
        },
        style: {
          plot: { marker: { maxLightness: 0, minLightness: 0.8 } },
        },
      });

      chart.animate(
        {
          config: {
            lightness: "Roger",
            title: "Second on this list is Federer - with 6 encounters",
          },
        },
        { delay: 4 },
      );

      chart.animate(
        {
          config: {
            lightness: "Final",
            title: "Rafa won all of his 14 finals",
          },
        },
        { delay: 4 },
      );

      chart.animate(
        {
          data: {
            filter: (record) => {
              return record.Year !== "Total" && record.Round === "F";
            },
          },
          config: {
            y: { set: "Round2", range: { max: 1, min: -5 } },
            x: "Count",
            lightness: null,
            noop: "Year",
            label: null,
            title: "",
          },
          style: {
            plot: {
              marker: {
                borderWidth: 0,
                colorPalette:
                  "#C6652A #CDA02E #47B0FF #329564 #5C88F2 #91A9B5 #DBC4B1",
                maxLightness: null,
                minLightness: null,
                label: {
                  position: "center",
                  format: "dimensionsFirst",
                },
              },
              xAxis: {
                title: { color: "#ffffff00" },
                label: { color: "#ffffff00" },
                interlacing: { color: "#ffffff00" },
              },
              yAxis: {
                title: { color: "#ffffff00" },
                label: { color: "#ffffff00", fontSize: null },
              },
            },
          },
        },
        { delay: 3 },
      );

      chart.animate(
        {
          data: {
            filter: (record) => {
              return (
                record.Year === "Total" &&
                record.Tournament === "Roland Garros" &&
                record.Player === "Nadal"
              );
            },
          },
          config: {
            noop: ["Level", "Round2"],
            label: ["Player", "Tournament", "Count"],
            y: { set: ["Player", "Tournament"] },
          },
        },
        { duration: 0 },
      );

      chart.animate(
        {
          config: { noop: "Level" },
        },
        { duration: 0 },
      );

      chart.animate({
        data: {
          filter: (record) => {
            return (
              record.Year === "Total" &&
              record.Round === "GS" &&
              record.Top === "1"
            );
          },
        },
        config: {
          y: {
            set: ["Player", "Tournament", "Level"],
            range: { max: null, min: null },
          },
          title: "Rafa won the same Grand Slam title the most times",
          color: "Level",
          legend: "color",
          noop: null,
          sort: "byValue",
        },
      });

      chart.animate(
        {
          data: {
            filter: (record) => {
              return record.Year === "Total" && record.Top === "1";
            },
          },
          config: {
            y: {
              set: ["Player", "Tournament", "Level"],
              range: { max: 19, min: 7 },
            },
            x: ["Count"],
            title: "Winning the same ATP title - Rafa is 1st, 2nd, 3rd & 4th!",
          },
        },
        { delay: 5 },
      );

      chart.animate(
        {
          data: {
            filter: (record) => {
              return (
                record.Year === "Total" &&
                record.Round === "GS" &&
                record.Top === "1"
              );
            },
          },
          config: {
            y: {
              set: ["Player", "Tournament", "Level"],
              range: { max: null, min: null },
            },
            x: ["Count"],
            title: "",
            color: "Level",
          },
        },
        { delay: 5 },
      );

      chart.animate({
        config: { x: ["Count", "Total_GS"], label: "Player" },
      });

      chart.animate({
        data: {
          filter: (record) => {
            return record.Year === "Total" && record.Round === "GS";
          },
        },
        config: {
          y: { set: ["Player"], range: { max: null, min: null } },
          x: ["Count", "Tournament", "Level", "Total_GS"],
          title: "Rafa also leads in the number of total Grand Slams won",
        },
      });

      chart.animate({
        config: { label: ["Total_GS"] },
        style: {
          plot: {
            marker: {
              label: {
                position: "right",
                filter: "color(#666666FF)",
              },
            },
          },
        },
      });
    });
  });
});

docs/showcases/nadal/main.html METASEP
<!doctype html>
<html>
  <head>
    <title>Vizzu - Rafael Nadal's matches</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preload" href="../../assets/stylesheets/iframe.css" as="style" />
    <link rel="stylesheet" href="../../assets/stylesheets/iframe.css" />
    <script
      type="text/javascript"
      src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.4.2/tinycolor.min.js"
    ></script>
  </head>
  <body>
    <div id="zoom" style="width: 100%">
      <canvas id="testVizzuCanvas" width="1280" height="720"></canvas>
    </div>
    <script
      src="../../assets/javascripts/iframe/autoscale.js"
      type="text/javascript"
    ></script>
    <script src="main.js" type="module"></script>
  </body>
</html>

docs/showcases/musicformats/musicformats.csv METASEP
Year,Format,Revenue [m$]
1972,Other,0
1972,DVD,0
1972,Tapes,0
1972,Download,0
1972,Streaming,0
1972,Cassette,0
1972,Vinyl,0
1972,CD,0
1973,Cassette,443
1973,Tapes,2941
1973,Vinyl,8371
1974,Cassette,458
1974,Tapes,2953
1974,Vinyl,8137
1975,Cassette,475
1975,Tapes,2854
1975,Vinyl,8161
1976,Cassette,663
1976,Tapes,3108
1976,Vinyl,8679
1977,Cassette,1066
1977,Tapes,3464
1977,Vinyl,10422
1978,Cassette,1786
1978,Tapes,3763
1978,Vinyl,10851
1979,Cassette,2070
1979,Tapes,2440
1979,Vinyl,8594
1980,Tapes,1655
1980,Cassette,2214
1980,Vinyl,7695
1981,Tapes,891
1981,Cassette,3026
1981,Vinyl,7397
1982,Tapes,97
1982,Cassette,3713
1982,Vinyl,5922
1983,CD,45
1983,Cassette,4706
1983,Vinyl,5089
1984,CD,257
1984,Vinyl,4602
1984,Cassette,5938
1985,CD,937
1985,Vinyl,3756
1985,Cassette,5800
1986,CD,2196
1986,Vinyl,2860
1986,Cassette,5902
1987,Vinyl,2270
1987,CD,3631
1987,Cassette,6776
1988,Vinyl,1559
1988,CD,4594
1988,Cassette,7531
1989,DVD,241
1989,Vinyl,703
1989,CD,5401
1989,Cassette,7390
1990,DVD,341
1990,Vinyl,358
1990,CD,6847
1990,Cassette,7387
1991,Vinyl,177
1991,DVD,224
1991,Cassette,6176
1991,CD,8309
1992,Vinyl,147
1992,DVD,290
1992,Cassette,6300
1992,CD,9909
1993,Vinyl,111
1993,DVD,382
1993,Cassette,5757
1993,CD,11745
1994,Vinyl,114
1994,DVD,404
1994,Cassette,5678
1994,CD,14880
1995,Vinyl,122
1995,DVD,374
1995,Cassette,4313
1995,CD,16113
1996,Vinyl,139
1996,DVD,390
1996,Cassette,3455
1996,CD,16691
1997,Vinyl,111
1997,DVD,522
1997,Cassette,2671
1997,CD,16428
1998,Vinyl,95
1998,DVD,807
1998,Cassette,2404
1998,CD,18465
1999,Vinyl,93
1999,DVD,585
1999,Cassette,1724
1999,CD,20256
2000,Vinyl,81
2000,DVD,424
2000,Cassette,948
2000,CD,20075
2001,Vinyl,86
2001,DVD,490
2001,Cassette,531
2001,CD,18982
2002,Vinyl,65
2002,Cassette,302
2002,DVD,427
2002,CD,17355
2003,Vinyl,61
2003,Cassette,152
2003,DVD,574
2003,CD,15888
2004,Streaming,10
2004,Cassette,33
2004,Vinyl,54
2004,Download,251
2004,DVD,841
2004,CD,15726
2005,Cassette,17
2005,Vinyl,36
2005,Streaming,225
2005,Other,560
2005,Download,666
2005,DVD,813
2005,CD,13969
2006,Cassette,5
2006,Vinyl,33
2006,Streaming,307
2006,DVD,582
2006,Other,996
2006,Download,1125
2006,CD,12049
2007,Cassette,4
2007,Vinyl,34
2007,Streaming,337
2007,DVD,609
2007,Other,1321
2007,Download,1669
2007,CD,9324
2008,Cassette,1
2008,Vinyl,72
2008,DVD,275
2008,Streaming,386
2008,Other,1178
2008,Download,2054
2008,CD,6585
2009,Vinyl,80
2009,DVD,255
2009,Streaming,436
2009,Other,1098
2009,Download,2361
2009,CD,5217
2010,Vinyl,108
2010,DVD,212
2010,Streaming,548
2010,Other,763
2010,Download,2665
2010,CD,4028
2011,Vinyl,143
2011,DVD,174
2011,Other,547
2011,Streaming,752
2011,Download,3021
2011,CD,3573
2012,DVD,132
2012,Vinyl,187
2012,Other,384
2012,Streaming,1164
2012,CD,2807
2012,Download,3236
2013,DVD,118
2013,Vinyl,237
2013,Other,327
2013,Streaming,1616
2013,CD,2382
2013,Download,3136
2014,DVD,100
2014,Vinyl,273
2014,Other,283
2014,CD,1947
2014,Streaming,1998
2014,Download,2719
2015,DVD,83
2015,Other,285
2015,Vinyl,370
2015,CD,1580
2015,Download,2464
2015,Streaming,2546
2016,DVD,64
2016,Other,296
2016,Vinyl,389
2016,CD,1221
2016,Download,1930
2016,Streaming,4179
2017,DVD,40
2017,Other,285
2017,Vinyl,417
2017,CD,1103
2017,Download,1412
2017,Streaming,5721
2018,DVD,30
2018,Other,322
2018,Vinyl,438
2018,CD,718
2018,Download,1038
2018,Streaming,7491
2019,DVD,28
2019,Other,307
2019,Vinyl,492
2019,CD,639
2019,Download,810
2019,Streaming,8992
2020,DVD,29
2020,Other,287
2020,CD,484
2020,Vinyl,626
2020,Download,653
2020,Streaming,10075
docs/showcases/musicformats/main.js METASEP
const csv2JsLoaded = import("../../assets/javascripts/csv2js.js");
const vizzuLoaded = import("../../assets/javascripts/vizzu.js").then(
  (vizzuUrl) => {
    return import(vizzuUrl.default);
  },
);

Promise.all([csv2JsLoaded, vizzuLoaded]).then((results) => {
  const Csv2Js = results[0].default;
  const Vizzu = results[1].default;

  const dataLoaded = Csv2Js.csv("./musicformats.csv", ["Year"]);

  dataLoaded.then((data) => {
    new Vizzu("testVizzuCanvas", { data }).initializing.then((chart) => {
      const config = {
        channels: {
          y: {
            set: ["Format"],
          },
          x: { set: ["Revenue [m$]"] },
          label: { set: ["Revenue [m$]"] },
          color: { set: ["Format"] },
        },
        sort: "byValue",
        title: "Music Revenue by Format - Year by Year 1973",
      };

      const style = {
        plot: {
          paddingLeft: 100,
          paddingTop: 25,
          yAxis: {
            color: "#ffffff00",
            label: { paddingRight: 10 },
          },
          xAxis: {
            title: { color: "#ffffff00" },
            label: { color: "#ffffff00", numberFormat: "grouped" },
          },
          marker: {
            colorPalette:
              "#b74c20FF #c47f58FF #1c9761FF #ea4549FF #875792FF #3562b6FF #ee7c34FF #efae3aFF",
          },
        },
      };

      chart.animate({
        data: {
          filter: (record) => {
            return parseInt(record.Year) === 1973;
          },
        },
        config,
        style,
      });

      for (let i = 1974; i < 2021; i++) {
        const title = `Music Revenue by Format - Year by Year ${i}`;
        chart.animate(
          {
            data: {
              filter: (record) => {
                return parseInt(record.Year) === i;
              },
            },
            config: { title },
          },
          {
            duration: 0.2,
            x: { easing: "linear", delay: 0 },
            y: { delay: 0 },
            show: { delay: 0 },
            hide: { delay: 0 },
            title: { duration: 0, delay: 0 },
          },
        );
      }

      chart.animate(
        {
          config: {
            channels: { x: { attach: ["Year"] }, label: { set: null } },
          },
        },
        {
          duration: 0.3,
        },
      );

      chart.animate(
        {
          data: {
            filter: (record) => {
              return record.Year === "2020" || record.Year === "1972";
            },
          },
          config: { title: "Lets see the total of the last 47 years" },
        },
        {
          duration: 2,
        },
      );

      chart.animate(
        {
          config: { sort: "none" },
        },
        {
          delay: 0,
          duration: 2,
        },
      );

      for (let i = 2019; i > 1972; i--) {
        chart.animate(
          {
            data: {
              filter: (record) => {
                return parseInt(record.Year) >= i || record.Year === "1972";
              },
            },
            config: { split: true },
            style: { "plot.xAxis.interlacing.color": "#ffffff" },
          },
          {
            duration: 0.005,
          },
        );
      }

      chart.animate(
        {
          data: {
            filter: (record) => {
              return record.Year !== "1972";
            },
          },
          config: { split: false },
        },
        {
          duration: 1.5,
        },
      );

      chart.animate(
        {
          config: { channels: { x: { detach: ["Year"] } } },
        },
        {
          duration: 0,
        },
      );

      chart.animate(
        {
          config: { channels: { label: { set: ["Revenue [m$]"] } } },
        },
        {
          duration: 0.1,
        },
      );

      chart.animate(
        {
          config: {
            channels: {
              x: { attach: ["Year"] },
              label: { detach: ["Revenue [m$]"] },
            },
          },
        },
        {
          duration: 1,
        },
      );

      chart.animate(
        {
          config: {
            channels: {
              x: { set: ["Year"] },
              y: {
                set: ["Revenue [m$]", "Format"],
                range: { min: null, max: null },
              },
              color: { set: ["Format"] },
            },
            title: "Music Revenue by Format in the USA 1973 - 2020",
            split: true,
          },
          style: {
            plot: {
              paddingLeft: 7.5,
              paddingTop: 25,
              xAxis: {
                label: { fontSize: 9, angle: 2.0, color: "#8e8e8e" },
              },
              yAxis: {
                interlacing: { color: "#ffffff00" },
                title: { color: "#ffffff00" },
                label: { color: "#ffffff00" },
              },
            },
          },
        },
        {
          duration: 2,
        },
      );

      chart.animate(
        {
          config: {
            geometry: "area",
          },
        },
        {
          duration: 1,
        },
      );

      chart.animate(
        {
          config: {
            channels: {
              x: { set: ["Year"] },
              y: { range: { max: "110%" } },
            },
            align: "center",
            split: false,
          },
          style: {
            "plot.marker.borderWidth": 1,
          },
        },
        {
          duration: 1,
        },
      );
    });
  });
});

docs/showcases/musicformats/main.html METASEP
<!doctype html>
<html>
  <head>
    <title>Vizzu - Music formats (Year by Year)</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preload" href="../../assets/stylesheets/iframe.css" as="style" />
    <link rel="stylesheet" href="../../assets/stylesheets/iframe.css" />
    <script
      type="text/javascript"
      src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.4.2/tinycolor.min.js"
    ></script>
  </head>
  <body>
    <div id="zoom" style="width: 100%">
      <canvas id="testVizzuCanvas" width="1280" height="720"></canvas>
    </div>
    <script
      src="../../assets/javascripts/iframe/autoscale.js"
      type="text/javascript"
    ></script>
    <script src="main.js" type="module"></script>
  </body>
</html>

docs/showcases/music/music.csv METASEP
Year,Format,Revenue [m$]
1973,DVD,0
1973,Other,0
1973,Tapes,2941
1973,Download,0
1973,Streaming,0
1973,Cassette,443
1973,Vinyl,8371
1973,CD,0
1974,DVD,0
1974,Other,0
1974,Tapes,2953
1974,Download,0
1974,Streaming,0
1974,Cassette,458
1974,Vinyl,8137
1974,CD,0
1975,DVD,0
1975,Other,0
1975,Tapes,2854
1975,Download,0
1975,Streaming,0
1975,Cassette,475
1975,Vinyl,8161
1975,CD,0
1976,DVD,0
1976,Other,0
1976,Tapes,3108
1976,Download,0
1976,Streaming,0
1976,Cassette,663
1976,Vinyl,8679
1976,CD,0
1977,DVD,0
1977,Other,0
1977,Tapes,3464
1977,Download,0
1977,Streaming,0
1977,Cassette,1066
1977,Vinyl,10422
1977,CD,0
1978,DVD,0
1978,Other,0
1978,Tapes,3763
1978,Download,0
1978,Streaming,0
1978,Cassette,1785
1978,Vinyl,10851
1978,CD,0
1979,DVD,0
1979,Other,0
1979,Tapes,2439
1979,Download,0
1979,Streaming,0
1979,Cassette,2070
1979,Vinyl,8594
1979,CD,0
1980,DVD,0
1980,Other,0
1980,Tapes,1655
1980,Download,0
1980,Streaming,0
1980,Cassette,2214
1980,Vinyl,7695
1980,CD,0
1981,DVD,0
1981,Other,0
1981,Tapes,891
1981,Download,0
1981,Streaming,0
1981,Cassette,3026
1981,Vinyl,7397
1981,CD,0
1982,DVD,0
1982,Other,0
1982,Tapes,97
1982,Download,0
1982,Streaming,0
1982,Cassette,3713
1982,Vinyl,5922
1982,CD,0
1983,DVD,0
1983,Other,0
1983,Tapes,0
1983,Download,0
1983,Streaming,0
1983,Cassette,4706
1983,Vinyl,5089
1983,CD,45
1984,DVD,0
1984,Other,0
1984,Tapes,0
1984,Download,0
1984,Streaming,0
1984,Cassette,5938
1984,Vinyl,4602
1984,CD,257
1985,DVD,0
1985,Other,0
1985,Tapes,0
1985,Download,0
1985,Streaming,0
1985,Cassette,5800
1985,Vinyl,3756
1985,CD,937
1986,DVD,0
1986,Other,0
1986,Tapes,0
1986,Download,0
1986,Streaming,0
1986,Cassette,5902
1986,Vinyl,2860
1986,CD,2196
1987,DVD,0
1987,Other,0
1987,Tapes,0
1987,Download,0
1987,Streaming,0
1987,Cassette,6776
1987,Vinyl,2270
1987,CD,3631
1988,DVD,0
1988,Other,0
1988,Tapes,0
1988,Download,0
1988,Streaming,0
1988,Cassette,7531
1988,Vinyl,1559
1988,CD,4594
1989,DVD,0
1989,Other,241
1989,Tapes,0
1989,Download,0
1989,Streaming,0
1989,Cassette,7389
1989,Vinyl,703
1989,CD,5401
1990,DVD,0
1990,Other,341
1990,Tapes,0
1990,Download,0
1990,Streaming,0
1990,Cassette,7387
1990,Vinyl,358
1990,CD,6847
1991,DVD,0
1991,Other,224
1991,Tapes,0
1991,Download,0
1991,Streaming,0
1991,Cassette,6176
1991,Vinyl,177
1991,CD,8309
1992,DVD,0
1992,Other,290
1992,Tapes,0
1992,Download,0
1992,Streaming,0
1992,Cassette,6300
1992,Vinyl,147
1992,CD,9909
1993,DVD,0
1993,Other,382
1993,Tapes,0
1993,Download,0
1993,Streaming,0
1993,Cassette,5757
1993,Vinyl,111
1993,CD,11744
1994,DVD,0
1994,Other,404
1994,Tapes,0
1994,Download,0
1994,Streaming,0
1994,Cassette,5678
1994,Vinyl,114
1994,CD,14880
1995,DVD,0
1995,Other,374
1995,Tapes,0
1995,Download,0
1995,Streaming,0
1995,Cassette,4313
1995,Vinyl,122
1995,CD,16113
1996,DVD,0
1996,Other,389
1996,Tapes,0
1996,Download,0
1996,Streaming,0
1996,Cassette,3455
1996,Vinyl,139
1996,CD,16691
1997,DVD,0
1997,Other,522
1997,Tapes,0
1997,Download,0
1997,Streaming,0
1997,Cassette,2671
1997,Vinyl,111
1997,CD,16428
1998,DVD,0
1998,Other,807
1998,Tapes,0
1998,Download,0
1998,Streaming,0
1998,Cassette,2404
1998,Vinyl,95
1998,CD,18465
1999,DVD,0
1999,Other,585
1999,Tapes,0
1999,Download,0
1999,Streaming,0
1999,Cassette,1724
1999,Vinyl,93
1999,CD,20255
2000,DVD,0
2000,Other,424
2000,Tapes,0
2000,Download,0
2000,Streaming,0
2000,Cassette,948
2000,Vinyl,81
2000,CD,20075
2001,DVD,8.8
2001,Other,481
2001,Tapes,0
2001,Download,0
2001,Streaming,0
2001,Cassette,531
2001,Vinyl,86
2001,CD,18982
2002,DVD,12
2002,Other,415
2002,Tapes,0
2002,Download,0
2002,Streaming,0
2002,Cassette,302
2002,Vinyl,65
2002,CD,17355
2003,DVD,11
2003,Other,562
2003,Tapes,0
2003,Download,0
2003,Streaming,0
2003,Cassette,152
2003,Vinyl,61
2003,CD,15888
2004,DVD,8.9
2004,Other,832
2004,Tapes,0
2004,Download,251
2004,Streaming,9.5
2004,Cassette,32
2004,Vinyl,54
2004,CD,15726
2005,DVD,15
2005,Other,1358
2005,Tapes,0
2005,Download,666
2005,Streaming,225
2005,Cassette,17
2005,Vinyl,36
2005,CD,13969
2006,DVD,3.1
2006,Other,1575
2006,Tapes,0
2006,Download,1125
2006,Streaming,307
2006,Cassette,4.8
2006,Vinyl,33
2006,CD,12049
2007,DVD,3.5
2007,Other,1927
2007,Tapes,0
2007,Download,1669
2007,Streaming,337
2007,Cassette,3.7
2007,Vinyl,34
2007,CD,9324
2008,DVD,1.4
2008,Other,1451
2008,Tapes,0
2008,Download,2054
2008,Streaming,386
2008,Cassette,1.1
2008,Vinyl,72
2008,CD,6585
2009,DVD,1.9
2009,Other,1351
2009,Tapes,0
2009,Download,2361
2009,Streaming,436
2009,Cassette,0
2009,Vinyl,80
2009,CD,5217
2010,DVD,1.1
2010,Other,974
2010,Tapes,0
2010,Download,2665
2010,Streaming,548
2010,Cassette,0
2010,Vinyl,108
2010,CD,4028
2011,DVD,0.3
2011,Other,721
2011,Tapes,0
2011,Download,3021
2011,Streaming,752
2011,Cassette,0
2011,Vinyl,143
2011,CD,3573
2012,DVD,0.2
2012,Other,515
2012,Tapes,0
2012,Download,3235
2012,Streaming,1164
2012,Cassette,0
2012,Vinyl,187
2012,CD,2807
2013,DVD,0
2013,Other,445
2013,Tapes,0
2013,Download,3136
2013,Streaming,1616
2013,Cassette,0
2013,Vinyl,237
2013,CD,2382
2014,DVD,2.3
2014,Other,381
2014,Tapes,0
2014,Download,2719
2014,Streaming,1998
2014,Cassette,0
2014,Vinyl,273
2014,CD,1947
2015,DVD,5.9
2015,Other,362
2015,Tapes,0
2015,Download,2464
2015,Streaming,2546
2015,Cassette,0
2015,Vinyl,370
2015,CD,1580
2016,DVD,3.1
2016,Other,357
2016,Tapes,0
2016,Download,1930
2016,Streaming,4179
2016,Cassette,0
2016,Vinyl,389
2016,CD,1221
2017,DVD,0.3
2017,Other,325
2017,Tapes,0
2017,Download,1412
2017,Streaming,5721
2017,Cassette,0
2017,Vinyl,417
2017,CD,1103
2018,DVD,0.3
2018,Other,351
2018,Tapes,0
2018,Download,1038
2018,Streaming,7491
2018,Cassette,0
2018,Vinyl,438
2018,CD,718
2019,DVD,1.3
2019,Other,333
2019,Tapes,0
2019,Download,810
2019,Streaming,8992
2019,Cassette,0
2019,Vinyl,492
2019,CD,639
2020,DVD,1.8
2020,Other,314
2020,Tapes,0
2020,Download,653
2020,Streaming,10075
2020,Cassette,0
2020,Vinyl,626
2020,CD,484
docs/showcases/music/main.js METASEP
const csv2JsLoaded = import("../../assets/javascripts/csv2js.js");
const vizzuLoaded = import("../../assets/javascripts/vizzu.js").then(
  (vizzuUrl) => {
    return import(vizzuUrl.default);
  },
);

Promise.all([csv2JsLoaded, vizzuLoaded]).then((results) => {
  const Csv2Js = results[0].default;
  const Vizzu = results[1].default;

  const dataLoaded = Csv2Js.csv("./music.csv", ["Year"]);

  dataLoaded.then((data) => {
    new Vizzu("testVizzuCanvas", { data }).initializing.then((chart) => {
      chart.animate({
        config: {
          title: "Music Revenue by Format 1973-2020",
          x: "Year",
          y: ["Format", "Revenue [m$]"],
          color: "Format",
          geometry: "area",
          align: "center",
        },
        style: {
          plot: {
            xAxis: { label: { fontSize: 9, angle: 2.0 } },
            marker: {
              colorPalette:
                "#b74c20FF #c47f58FF #1c9761FF" +
                " #ea4549FF #875792FF #3562b6FF" +
                " #ee7c34FF #efae3aFF",
            },
          },
        },
      });

      chart.animate(
        {
          config: {
            title: "Music Revenue by Format 1973-2020(%)",
            align: "stretch",
          },
        },
        {
          delay: 1,
        },
      );

      chart.animate(
        {
          config: {
            title: "Music Revenue by Format 1973-2020",
            align: "center",
          },
        },
        {
          delay: 1,
        },
      );

      chart.animate(
        {
          config: {
            split: true,
          },
        },
        {
          delay: 1,
        },
      );

      chart.animate(
        {
          data: {
            filter: (record) => {
              return record.Format === "Vinyl" || record.Format === "Streaming";
            },
          },
          config: {
            title: "Revenue of Vinyl & Streaming 1973-2020",
          },
        },
        {
          delay: 1,
        },
      );

      chart.animate(
        {
          data: { filter: null },
          config: {
            title: "Music Revenue by Format 1973-2020",
            split: false,
          },
        },
        {
          delay: 1,
        },
      );

      chart.animate(
        {
          config: {
            x: "Year",
            y: "Revenue [m$]",
            noop: "Format",
            align: "none",
            geometry: "line",
          },
        },
        {
          delay: 1,
        },
      );
    });
  });
});

docs/showcases/music/main.html METASEP
<!doctype html>
<html>
  <head>
    <title>Vizzu - Music formats</title>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="preload" href="../../assets/stylesheets/iframe.css" as="style" />
    <link rel="stylesheet" href="../../assets/stylesheets/iframe.css" />
    <script
      type="text/javascript"
      src="https://cdnjs.cloudflare.com/ajax/libs/tinycolor/1.4.2/tinycolor.min.js"
    ></script>
  </head>
  <body>
    <div id="zoom" style="width: 100%">
      <canvas id="testVizzuCanvas" width="1280" height="720"></canvas>
    </div>
    <script
      src="../../assets/javascripts/iframe/autoscale.js"
      type="text/javascript"
    ></script>
    <script src="main.js" type="module"></script>
  </body>
</html>

docs/environments/platform/voila.md METASEP
# Voilà

## Features

The features of `ipyvizzu` that are available in `Voilà` are marked with a green
check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line

```sh
pip install ipyvizzu pandas voila
```

or place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Voilà` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Place the above code blocks into notebook cells in a notebook file (for example
called `ipyvizzu_example.ipynb`) and run the following command in your command
line in order to try it.

```sh
voila ipyvizzu_example.ipynb
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/platform/streamlit.md METASEP
# Streamlit

There is a new `Streamlit` component,
[streamlit-vizzu](https://github.com/vizzu-streamlit/streamlit-vizzu), that
allow you to interact with an `ipyvizzu` chart within a `Streamlit` app without
the chart being redrawn on every interaction.

## Features

The features of `ipyvizzu` that are available in `Streamlit` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```sh
pip install ipyvizzu pandas streamlit
```

## Sample

Try `ipyvizzu` in `Streamlit` with the following sample.

```python
# import streamlit, pandas and ipyvizzu

from streamlit.components.v1 import html
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


def create_chart():
    # initialize Chart

    chart = Chart(
        width="640px", height="360px", display=DisplayTarget.MANUAL
    )

    # create and add data to Chart

    data = Data()
    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
    )
    data.add_df(df)

    chart.animate(data)

    # add config to Chart

    chart.animate(
        Config(
            {
                "x": "Count",
                "y": "Sex",
                "label": "Count",
                "title": "Passengers of the Titanic",
            }
        )
    )
    chart.animate(
        Config(
            {
                "x": ["Count", "Survived"],
                "label": ["Count", "Survived"],
                "color": "Survived",
            }
        )
    )
    chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))

    # add style to Chart

    chart.animate(Style({"title": {"fontSize": 35}}))

    # return generated html code

    return chart._repr_html_()


# generate Chart's html code

CHART = create_chart()


# display Chart

html(CHART, width=650, height=370)
```

Place the above code blocks into a python file (for example called
`ipyvizzu_example.py`) and run the following command in your command line in
order to try it.

```sh
streamlit run ipyvizzu_example.py
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/platform/panel.md METASEP
# Panel

## Features

The features of `ipyvizzu` that are available in `Panel` are marked with a green
check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```sh
pip install ipyvizzu pandas panel
```

## Sample

Try `ipyvizzu` in `Panel` with the following sample.

```python
# import panel, pandas and ipyvizzu

import panel as pn
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


def create_chart():
    # initialize chart

    chart = Chart(
        width="640px", height="360px", display=DisplayTarget.MANUAL
    )

    # create and add data to Chart

    data = Data()
    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
    )
    data.add_df(df)

    chart.animate(data)

    # add config to Chart

    chart.animate(
        Config(
            {
                "x": "Count",
                "y": "Sex",
                "label": "Count",
                "title": "Passengers of the Titanic",
            }
        )
    )
    chart.animate(
        Config(
            {
                "x": ["Count", "Survived"],
                "label": ["Count", "Survived"],
                "color": "Survived",
            }
        )
    )
    chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))

    # add style to Chart

    chart.animate(Style({"title": {"fontSize": 35}}))

    # return Chart

    return chart


# create Chart

CHART = create_chart()


# display Chart

pn.extension(sizing_mode="stretch_width", template="fast")

pn.state.template.param.update(
    title="ipyvizzu",
)

pn.pane.Markdown(
    """
# Panel demo with ipyvizzu
"""
).servable()

pn.pane.HTML(CHART, height=370, sizing_mode="stretch_both").servable()
```

Place the above code blocks into a python file (for example called
`ipyvizzu_example.py`) and run the following command in your command line in
order to try it.

```sh
panel serve ipyvizzu_example.py --autoreload
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/platform/mercury.md METASEP
# Mercury

The [`Mercury`](https://github.com/mljar/mercury) framework convert Jupyter
Notebooks to interactive Web Apps. It integrates great with `ipyvizzu`.

## Features

The features of `ipyvizzu` that are available in `Mercury` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`) DisplayUse scroll into view
  (`scroll_into_view`=`True`)

Display features:

- [ ]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Live example

[![Open in Mercury](https://raw.githubusercontent.com/mljar/mercury/main/docs/media/open_in_mercury.svg)](https://veghdev-ipyvizzu-demo.hf.space/app/ipyvizzu_demo)

## Installation

Add `ipyvizzu` to `requirements.txt`.

```
python-dotenv
pandas
mercury
ipyvizzu
```

## Sample

Try `ipyvizzu` in `Mercury` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget
import mercury as mr


# setup Mercury App
app = mr.App(
    title="ipyvizzu demo", description="ipyvizzu demo with mercury"
)


# add widget
gender = mr.Select(
    label="Select sex", value="female", choices=["female", "male"]
)


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# filter data by the selected gender to Chart

data_filter = Data.filter(f"record['Sex'] == '{gender.value}'")
chart.animate(data_filter)


# display Chart with show method (display=DisplayTarget.MANUAL)

# chart.show()
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/platform/index.md METASEP
# App platforms

`ipyvizzu` is available in the following App platforms. We would love to add
more environments and examples, so if you miss anything from our list, please
open an issue in our [Github repo](https://github.com/vizzuhq/ipyvizzu).

docs/environments/platform/flask.md METASEP
# Flask

## Features

The features of `ipyvizzu` that are available in `Flask` are marked with a green
check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [ ]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`) \*
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

\*you can display the `Chart` in other ways, see the sample below

## Installation

Run the following command in your command line in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```sh
pip install ipyvizzu pandas flask
```

## Sample

Try `ipyvizzu` in `Flask` with the following sample.

```python
# import flask, pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget

from flask import Flask, render_template


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart

app = Flask(__name__)
html = chart._repr_html_()


@app.route("/")
def vizzu():
    return render_template("vizzu.html", mychart=html)
```

Place the above code blocks into a python file (for example called
`application.py`), create the html template (`templates/vizzu.html`) with the
following content

```html
<!DOCTYPE html>
<html>
 <body>
  <div class="container">
   <iframe frameborder="0" height="480px" scrolling="no" src="data:text/html, {{ mychart }}" width="800px">
   </iframe>
  </div>
 </body>
</html>

```

and run the following command in your command line in order to try it.

```sh
flask --app application run
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/noteable.md METASEP
# Noteable

## Features

The features of `ipyvizzu` that are available in `Noteable` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [x]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Noteable` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/kaggle.md METASEP
# Kaggle

## Features

The features of `ipyvizzu` that are available in `Kaggle` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [x]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Live example

[![Open in Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://www.kaggle.com/dvidandrsvgh/ipyvizzu-demo)

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Kaggle` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/jupyternotebook.md METASEP
# Jupyter Notebook

## Features

The features of `ipyvizzu` that are available in `Jupyter Notebook` are marked
with a green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [x]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line

```sh
pip install ipyvizzu pandas
```

or place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Jupyter Notebook` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/jupyterlite.md METASEP
# JupyterLite

## Features

The features of `ipyvizzu` that are available in `JupyterLite` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [x]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```python
import micropip

await micropip.install("ipyvizzu")
```

## Sample

Try `ipyvizzu` in `JupyterLite` with the following sample.

```python
# import pandas, js, asyncio, StringIO and ipyvizzu

import pandas as pd
import js, asyncio
from io import StringIO
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart
# download data from
# "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
# and place it in your JupyterLite workspace

DB_NAME = "JupyterLite Storage"


async def get_contents(path):
    """use the IndexedDB API to acess JupyterLite's in-browser storage
    for documentation purposes, the full names of the JS API objects are used.
    see https://developer.mozilla.org/en-US/docs/Web/API/IDBRequest
    """
    queue = asyncio.Queue(1)

    IDBOpenDBRequest = js.self.indexedDB.open(DB_NAME)
    IDBOpenDBRequest.onsuccess = (
        IDBOpenDBRequest.onerror
    ) = queue.put_nowait

    await queue.get()

    if IDBOpenDBRequest.result is None:
        return None

    IDBTransaction = IDBOpenDBRequest.result.transaction(
        "files", "readonly"
    )
    IDBObjectStore = IDBTransaction.objectStore("files")
    IDBRequest = IDBObjectStore.get(path, "key")
    IDBRequest.onsuccess = IDBRequest.onerror = queue.put_nowait

    await queue.get()

    return IDBRequest.result.to_py() if IDBRequest.result else None


data = Data()
data_csv = await get_contents("titanic.csv")
df = pd.read_csv(StringIO(data_csv["content"]))
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/jupyterlab.md METASEP
# JupyterLab

## Features

The features of `ipyvizzu` that are available in `JupyterLab` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [x]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line

```sh
pip install ipyvizzu pandas
```

or place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `JupyterLab` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/index.md METASEP
# Notebooks

`ipyvizzu` is available in the following Notebooks. We would love to add more
environments and examples, so if you miss anything from our list, please open an
issue in our [Github repo](https://github.com/vizzuhq/ipyvizzu).

docs/environments/notebook/deepnote.md METASEP
# Deepnote

## Features

The features of `ipyvizzu` that are available in `Deepnote` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Live example

[![View in Deepnote](https://deepnote.com/static/buttons/view-in-deepnote.svg)](https://deepnote.com/workspace/david-andras-vegh-bc03-79fd3a98-abaf-40c0-8b52-9f3e438a73fc/project/ipyvizzu-demo-dff3c2c3-f212-434e-8fa1-23d843c52fe3/%2Fipyvizzu_demo.ipynb)

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Deepnote` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/datacamp.md METASEP
# DataCamp

## Features

The features of `ipyvizzu` that are available in `DataCamp` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`) \*
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`) \*
- [x]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`) \*
- [x]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`) \*
- [x]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`) \*
- [x]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

\*`ipyvizzu` does not work in the default editor, switch to the
`JupyterLab`-style editor

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `DataCamp` with the following sample.

```python
# import pandas and ipyvizzu
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px"
)  # or Chart(width="640px", height="360px", display=DisplayTarget.ACTUAL)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.BEGIN)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.END)
# chart = Chart(width="640px", height="360px", display=DisplayTarget.MANUAL)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)
chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

# chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/databricks.md METASEP
# Databricks

## Features

The features of `ipyvizzu` that are available in `Databricks` are marked with a
green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Live example

[Open in Databricks](https://databricks-prod-cloudfront.cloud.databricks.com/public/4027ec902e239c93eaaa8714f173bcfc/808850182010194/3745120999164565/1947355309752283/latest.html)

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Databricks` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with _repr_html_ method (display=DisplayTarget.MANUAL)

chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/notebook/colab.md METASEP
# Colab

## Features

The features of `ipyvizzu` that are available in `Colab` are marked with a green
check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [x]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Live example

[![Open in Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/drive/19H4etDPuSyJ3LNJbshsfEAnxxwjJgZgq?usp=sharing)

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `Colab` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with show or _repr_html_ method (display=DisplayTarget.MANUAL)

chart.show()
# chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/ide/vscode.md METASEP
# VSCode Python

## Features

The features of `ipyvizzu` that are available in `VSCode Python` are marked with
a green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line

```sh
pip install ipyvizzu pandas
```

or place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `VSCode Python` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with _repr_html_() method (display=DisplayTarget.MANUAL)

chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/ide/pycharm.md METASEP
# PyCharm

## Features

The features of `ipyvizzu` that are available in `PyCharm Professional` are
marked with a green check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [ ]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Run the following command in your command line

```sh
pip install ipyvizzu pandas
```

or place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas
```

## Sample

Try `ipyvizzu` in `PyCharm Professional` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with _repr_html_() method (display=DisplayTarget.MANUAL)

chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/ide/index.md METASEP
# IDEs

`ipyvizzu` is available in the following IDEs. We would love to add more
environments and examples, so if you miss anything from our list, please open an
issue in our [Github repo](https://github.com/vizzuhq/ipyvizzu).

docs/environments/bi/mode.md METASEP
# Mode

## Features

The features of `ipyvizzu` that are available in `Mode` are marked with a green
check.

- [x]  Change the url of `Vizzu` (`vizzu`)
- [x]  Change the width of the `Chart` (`width`)
- [x]  Change the height of the `Chart` (`height`)
- [x]  Use scroll into view (`scroll_into_view`=`True`)

Display features:

- [x]  Display all animations after `_repr_html_` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Display all animations after `show` method called
  (`display`=`DisplayTarget.MANUAL`)
- [ ]  Automatically display all animations after the first cell
  (`display`=`DisplayTarget.BEGIN`)
- [ ]  Automatically display all animations after the currently running cell
  (`display`=`DisplayTarget.ACTUAL`)
- [ ]  Automatically display all animations after the last running cell
  (`display`=`DisplayTarget.END`)
- [ ]  Rerun any cell without rerun the first cell
  (`display`!=`DisplayTarget.MANUAL`)

Check [Chart settings chapter](../../tutorial/chart_settings.md) for more
details.

## Installation

Place the following code into a notebook cell in order to install `ipyvizzu`
(visit [Installation chapter](../../installation.md) for more options and
details).

```
!pip install ipyvizzu pandas -t "/tmp" > /dev/null 2>&1
```

## Sample

Try `ipyvizzu` in `Mode` with the following sample.

```python
# import pandas and ipyvizzu

import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget


# initialize Chart

chart = Chart(
    width="640px", height="360px", display=DisplayTarget.MANUAL
)


# add data to Chart

data = Data()
df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data.add_df(df)

chart.animate(data)


# add config to Chart

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))


# add style to Chart

chart.animate(Style({"title": {"fontSize": 35}}))


# display Chart with _repr_html_ method (display=DisplayTarget.MANUAL)

chart
```

Check the [Tutorial](../../tutorial/index.md) for more info.

docs/environments/bi/index.md METASEP
# BI tools

`ipyvizzu` is available in the following BI tools. We would love to add more
environments and examples, so if you miss anything from our list, please open an
issue in our [Github repo](https://github.com/vizzuhq/ipyvizzu).

docs/assets/stylesheets/vizzu.css METASEP
[data-md-color-scheme="vizzu"] {
  --md-primary-fg-color: #333;
  --md-primary-fg-color--dark: #666;
  --md-default-fg-color: #666;
  --md-typeset-color: #666;
  --md-typeset-a-color: #4171cd;
}

.md-typeset details.tip,
.md-typeset .admonition.tip,
.md-typeset details.note,
.md-typeset .admonition.note,
.md-typeset details.info,
.md-typeset .admonition.info,
.md-typeset details.example,
.md-typeset .admonition.example {
  color: #666 !important;
  border-color: #ccc !important;
}

.md-typeset .tip > .admonition-title,
.md-typeset .tip > summary {
  color: #666 !important;
  border-color: #ccc !important;
  background-color: #f8f9fa !important;
}
.md-typeset .tip > .admonition-title::before,
.md-typeset .tip > summary::before {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-admonition-icon--tip);
  mask-image: var(--md-admonition-icon--tip);
}
.md-typeset .tip > summary::after {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-details-icon);
  mask-image: var(--md-details-icon);
}

.md-typeset .note > .admonition-title,
.md-typeset .note > summary {
  color: #666 !important;
  border-color: #ccc !important;
  background-color: #f8f9fa !important;
}
.md-typeset .note > .admonition-title::before,
.md-typeset .note > summary::before {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-admonition-icon--note);
  mask-image: var(--md-admonition-icon--note);
}
.md-typeset .note > summary::after {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-details-icon);
  mask-image: var(--md-details-icon);
}

.md-typeset .info > .admonition-title,
.md-typeset .info > summary {
  color: #666 !important;
  border-color: #ccc !important;
  background-color: #f8f9fa !important;
}
.md-typeset .info > .admonition-title::before,
.md-typeset .info > summary::before {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-admonition-icon--info);
  mask-image: var(--md-admonition-icon--info);
}
.md-typeset .info > summary::after {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-details-icon);
  mask-image: var(--md-details-icon);
}

.md-typeset .example > .admonition-title,
.md-typeset .example > summary {
  color: #666 !important;
  border-color: #ccc !important;
  background-color: #f8f9fa !important;
}
.md-typeset .example > .admonition-title::before,
.md-typeset .example > summary::before {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-admonition-icon--example);
  mask-image: var(--md-admonition-icon--example);
}
.md-typeset .example > summary::after {
  background-color: #ccc !important;
  -webkit-mask-image: var(--md-details-icon);
  mask-image: var(--md-details-icon);
}

docs/assets/stylesheets/style_reference.css METASEP
.not-collapsible-style {
  text-align: left;
  font-size: 0.8rem;
  margin: 5px;
}

.collapsible-style,
.allbtn-style {
  cursor: pointer;
  font-size: 0.8rem;
  margin: 5px;
}

.collapsible-style:hover button,
.allbtn-style:hover button {
  color: #4171cd;
}

.collapsible-style-content {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.1s ease-out;
}

docs/assets/stylesheets/iframe.css METASEP
@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Roboto&family=Roboto+Condensed&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@100&display=swap");

* {
  margin: 0;
  padding: 0;
}

@font-face {
  font-family: "Roboto Condensed";
  font-style: normal;
  font-weight: 400;
  src:
    local("Roboto Condensed"),
    local("RobotoCondensed-Regular"),
    url("roboto-condensed-v18-latin_latin-ext-regular.woff2") format("woff2"),
    /* Super Modern Browsers */
      url("roboto-condensed-v18-latin_latin-ext-regular.woff") format("woff"),
    /* Modern Browsers */
      url("roboto-condensed-v18-latin_latin-ext-regular.ttf") format("truetype"); /* Legacy iOS */
}

#testVizzuCanvas {
  width: 1280px;
  height: 720px;
  border: 1px solid #e0e0e0;
}

a {
  font-weight: 400;
  font-size: 15px;
  line-height: 1.5em;
  font-family: Roboto;
  color: #4171cd;
  text-decoration: none;
}

docs/assets/stylesheets/highlight.css METASEP
.highlight {
  background-color: #f8f9fa !important;
}

.hljs {
  background-color: #f9f9fb00 !important;
}

.hljs-title {
  color: #f4941b !important;
}

.hljs-property,
.hljs-attr {
  color: #4171cd !important;
}

.hljs-literal {
  color: #03ae71 !important;
}

.hljs-string {
  color: #f25456 !important;
}

.hljs-number {
  color: #f25456 !important;
}

.hljs-built_in,
.hljs-keyword {
  color: #03ae71 !important;
}

.hljs-keyword {
  color: #03ae71 !important;
}

.hljs-meta {
  color: #d49664ff !important;
}

.hljs-params,
.hljs-comment {
  color: #4c7450ff !important;
}

.hljs-ln-numbers {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;

  text-align: center;
  color: #ccc;
  border-right: 1px solid #ccc;
  vertical-align: top;
  padding-right: 5px !important;
}

.hljs-ln-code {
  padding-left: 10px !important;
}

.snippet:focus {
  color: #93a49a70 !important;
  transition: 200ms;
}

docs/assets/stylesheets/gallery.css METASEP
.image-gallery {
  max-width: 320px;
  border: 1px solid #ddd;
  margin: 20px;
}

.image-gallery-w-caption {
  max-width: 320px;
  border: 1px solid #ddd;
  margin: 20px;
  margin-bottom: 0px !important;
}

.image-figure {
  margin: 0px !important;
}

.image-caption {
  margin: 0px;
  margin-bottom: 20px !important;
  font-family: "Roboto" !important;
  font-style: normal !important;
}

.image-center {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

docs/assets/stylesheets/chart.css METASEP
.loading:before {
  content: "Loading...";
  color: #4171cd;
  font-size: 0.95em;
  width: auto;
  display: block;
  text-align: right;
}

.playing:before {
  content: "Playing...";
  color: #4171cd;
  font-size: 0.95em;
  width: auto;
  display: block;
  text-align: right;
}

.replay:before {
  content: "Tap to play";
  color: #4171cd;
  font-size: 0.95em;
  width: auto;
  display: block;
  text-align: right;
}

.showcase:before {
  content: "Tap to reload";
  color: #4171cd;
  font-size: 0.95em;
  width: auto;
  display: block;
  text-align: left;
}

docs/assets/javascripts/thumbs.js METASEP
function setupVideos() {
  const videos = document.querySelectorAll("video.image-gallery");
  videos.forEach((video) => {
    const playPromise = video.play();
    if (playPromise !== undefined) {
      playPromise.then((_) => {
        const observer = new IntersectionObserver(
          (entries) => {
            entries.forEach((entry) => {
              if (entry.intersectionRatio !== 1 && !video.paused) {
                video.pause();
              } else if (video.paused) {
                video.play();
              }
            });
          },
          { threshold: 0.2 },
        );
        observer.observe(video);
      });
    }
  });
}

const currentScript = document.currentScript;
document.addEventListener("DOMContentLoaded", (event) => {
  const parentContainer = currentScript.nextElementSibling;
  parentContainer.style.display = "flex";
  parentContainer.style["flex-wrap"] = "wrap";
  parentContainer.style.justifyContent = "center";
  setupVideos();
});

docs/assets/javascripts/style_ref_clickevent.js METASEP
function calcMaxHeight(elem) {
  const content = elem.nextElementSibling;
  const button = elem.getElementsByTagName("button")[0];
  if (button.textContent.includes("-")) {
    content.style.maxHeight = content.scrollHeight + "px";
  } else {
    content.style.maxHeight = "0";
  }
  const nextParentContent = elem.closest(".collapsible-style-content");
  if (nextParentContent !== null) {
    const nextParentCollapsible = nextParentContent.previousElementSibling;
    setTimeout(function () {
      calcMaxHeight(nextParentCollapsible);
    }, animationDelay);
  }
}

const coll = document.getElementsByClassName("collapsible-style");
const animationDelay = 110;
for (let i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function () {
    const button = this.getElementsByTagName("button")[0];
    if (button.textContent.includes("+")) {
      button.textContent = button.textContent.replace("+", "-");
    } else {
      button.textContent = button.textContent.replace("-", "+");
    }
    calcMaxHeight(this);
  });
}

docs/assets/javascripts/style_ref_allbtn.js METASEP
const pAll = document.getElementById("allbtn-style");
const btnAll = pAll.getElementsByTagName("button")[0];
pAll.addEventListener("click", function () {
  const collapsible = btnAll.textContent.includes("-");
  const coll = document.getElementsByClassName("collapsible-style");
  for (let i = 0; i < coll.length; i++) {
    const button = coll[i].getElementsByTagName("button")[0];
    if (collapsible && button.textContent.includes("-")) {
      coll[i].click();
      btnAll.textContent = "+ expand all";
    }
    if (!collapsible && button.textContent.includes("+")) {
      coll[i].click();
      btnAll.textContent = "- collapse all";
    }
  }
});

docs/assets/javascripts/mdchart.js METASEP
class MdChart {
  constructor(data, vizzu, id) {
    this.data = data;
    this.vizzuLoaded = import(vizzu).then((vizzuUrl) => {
      return import(vizzuUrl.default);
    });
    this.id = id;
  }

  create(snippets) {
    let chart = Promise.resolve();
    for (let i = 0; i < snippets.length; i++) {
      const number = i + 1;
      chart = this.animate(("0" + number).slice(-2), snippets[i], chart);
    }
  }

  restore(number, snippet, prevChart, snapshot, chart) {
    const div = document.getElementById(this.id + "_" + number);

    return Promise.all([chart, prevChart]).then((results) => {
      let chart = results[0];
      const prevChart = results[1];
      div.classList.remove("loading");
      div.classList.add("playing");
      let animTarget;
      if (snapshot && !prevChart) {
        animTarget = snapshot;
      } else {
        animTarget = {};
        if (prevChart) {
          animTarget.config = Object.assign({}, prevChart.config);
          animTarget.style = Object.assign({}, prevChart.style);
          // remove if it can be found in the prevChart
          if (snippet.initDataFilter) {
            animTarget.data = { filter: snippet.initDataFilter };
          }
        }
      }
      chart = chart.animate(animTarget);
      chart.activated.then((control) => control.seek("100%"));
      return chart;
    });
  }

  animate(number, snippet, prevChart) {
    const div = document.getElementById(this.id + "_" + number);
    div.classList.add("loading");

    let snapshot;

    let chart = this.vizzuLoaded.then((Vizzu) => {
      const VizzuConstructor = Vizzu.default;
      return new VizzuConstructor(div, { data: this.data }).initializing;
    });

    chart = this.restore(number, snippet, prevChart, snapshot, chart);

    chart = chart.then((chart) => {
      snapshot = chart.store();
      return chart;
    });

    let firstRun = true;
    let clicked = false;
    div.onclick = () => {
      if (!clicked) {
        clicked = true;

        chart = this.restore(number, snippet, prevChart, snapshot, chart);
        chart.then(() => {
          div.classList.remove("replay");
          div.classList.add("playing");
        });
        for (let i = 0; i < snippet.anims.length; i++) {
          chart = chart.then((chart) => {
            chart = snippet.anims[i](chart, {});
            if (this.id === "tutorial" && firstRun && chart.activated) {
              chart.activated.then((control) => control.seek("100%"));
            }
            return chart;
          });
        }
        chart.then(() => {
          div.classList.remove("playing");
          div.classList.add("replay");
          clicked = false;
          firstRun = false;
        });

        return chart;
      }
    };
    div.click();

    return chart;
  }
}

export default MdChart;

docs/assets/javascripts/highlight.js METASEP
document.addEventListener("DOMContentLoaded", (event) => {
  document.querySelectorAll("pre code").forEach((el) => {
    if (window.location.href.includes("LICENSE")) {
      return;
    }

    if (window.location.href.includes("/reference/ipyvizzu/")) {
      el.classList.add("language-python");
    }

    hljs.highlightElement(el); // eslint-disable-line no-undef
    if (
      window.location.href.includes("/examples/") ||
      window.location.href.includes("/showcases/") ||
      window.location.href.includes("/reference/") ||
      window.location.href.includes("/environments/")
    ) {
      hljs.lineNumbersBlock(el); // eslint-disable-line no-undef
    }
  });
});

docs/assets/javascripts/extlinks.js METASEP
function changeTarget(links, target) {
  for (let i = 0; i < links.length; i++) {
    if (
      links[i].hostname !== window.location.hostname ||
      links[i].href.includes("/assets/")
    ) {
      links[i].target = target;
    }
  }
}

document.addEventListener("DOMContentLoaded", (event) => {
  const target = "_blank";
  changeTarget(document.links, target);

  const iframe = document.getElementById("coviframe");
  if (iframe) {
    iframe.addEventListener("load", (event) => {
      changeTarget(
        iframe.contentWindow.document.getElementsByTagName("a"),
        target,
      );
    });
  }
});

docs/assets/javascripts/csv2js.js METASEP
import * as d3 from "https://cdn.jsdelivr.net/npm/d3@7/+esm";

class Csv2Js {
  static csv(csv, dimensions, measures) {
    return new Promise((resolve, reject) => {
      if (!dimensions) {
        dimensions = [];
      }
      if (!measures) {
        measures = [];
      }
      const detectedDimensions = {};
      const data = { series: [], records: [] };
      const csvLoaded = d3.csv(csv);

      csvLoaded.then((csvData) => {
        for (let i = 0; i < csvData.length; i++) {
          const record = [];
          const keys = Object.keys(csvData[i]);
          for (const key of keys) {
            const numValue = +csvData[i][key];
            if (csvData[i][key] !== "" && !isNaN(numValue)) {
              record.push(numValue);
            } else {
              record.push(csvData[i][key]);
              detectedDimensions[key] = true;
            }
          }
          data.records.push(record);
        }
        for (let i = 0; i < csvData.columns.length; i++) {
          const key = csvData.columns[i];
          const series = {
            name: key,
            type:
              dimensions.includes(key) ||
              (detectedDimensions[key] && !measures.includes(key))
                ? "dimension"
                : "measure",
          };
          data.series.push(series);
        }
        return resolve(data);
      });
    });
  }
}

export default Csv2Js;

docs/assets/data/music_data.xlsx METASEP

docs/assets/data/music_data.json METASEP
{
  "dimensions": [
    { "name": "Genres", "values": ["Pop", "Rock", "Jazz", "Metal"] },
    { "name": "Kinds", "values": ["Hard", "Smooth", "Experimental"] }
  ],
  "measures": [
    {
      "name": "Popularity",
      "values": [
        [114, 96, 78, 52],
        [56, 36, 174, 121],
        [127, 83, 94, 58]
      ]
    }
  ]
}

docs/assets/data/music_data.js METASEP
const data = {
  series: [
    {
      name: "Genres",
      type: "dimension",
      values: [
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
      ],
    },
    {
      name: "Kinds",
      type: "dimension",
      values: [
        "Hard",
        "Hard",
        "Hard",
        "Hard",
        "Smooth",
        "Experimental",
        "Smooth",
        "Smooth",
        "Experimental",
        "Experimental",
        "Experimental",
        "Experimental",
      ],
    },
    {
      name: "Popularity",
      type: "measure",
      values: [114, 96, 78, 52, 56, 36, 174, 121, 127, 83, 94, 58],
    },
  ],
};

export default data;

docs/assets/data/music_data.csv METASEP
Genres,Kinds,Popularity
Pop,Hard,114
Rock,Hard,96
Jazz,Hard,78
Metal,Hard,52
Pop,Smooth,56
Rock,Experimental,36
Jazz,Smooth,174
Metal,Smooth,121
Pop,Experimental,127
Rock,Experimental,83
Jazz,Experimental,94
Metal,Experimental,58
tools/docs/style/gen_style_reference.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
import sys

import mkdocs_gen_files


REPO_PATH = Path(__file__).parent / ".." / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"
MKDOCS_PATH = TOOLS_PATH / "docs"
GEN_PATH = MKDOCS_PATH / "style"

sys.path.insert(0, str(TOOLS_PATH / "modules"))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from node import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Node,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
)


class StyleReference:
    # pylint: disable=too-few-public-methods

    @staticmethod
    def generate(dst: str) -> None:
        content = Node.node(
            True,
            GEN_PATH / "gen_style_reference.mjs",
            Vizzu.get_vizzu_styleref_backend_url(),
        )
        with mkdocs_gen_files.open(dst, "a") as f_index:
            f_index.write(f"\n{content}\n")


def main() -> None:
    with chdir(REPO_PATH):
        StyleReference.generate(dst="tutorial/style.md")


main()

tools/docs/snippets/gen_vizzu.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
import sys

import mkdocs_gen_files


REPO_PATH = Path(__file__).parent / ".." / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"
MKDOCS_PATH = TOOLS_PATH / "docs"

sys.path.insert(0, str(TOOLS_PATH / "modules"))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
)


class VizzuUrl:
    # pylint: disable=too-few-public-methods

    TEMPLATE = 'const vizzu = "{vizzu}";\n\nexport default vizzu;\n'

    @staticmethod
    def generate(dst: str) -> None:
        with mkdocs_gen_files.open(dst, "w") as f_vizzu:
            f_vizzu.write(VizzuUrl.TEMPLATE.format(vizzu=Vizzu.get_vizzu_backend_url()))


def main() -> None:
    with chdir(REPO_PATH):
        VizzuUrl.generate("assets/javascripts/vizzu.js")


main()

tools/docs/reference/gen_reference.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
import sys
from types import ModuleType

import mkdocs_gen_files  # type: ignore

import ipyvizzu

REPO_PATH = Path(__file__).parent / ".." / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"
MKDOCS_PATH = TOOLS_PATH / "docs"

sys.path.insert(0, str(TOOLS_PATH / "modules"))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
    VIZZU_SITE_URL,
)


class Reference:
    @staticmethod
    def generate(package: ModuleType, folder: str) -> None:
        for path in sorted(Path("src").rglob("*.py")):
            module_path = path.relative_to("src").with_suffix("")

            doc_path = path.relative_to("src").with_suffix(".md")
            full_doc_path = Path(folder, doc_path)

            parts = tuple(module_path.parts)

            if parts[-1] == "__main__":
                continue
            if parts[-1] == "__init__":
                parts = parts[:-1]
                doc_path = doc_path.with_name("index.md")
                full_doc_path = full_doc_path.with_name("index.md")

            item = ".".join(parts)
            if item == package.__name__:
                mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path)
                with mkdocs_gen_files.open(full_doc_path, "w") as f_md:
                    f_md.write(f"{package.__doc__}\n")
                    for item in package.__all__:
                        f_md.write(f"::: {package.__name__}.{item}\n")
                        f_md.write("    options:\n")
                        f_md.write("      show_root_members_full_path: false\n")
            else:
                mkdocs_gen_files.set_edit_path(full_doc_path, ".." / path)
                with mkdocs_gen_files.open(full_doc_path, "w") as f_md:
                    f_md.write(f"::: {item}")

    @staticmethod
    def generate_version_script(file: str) -> None:
        with mkdocs_gen_files.open(file, "w") as f_js:
            vizzu_version = Vizzu.get_vizzu_version()
            f_js.write(
                f"""
document.addEventListener("DOMContentLoaded", (event) => {{
  if (window.location.href.includes("/reference/")) {{
    const links = document.links;
    for (let i = 0; i < links.length; i++) {{
      if (
        links[i].hostname !== window.location.hostname &&
        links[i].href.includes("{VIZZU_SITE_URL}")
      ) {{
        links[i].href = links[i].href.replace("latest", "{vizzu_version}");
      }}
    }}
  }}
}});
            """
            )


def main() -> None:
    with chdir(REPO_PATH):
        Reference.generate(ipyvizzu, "reference")
        Reference.generate_version_script("assets/javascripts/codereflinks.js")


main()

tools/docs/pages/gen_pages.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import os
from pathlib import Path
from typing import Union, Optional, List
import sys

import mkdocs_gen_files  # type: ignore


REPO_PATH = Path(__file__).parent / ".." / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"
MKDOCS_PATH = TOOLS_PATH / "docs"

sys.path.insert(0, str(TOOLS_PATH / "modules"))
sys.path.insert(0, str(TOOLS_PATH / "ci"))
sys.path.insert(0, str(MKDOCS_PATH))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
)
from markdown_format import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Markdown,
)
from config import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    MkdocsConfig,
)


class IndexPages:
    # pylint: disable=too-few-public-methods

    @staticmethod
    def _write_index_file(file: str, toc: list) -> None:
        for item in toc:
            if isinstance(item, str):
                IndexPages._write_str_index(file, item)
            elif isinstance(item, dict):
                IndexPages._write_dict_index(file, item)
            else:
                raise NotImplementedError(f"{item}")

    @staticmethod
    def _write_str_index(file: str, item: str) -> None:
        with mkdocs_gen_files.open(file, "a") as f_index:
            parts = item.split("/")
            part = parts[-1].replace(".md", "").capitalize()
            link = Path(os.path.relpath(item, Path(file).parent))
            f_index.write(f"* [{part}]({link})\n")

    @staticmethod
    def _write_dict_index(file: str, item: dict) -> None:
        with mkdocs_gen_files.open(file, "a") as f_index:
            for key in item:
                if isinstance(item[key], str):
                    link = Path(os.path.relpath(item[key], Path(file).parent))
                    f_index.write(f"* [{key}]({link})\n")
                    continue
                if item[key] and isinstance(item[key], list):
                    if isinstance(item[key][0], str):
                        if item[key][0].endswith("index.md"):
                            link = Path(
                                os.path.relpath(item[key][0], Path(file).parent)
                            )
                            f_index.write(f"* [{key}]({link})\n")
                            continue
                raise NotImplementedError(f"{item}")

    @staticmethod
    def generate(
        nav_item: Union[list, dict, str], skip: Optional[List[str]] = None
    ) -> None:
        if isinstance(nav_item, list):
            if (
                nav_item
                and isinstance(nav_item[0], str)
                and nav_item[0].endswith("index.md")
            ):
                if not skip or nav_item[0] not in skip:
                    original = Path("docs", nav_item[0])
                    if original.exists():
                        mkdocs_gen_files.set_edit_path(nav_item[0], nav_item[0])
                    with mkdocs_gen_files.open(nav_item[0], "a") as f_index:
                        f_index.write("\n")
                    IndexPages._write_index_file(file=nav_item[0], toc=nav_item[1:])
            for item in nav_item:
                IndexPages.generate(nav_item=item, skip=skip)
        elif isinstance(nav_item, dict):
            for key in nav_item:
                IndexPages.generate(nav_item=nav_item[key], skip=skip)


class Page:
    # pylint: disable=too-few-public-methods

    @staticmethod
    def generate(src: Path, dst: str, pos: str, site: str, keep: bool = False) -> None:
        with open(src, "rt", encoding="utf8") as f_src:
            content = f_src.read()

        content = content.replace(f"{site}/latest/", pos).replace(f"{site}/latest", pos)
        if dst == "index.md":
            example = "./showcases/titanic/titanic.csv"
            content = content.replace(example, f"{site}/latest/{example[2:]}")
        content = Vizzu.set_version(content)
        if keep:
            content = f"<pre>{content}</pre>"

        mkdocs_gen_files.set_edit_path(dst, ".." / Path(dst).parent / Path(src).name)
        with mkdocs_gen_files.open(dst, "w") as f_dst:
            f_dst.write(content)


class Docs:
    # pylint: disable=too-few-public-methods

    @staticmethod
    def generate(skip: Optional[List[str]] = None) -> None:
        docs_path = REPO_PATH / "docs"
        for path in list(docs_path.rglob("*.md")) + list(docs_path.rglob("*.js")):
            if skip and path.name in skip:
                continue
            with open(path, "rt", encoding="utf8") as f_src:
                dst = path.relative_to(docs_path)
                content = f_src.read()
                if path.suffix == ".md":
                    content = Vizzu.set_version(content)
                    content = Markdown.format(content)
                    mkdocs_gen_files.set_edit_path(dst, dst)
                with mkdocs_gen_files.open(dst, "w") as f_dst:
                    f_dst.write(content)


def main() -> None:
    with chdir(REPO_PATH):
        config = MkdocsConfig.load(MKDOCS_PATH / "mkdocs.yml")

        Docs.generate()

        IndexPages.generate(
            nav_item=config["nav"],
            skip=["examples/index.md", "examples/analytical_operations/index.md"],
        )

        Page.generate(
            src=REPO_PATH / "README.md",
            dst="index.md",
            pos="./",
            site=config["site_url"],
        )

        Page.generate(
            src=REPO_PATH / "CONTRIBUTING.md",
            dst="CONTRIBUTING.md",
            pos="../",
            site=config["site_url"],
        )

        Page.generate(
            src=REPO_PATH / "CODE_OF_CONDUCT.md",
            dst="CODE_OF_CONDUCT.md",
            pos="../",
            site=config["site_url"],
        )

        Page.generate(
            src=REPO_PATH / "LICENSE",
            dst="LICENSE.md",
            pos="../",
            site=config["site_url"],
            keep=True,
        )


main()

tools/docs/examples/gen_examples.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import os
from pathlib import Path
import re
import sys
from typing import List, Dict, Optional, Union, Tuple

import mkdocs_gen_files
import markdown


REPO_PATH = Path(__file__).parent / ".." / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"
MKDOCS_PATH = TOOLS_PATH / "docs"
GEN_PATH = MKDOCS_PATH / "examples"
VIZZU_LIB_PATH = REPO_PATH / "vizzu-lib"
WEB_CONTENT_PATH = (
    VIZZU_LIB_PATH / "test" / "integration" / "test_cases" / "web_content"
)
TEST_DATA_PATH = VIZZU_LIB_PATH / "test" / "integration" / "test_data"
STATIC_EXAMPLES_PATH = WEB_CONTENT_PATH / "static"
OPERATION_EXAMPLES_PATH = WEB_CONTENT_PATH / "analytical_operations"
PRESET_EXAMPLES_PATH = WEB_CONTENT_PATH / "presets"
SHOWCASES_PATH = REPO_PATH / "docs" / "showcases"
JS_ASSETS_PATH = "assets/javascripts"

sys.path.insert(0, str(TOOLS_PATH / "modules"))
sys.path.insert(0, str(TOOLS_PATH / "ci"))
sys.path.insert(0, str(MKDOCS_PATH))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from node import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Node,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
    VIZZU_SITE_URL,
)
from markdown_format import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Markdown,
)
from config import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    MkdocsConfig,
)


class GenExamples:
    # pylint: disable=too-many-instance-attributes

    datafiles: Dict[str, bool] = {}

    datafile_re = re.compile(r"test_data\/(\w*).mjs")
    dataname_re = re.compile(r"import\s*\{\s*(.*)\s*}")
    title_re = re.compile(r'title\:\s"(.*)"')

    def __init__(self, name: str, src: Path, dst: str) -> None:
        self._name = name

        self._src = src
        self._dst = dst
        self._depth = len(dst.split("/")) + 1

        self._generated: List[str] = []
        self._indices: List[str] = []

        self._merge_subfolders = False
        self._video_thumbnails = False
        self._blocked: List[str] = []

    @property
    def merge_subfolders(self) -> bool:
        return self._merge_subfolders

    @merge_subfolders.setter
    def merge_subfolders(self, value: bool) -> None:
        self._merge_subfolders = value

    @property
    def video_thumbnails(self) -> bool:
        return self._video_thumbnails

    @video_thumbnails.setter
    def video_thumbnails(self, value: bool) -> None:
        self._video_thumbnails = value

    @property
    def blocked(self) -> List[str]:
        return self._blocked

    @blocked.setter
    def blocked(self, items: List[str]) -> None:
        self._blocked = items

    @staticmethod
    def _get_content(item: Path) -> str:
        with open(item, "r", encoding="utf8") as fh_item:
            return fh_item.read()

    def _get_title(self, item: Path, sub: Optional[str] = None) -> str:
        drop = ["Existingmeasure", "Newmeasure"]
        conjunction = ["and", "from", "to", "with"]
        title_parts = str(item.stem).split("_")
        contains_conjunction = False
        for index, title_part in enumerate(title_parts):
            if title_part in conjunction:
                contains_conjunction = True
                continue
            title_parts[index] = title_part.capitalize()
        title_parts[0] = title_parts[0].capitalize()
        if title_parts[0] in drop:
            title_parts = title_parts[1:]
        title = " ".join(title_parts)
        if not contains_conjunction:
            if title_parts[-1].isdigit():
                title = " ".join(
                    title_parts[1:-1] + [title_parts[0]] + [title_parts[-1]]
                )
            else:
                title = " ".join(title_parts[1:] + [title_parts[0]])
        if sub:
            title = " ".join([title, sub.capitalize()])
        title = title.replace("plot", " Plot")
        return title

    def _get_datafile(self, item: Path, content: str) -> str:
        datafiles = re.findall(GenExamples.datafile_re, content)
        if not datafiles or len(datafiles) > 1:
            raise ValueError(f"failed to find datafile {item}")
        datafile = "".join(datafiles)
        return datafile

    def _get_dataname(self, item: Path, content: str) -> str:
        datanames = re.findall(GenExamples.dataname_re, content)
        if not datanames or len(datanames) > 1:
            raise ValueError(f"failed to find dataname {item}")
        dataname = "".join(datanames)
        dataname = dataname.strip()
        return dataname

    def _get_sub(self, path: Path) -> Optional[str]:
        sub = os.path.relpath(path.parent, self._src)
        if self._merge_subfolders and sub != ".":
            return sub
        return None

    def _create_index(self, dst: str, depth: int, title: str) -> str:
        index = "/".join([self._dst, dst]) if dst != "." else self._dst
        assets = "/".join([".."] * (depth - 1))
        if index not in self._indices:
            with mkdocs_gen_files.open(f"{index}/index.md", "a") as fh_index:
                meta = """---\nhide:\n  - toc\n---"""
                fh_index.write(f"{meta}\n\n")
                fh_index.write(f"# {title}\n")
                fh_index.write(
                    f'<script src="{assets + "/" + JS_ASSETS_PATH}/thumbs.js"></script>\n'
                )
            self._indices.append(index)

        return index

    def _add_index_item(  # pylint: disable=too-many-arguments
        self,
        index: str,
        title: str,
        href: str,
        thumbnail: Optional[str] = None,
        figcaption: bool = False,
    ) -> None:
        if not thumbnail:
            thumbnail = href
        if self._video_thumbnails:
            self._add_video(index, title, href, thumbnail, figcaption)
        else:
            self._add_image(index, title, href, thumbnail)

    def _add_index_sub_menus(self, index: str, groups: dict) -> None:
        with mkdocs_gen_files.open(f"{index}/index.md", "a") as fh_index:
            fh_index.write("<pre>")
        sorted_items = {}
        items = []
        for group_title in groups.keys():
            number = groups[group_title]["number"]
            if number:
                sorted_items[number] = group_title
            else:
                items.append(group_title)
        numbers = list(sorted_items.keys())
        numbers.sort()
        numbers.reverse()
        for number in numbers:
            items.insert(0, sorted_items[number])
        for group_title in items:
            self._add_index_item(
                index,
                group_title,
                groups[group_title]["dst"],
                groups[group_title]["dst"] + "/" + groups[group_title]["item"].stem,
                True,
            )
        with mkdocs_gen_files.open(f"{index}/index.md", "a") as fh_index:
            fh_index.write("</pre>\n")

    def _add_image(self, index: str, title: str, href: str, thumbnail: str) -> None:
        with mkdocs_gen_files.open(f"{index}/index.md", "a") as fh_index:
            url = f"{VIZZU_SITE_URL}/{Vizzu.get_vizzu_version()}/{index}"
            fh_index.write(
                "["
                + f"![{title}]"
                + f"({url}/{thumbnail}.png)"
                + f"{{ class='image-gallery', title='{title}' }}"
                + "]"
                + f"(./{href}.md)\n"
            )

    def _add_video(  # pylint: disable=too-many-arguments
        self, index: str, title: str, href: str, thumbnail: str, figcaption: bool
    ) -> None:
        url = f"{VIZZU_SITE_URL}/{Vizzu.get_vizzu_version()}/{index}"
        with mkdocs_gen_files.open(f"{index}/index.md", "a") as fh_index:
            html = []
            html.append(f"<a href='./{href}/' title='{title}'>")
            if figcaption:
                html.append("<figure markdown class='image-figure'>")
                html.append(
                    "<video nocontrols autoplay muted loop class='image-gallery-w-caption'"
                )
            else:
                html.append(
                    "<video nocontrols autoplay muted loop class='image-gallery'"
                )
            html.append(f" src='{url}/{thumbnail}.webm'")
            html.append(" type='video/webm'>")
            html.append(f" src='{url}/{thumbnail}.mp4'")
            html.append(" type='video/mp4'>")
            html.append("</video>")
            if figcaption:
                html.append(f"<figcaption class='image-caption'>{title}</figcaption>")
                html.append("</figure>")
            html.append("</a>\n")
            fh_index.write("".join(html))

    @staticmethod
    def _find_dict_with_value(
        data: Union[dict, list], val: str
    ) -> Tuple[Optional[str], Optional[int]]:
        if isinstance(data, dict):
            return GenExamples._find_dict_with_value_in_dict(data, val)
        if isinstance(data, list):
            return GenExamples._find_dict_with_value_in_list(data, val)
        return None, None

    @staticmethod
    def _find_dict_with_value_in_dict(
        data: dict, val: str
    ) -> Tuple[Optional[str], Optional[int]]:
        for key, value in data.items():
            if isinstance(value, dict):
                if len(value) == 1 and val in value.values():
                    return key, None
                nested_result = GenExamples._find_dict_with_value(value, val)
                if nested_result != (None, None):
                    return nested_result
            if isinstance(value, list):
                nested_result = GenExamples._find_dict_with_value(value, val)
                if nested_result != (None, None):
                    return nested_result
            if value == val:
                return key, None
        return None, None

    @staticmethod
    def _find_dict_with_value_in_list(
        data: list, val: str
    ) -> Tuple[Optional[str], Optional[int]]:
        for i, item in enumerate(data):
            if isinstance(item, dict) and len(item) == 1 and val in item.values():
                return list(item.keys())[0], i
            if isinstance(item, (list, dict)):
                nested_result = GenExamples._find_dict_with_value(item, val)
                if nested_result != (None, None):
                    return nested_result
            if item == val:
                return None, i
        return None, None

    @staticmethod
    def _generate_example_data(datafile: str, dataname: str) -> None:
        datakey = "_".join([datafile, dataname])
        if dataname == "data":
            datakey = datafile
        if datakey not in GenExamples.datafiles:
            GenExamples.datafiles[datakey] = True

            datacontent = GenExamples._get_content(TEST_DATA_PATH / f"{datafile}.mjs")
            with mkdocs_gen_files.open(f"assets/data/{datafile}.js", "w") as fh_data:
                fh_data.write(datacontent)

            content = Node.node(
                True,
                GEN_PATH / "mjs2csv.mjs",
                f"{TEST_DATA_PATH}/{datafile}.mjs",
                dataname,
            )
            with mkdocs_gen_files.open(f"assets/data/{datakey}.csv", "w") as f_example:
                f_example.write(content)

    def _generate_example_js(  # pylint: disable=too-many-arguments
        self,
        item: Path,
        item_name: str,
        dst: str,
        depth: int,
        datafile: str,
        dataname: str,
    ) -> None:
        params = [str(item), "/".join([".."] * depth), datafile, dataname]
        content = Node.node(True, GEN_PATH / "mjs2js.mjs", *params)
        with mkdocs_gen_files.open(
            f"{self._dst}/{dst}/{item_name}/main.js", "w"
        ) as f_example:
            f_example.write(content)

    def _generate_example_md(  # pylint: disable=too-many-arguments
        self,
        item: Path,
        item_name: str,
        dst: str,
        depth: int,
        datafile: str,
        dataname: str,
        title: str,
    ) -> None:
        params = [
            str(item),
            str(TEST_DATA_PATH),
            "/".join([".."] * depth),
            datafile,
            dataname,
            title,
        ]
        content = Node.node(True, GEN_PATH / "mjs2md.mjs", *params)
        content = Vizzu.set_version(content)
        content = Markdown.format(content)
        with mkdocs_gen_files.open(
            f"{self._dst}/{dst}/{item_name}.md", "w"
        ) as f_example:
            f_example.write(content)

    def _generate_example(  # pylint: disable=too-many-arguments
        self,
        item: Path,
        item_name: str,
        dst: str,
        depth: int,
        datafile: str,
        dataname: str,
        title: str,
    ) -> None:
        self._generate_example_md(
            item, item_name, dst, depth, datafile, dataname, title
        )
        self._generate_example_js(item, item_name, dst, depth, datafile, dataname)
        GenExamples._generate_example_data(datafile, dataname)

    def generate(self) -> None:
        # pylint: disable=too-many-locals

        config = MkdocsConfig.load(MKDOCS_PATH / "mkdocs.yml")
        dst = "."
        depth = self._depth
        index = self._create_index(dst, depth, self._name)
        groups = {}
        items = list(self._src.rglob("*.mjs"))
        items.sort(key=lambda f: f.stem)
        for item in items:
            if item in self._blocked:
                continue
            item_name = item.stem
            dst = "."
            depth = self._depth
            sub_index = index
            sub = self._get_sub(item)
            if sub:
                item_name += f"_{sub}"
            if self._merge_subfolders:
                if item_name in self._generated:
                    raise ValueError(f"example already exists {item_name}")
                self._generated.append(item_name)
            else:
                dst = os.path.relpath(item.parent, self._src)
                depth += dst.count("/")
                value = self._dst + "/"
                if dst != ".":
                    depth += 1
                    value += dst + "/"
                group_title, number = GenExamples._find_dict_with_value(
                    config["nav"], value
                )
                if group_title and group_title not in groups:
                    groups[group_title] = {"item": item, "dst": dst, "number": number}
                sub_index = self._create_index(dst, depth, group_title)  # type: ignore
            content = GenExamples._get_content(item)
            datafile = self._get_datafile(item, content)
            dataname = self._get_dataname(item, content)
            title = self._get_title(item, sub)
            self._add_index_item(sub_index, title, item_name)
            self._generate_example(
                item, item_name, dst, depth, datafile, dataname, title
            )
        self._add_index_sub_menus(index, groups)


class GenShowcases(GenExamples):
    def generate(self) -> None:
        dst = "."
        depth = self._depth
        index = self._create_index(dst, depth, self._name)

        items = list(self._src.rglob("*.js")) + list(self._src.rglob("main.html"))
        for item in items:
            content = GenExamples._get_content(item)
            content = Vizzu.set_version(content)
            with mkdocs_gen_files.open(
                self._dst + "/" + os.path.relpath(item, SHOWCASES_PATH), "w"
            ) as fh_js:
                fh_js.write(content)

        items = list(self._src.rglob("*.md"))
        items.sort(key=lambda f: f.stem)
        for item in items:
            content = GenExamples._get_content(item)
            html = markdown.markdown(content)
            h1_titles = re.findall(r"<h1.*?>(.*?)</h1>", html)
            self._add_index_item(index, h1_titles[0], item.stem)


def main() -> None:
    with chdir(REPO_PATH):
        presets = GenExamples(
            "Preset charts",
            PRESET_EXAMPLES_PATH,
            "examples/presets",
        )
        presets.merge_subfolders = True
        presets.generate()

        static = GenExamples(
            "Static charts",
            STATIC_EXAMPLES_PATH,
            "examples/static",
        )
        static.merge_subfolders = True
        static.generate()

        operations = GenExamples(
            "Analytical Operations",
            OPERATION_EXAMPLES_PATH,
            "examples/analytical_operations",
        )
        operations.video_thumbnails = True
        operations.generate()

        real = GenShowcases(
            "Showcases",
            SHOWCASES_PATH,
            "showcases",
        )
        real.video_thumbnails = True
        real.generate()


main()

src/ipyvizzu/integrations/fugue.py METASEP
"""
A module for Fugue integration.

Example:
    Users should not instantiate this module directly. As long as you
    installed fugue and ipyvizzu, the extension is auto-registered.

        from fugue import fsql

        fsql('''
        SELECT a, SUM(b) AS b FROM spark.table
        GROUP BY a ORDER BY b

        OUTPUT USING vizzu:bar(x="a", y="b", title="title")
        ''').run(spark_session)
"""

from typing import Any, Dict, Tuple

import pandas as pd
from fugue import DataFrames, Outputter  # type: ignore
from fugue.exceptions import FugueWorkflowError
from fugue.extensions import namespace_candidate  # type: ignore
from fugue.plugins import parse_outputter  # type: ignore
from triad import assert_or_throw  # type: ignore

from ipyvizzu import Chart, Config, Data, DisplayTarget

_TIMELINE_DEFAULT_CONF: Dict[str, Any] = dict(  # pylint: disable=use-dict-literal
    show={"delay": 0},
    hide={"delay": 0},
    title={"duration": 0, "delay": 0},
    duration=0.5,
)


class _Visualize(Outputter):
    """
    A Fugue outputter extension (majorly for Fugue SQL)

    Args:
        func:
            A function name of [Config][ipyvizzu.animation.Config]
        category:
            Can be preset or timeline
    """

    def __init__(self, func: str, category: str) -> None:
        super().__init__()
        self._category = category
        self._func = getattr(Config, func)

    def process(self, dfs: DataFrames) -> None:
        assert_or_throw(len(dfs) == 1, FugueWorkflowError("not single input"))
        df = dfs[0].as_pandas()  # pylint: disable=invalid-name
        if self._category == "timeline":
            self._process_timeline(df)
        else:
            self._process_preset(df)

    def _process_preset(self, df: pd.DataFrame) -> None:  # pylint: disable=invalid-name
        data = Data()
        data.add_df(df)
        chart = Chart(display=DisplayTarget.END)
        chart.animate(data)
        chart.animate(self._func(dict(self.params)))

    def _process_timeline(
        self, df: pd.DataFrame  # pylint: disable=invalid-name
    ) -> None:
        _p = dict(self.params)
        _pc = dict(_p.pop("config", {}))
        title = _pc.pop("title", "%s")
        key = _p.pop("by")
        conf = dict(_TIMELINE_DEFAULT_CONF)
        conf.update(_p)

        data = Data()
        chart = Chart(display=DisplayTarget.END)
        keys = df[key].unique()
        keys.sort()
        idx = pd.DataFrame({"_idx": range(len(keys)), key: keys})
        df = df.sort_values(key).merge(idx)
        data.add_df(df)
        chart.animate(data)

        for i, key in enumerate(keys):
            _p2 = dict(_pc)
            _p2["title"] = (title % key) if "%s" in title else title
            chart.animate(Data.filter(f"record._idx == {i}"), self._func(_p2), **conf)


@parse_outputter.candidate(namespace_candidate("vizzu", lambda x: isinstance(x, str)))
def _parse_vizzu(obj: Tuple[str, str]) -> Outputter:
    if obj[1].startswith("timeline_"):
        return _Visualize(obj[1].split("_", 1)[1], "timeline")
    return _Visualize(obj[1], "preset")

src/ipyvizzu/integrations/__init__.py METASEP
"""A module for integrations."""

src/ipyvizzu/data/type_alias.py METASEP
"""
This module provides typing aliases for data used in ipyvizzu.
"""

from typing import Dict, List, Sequence, Union


DimensionValue = str
"""
Represents a value that can be either a string or a number,
but both will be treated as strings.
"""

MeasureValue = Union[int, float]
"""
Represents a numerical value, which can be either an int or a float.
"""

NestedMeasureValues = Union[MeasureValue, List["NestedMeasureValues"]]
"""
Represents a nested structure of MeasureValues.
It can be a single MeasureValue or a list containing other NestedMeasureValues.
"""

RecordValue = Union[DimensionValue, MeasureValue]
"""
Represents a value that can be either a DimensionValue or a MeasureValue.
"""

Record = Union[List[RecordValue], Dict[str, RecordValue]]
"""
Represents a Record, which is a collection of RecordValues.
A Record can be represented as either a list of RecordValues or a dictionary
where keys are series names and values are the corresponding RecordValues.
"""

SeriesValues = Union[Sequence[DimensionValue], Sequence[MeasureValue]]
"""
Represents a collection of values for a Series.
It can be a list of DimensionValues or a list of MeasureValues.
"""

Series = Dict[str, Union[str, SeriesValues]]
"""
Represents a Series in a dictionary format.
It consists of a name (string), an optional type (also a string),
and a values key which contains a SeriesValues.
"""

src/ipyvizzu/data/infer_type.py METASEP
"""
This module provides the `InferType` class, which stores data infer types.
"""

from enum import Enum


class InferType(Enum):
    """
    An enum class for storing data infer types.

    Attributes:
        DIMENSION: An enum key-value for storing dimension infer type.
            Dimensions are categorical series that can contain strings and numbers,
            but both will be treated as strings.

        MEASURE: An enum key-value for storing measure infer type.
            Measures can only be numerical.
    """

    DIMENSION: str = "dimension"
    MEASURE: str = "measure"

src/ipyvizzu/data/__init__.py METASEP
"""
This module serves as a collection of data-related utilities,
including converter classes, data infer types and data typing aliases.
"""

tools/docs/mkdocs.yml METASEP
strict: true

site_name: ipyvizzu
site_url: https://ipyvizzu.vizzuhq.com/
copyright: Copyright &copy; 2022-2023 Vizzu Inc.

docs_dir: ../../docs
site_dir: ../../site

repo_url: https://github.com/vizzuhq/ipyvizzu
edit_uri: https://github.com/vizzuhq/ipyvizzu/edit/main/docs
use_directory_urls: true

theme:
  name: material
  palette:
    scheme: vizzu
  font:
    text: Roboto
    code: Roboto Mono
  logo: assets/logo-white.svg
  favicon: assets/favicon.svg
  custom_dir: ./overrides
  features:
    - toc.follow
    - search.suggest
    - search.highlight
    - navigation.top
    - navigation.footer
    - content.code.copy
    - content.action.edit

extra_css:
  - assets/stylesheets/vizzu.css
  - assets/stylesheets/highlight.css
  - assets/stylesheets/gallery.css
  - assets/stylesheets/chart.css
  - assets/stylesheets/style_reference.css

extra_javascript:
  - assets/javascripts/extlinks.js
  - assets/javascripts/codereflinks.js
  - //cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.7/build/highlight.min.js
  - //cdn.jsdelivr.net/npm/highlightjs-line-numbers.js@2.8.0/dist/highlightjs-line-numbers.min.js
  - assets/javascripts/highlight.js

extra:
  version:
    provider: mike
    default: latest
  social:
    - icon: fontawesome/brands/slack
      name: Vizzu on Slack
      link: https://join.slack.com/t/vizzu-community/shared_invite/zt-w2nqhq44-2CCWL4o7qn2Ns1EFSf9kEg
    - icon: fontawesome/brands/twitter
      name: Vizzu on Twitter
      link: https://twitter.com/VizzuHQ
    - icon: fontawesome/brands/reddit
      name: Vizzu on Reddit
      link: https://www.reddit.com/user/VizzuHQ/?sort=top
    - icon: fontawesome/brands/github
      name: Vizzu on GitHub
      link: https://github.com/vizzuhq/

markdown_extensions:
  - pymdownx.tasklist:
      custom_checkbox: true
  - mdx_truly_sane_lists
  - attr_list
  - md_in_html
  - admonition
  - pymdownx.highlight:
      use_pygments: false
  - pymdownx.details
  - pymdownx.superfences

plugins:
  - mike:
      version_selector: true
      alias_type: symlink
      canonical_version: latest
      redirect_template: ./tools/docs/overrides/mike/redirect.html
  - search
  - section-index
  - autorefs
  - mkdocstrings:
      enable_inventory: true
      handlers:
        python:
          paths: [../../src]
          options:
            members_order: source
            show_root_heading: True
            show_root_members_full_path: True
            show_submodules: True
          import:
            - https://docs.python.org/3/objects.inv
            - https://ipython.readthedocs.io/en/stable/objects.inv
            - https://python-jsonschema.readthedocs.io/en/stable/objects.inv
            - http://pandas.pydata.org/pandas-docs/stable/objects.inv
  - gen-files:
      scripts:
        - pages/gen_pages.py
        - snippets/gen_vizzu.py
        - examples/gen_examples.py
        - reference/gen_reference.py
        - style/gen_style_reference.py
  - coverage:
      page_name: coverage
      html_report_dir: .tox/py310/coverage
  - literate-nav:
      implicit_index: true

nav:
  - Home: index.md
  - installation.md
  - Tutorial:
      - tutorial/index.md
      - Chart settings: tutorial/chart_settings.md
      - tutorial/data.md
      - Axes, title, tooltip: tutorial/axes_title_tooltip.md
      - Aggregating data: tutorial/aggregating_data.md
      - tutorial/geometry.md
      - Channels & legend: tutorial/channels_legend.md
      - Group/stack: tutorial/group_stack.md
      - tutorial/sorting.md
      - Align & range: tutorial/align_range.md
      - Changing dimensions: tutorial/changing_dimensions.md
      - Orientation, split & polar: tutorial/orientation_split_polar.md
      - Filtering & adding new records: tutorial/filter_add_new_records.md
      - Without coordinates & noop channel: tutorial/without_coordinates_noop_channel.md
      - Color palette & fonts: tutorial/color_palette_fonts.md
      - Chart layout: tutorial/chart_layout.md
      - Animation options: tutorial/animation_options.md
      - Animation control & keyframes: tutorial/animation_control_keyframes.md
      - tutorial/events.md
      - Shorthands & Store: tutorial/shorthands_store.md
      - Chart presets: tutorial/chart_presets.md
      - tutorial/style.md
  - Examples:
      - examples/index.md
      - Preset charts: examples/presets/
      - Analytical operations:
          - examples/analytical_operations/index.md
          - Drill down: examples/analytical_operations/drilldown/
          - Sum: examples/analytical_operations/sum/
          - Compare: examples/analytical_operations/compare/
          - Split: examples/analytical_operations/split/
          - Stretch to proportion: examples/analytical_operations/stretch_to_proportion/
          - Distribute: examples/analytical_operations/distribute/
          - Filter: examples/analytical_operations/filter/
          - Change dimension: examples/analytical_operations/change_dimension/
          - Miscellaneous: examples/analytical_operations/misc/
      - Static charts: examples/static/
  - Showcases: showcases/
  - Code reference: reference/ipyvizzu/
  - Environments:
      - environments/index.md
      - Notebooks:
          - environments/notebook/index.md
          - Jupyter Notebook: environments/notebook/jupyternotebook.md
          - environments/notebook/colab.md
          - environments/notebook/databricks.md
          - DataCamp: environments/notebook/datacamp.md
          - environments/notebook/deepnote.md
          - JupyterLab: environments/notebook/jupyterlab.md
          - JupyterLite: environments/notebook/jupyterlite.md
          - environments/notebook/kaggle.md
          - environments/notebook/noteable.md
      - App platforms:
          - environments/platform/index.md
          - environments/platform/streamlit.md
          - environments/platform/flask.md
          - environments/platform/panel.md
          - environments/platform/mercury.md
          - Voilà: environments/platform/voila.md
      - BI tools:
          - environments/bi/index.md
          - environments/bi/mode.md
      - IDEs:
          - environments/ide/index.md
          - PyCharm: environments/ide/pycharm.md
          - VSCode Python: environments/ide/vscode.md
  - Development:
      - dev/index.md
      - Contributing: CONTRIBUTING.md
      - Code of Conduct: CODE_OF_CONDUCT.md
      - Coverage report: coverage.md
  - License: LICENSE.md

tools/ci/.pre-commit-ubuntu.yaml METASEP
repos:
  - repo: local
    hooks:
      - id: format
        name: format
        stages: [commit]
        entry: .venv/bin/python
        args: ["-m", "pdm", "run", "format"]
        language: system
        pass_filenames: false

      - id: fix_format
        stages: [push]
        name: fix_format
        entry: .venv/bin/python
        args: ["-m", "pdm", "run", "fix_format"]
        language: system
        pass_filenames: false

      - id: lint
        stages: [push]
        name: lint
        entry: .venv/bin/python
        args: ["-m", "pdm", "run", "lint"]
        language: system
        pass_filenames: false

      - id: type
        stages: [push]
        name: type
        entry: .venv/bin/python
        args: ["-m", "pdm", "run", "type"]
        language: system
        pass_filenames: false

      - id: test
        stages: [push]
        name: test
        entry: .venv/bin/python
        args: ["-m", "pdm", "run", "test"]
        language: system
        pass_filenames: false

src/ipyvizzu/py.typed METASEP

docs/tutorial/without_coordinates_noop_channel.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Without coordinates & noop channel

Certain chart types have neither measures nor dimensions on the axes such as
treemaps and bubble charts. This is a case when the `noop` channel comes in
handy for grouping and stacking elements in these kinds of charts.

To get to a treemap, we have to detach all dimensions and the measure from the
axes and put two of them on the `size` channel, whereas the other dimension is
still on the `color` channel.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Kinds", "Popularity"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"set": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {
                    "set": None,
                },
                "x": {
                    "set": None,
                },
                "size": {
                    "attach": ["Genres", "Popularity"],
                },
            }
        }
    )
)
```

Getting from a treemap to a bubble chart is simply by changing the geometry to
circle. This bubble chart is stacked by the `Kinds` dimension that is on the
`size` channel - this is why the bubbles are in separate, small groups.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "geometry": "circle",
        }
    )
)
```

In order to show all bubbles as one group, we use the `noop` (no operations)
channel for the `Genres` dimension. The `noop` channel enables us to have a
dimension on the chart, that doesn’t affect any parameter of the elements, only
their count.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "size": {"detach": "Genres"},
                "noop": {"set": "Genres"},
            }
        }
    )
)
```

<script src="../without_coordinates_noop_channel.js"></script>

docs/tutorial/without_coordinates_noop_channel.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Treemap",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  set: null,
                },
                x: {
                  set: null,
                },
                size: {
                  attach: ["Genres", "Popularity"],
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Bubble chart - stacked",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              geometry: "circle",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Bubble chart - grouped - using the noop channel",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                size: {
                  detach: "Genres",
                },
                noop: {
                  set: "Genres",
                },
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/style.md METASEP
# Style

`ipyizzu` offers a wide variety of styling options when you want to personalize
the look and feel of your animated charts. The styling properties are organized
into a hierarchical structure. Font styles, when set on a higher level of this
hierarchy, will be inherited on all lower levels. You can use absolute sizing
(`px`, `pt`) and relative (`%`, `em`, `vw`).

Similarly to all other parameters of the animate method, `ipyizzu` will animate
the changes in the styling of the charts. This provides an excellent opportunity
to check and control the effect of these changes.

## Styling properties

You can find below the complete list of the available styling properties and
their default values.

docs/tutorial/sorting.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Sorting

`ipyvizzu` provides multiple options to sort data. By default, the data is
sorted by the order it is added to `ipyvizzu`. This is why we suggest to add
temporal data such as dates in chronological order - from oldest to newest.

You can also sort the elements by value, which will provide you with an
ascending order.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"attach": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "sort": "byValue",
        }
    )
)
```

If you want descending order instead, you have to set the `reverse` parameter to
`True`. When used without setting the sorting to `byValue`, the elements will be
in the opposite order than they are in the data set added to `ipyvizzu`.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "reverse": True,
        }
    )
)
```

This is how to switch back to the default sorting.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "sort": "none",
            "reverse": False,
        }
    )
)
```

When you have more than one dimension on a channel, their order determines how
the elements are grouped. For example, below - each set of bars is first
organized by `Genres`, and then we have one bar for each of `Kinds`.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"detach": ["Kinds"]},
                "x": {"set": ["Genres", "Kinds"]},
            }
        }
    )
)
```

When switching the order of dimensions on the x-axis `ipyvizzu` will rearrange
the elements according to this new logic.

!!! note
    The legend is automatically removed during the animation.

<div id="tutorial_05"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"set": ["Kinds", "Genres"]},
            }
        }
    )
)
```

<script src="../sorting.js"></script>

docs/tutorial/sorting.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Switch to ascending order...",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { attach: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              sort: "byValue",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "...or descending order.",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              reverse: true,
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Let's get back to where we were",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              sort: "none",
              reverse: false,
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "With two discretes on one axis...",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  detach: "Kinds",
                },
                x: {
                  set: ["Genres", "Kinds"],
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "...grouping is determined by their order.",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: {
                  set: ["Kinds", "Genres"],
                },
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/shorthands_store.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Shorthands & Store

To assist you with the development we added various shorthands that will make
your code more compact.

We also added store functions, which enable you to save either a chart state or
a whole animation into a variable that you can reuse later instead of setting up
that state or animation once again.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config, Style

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "title": "Store function",
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                },
                "label": {"attach": ["Popularity"]},
                "color": {"set": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "align": "stretch",
        }
    )
)
```

Let's save this state by calling the `store` function.

```python
snapshot = chart.store()
```

If you set/attach/detach just one series on a channel, you don't have to put
that series into an array. Also, let's save this animation by calling the
`store` method of the `control` chart object.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                # "x": { "attach": [ "Kinds" ] },
                "x": {"attach": "Kinds"},
                # "y": { "detach": [ "Kinds" ] },
                "y": {"detach": "Kinds"},
            },
            "align": "none",
        }
    )
)

animation = chart.control.store()
```

If you use set on a channel and no other options like range, you don't have to
express that channel as an object. If you only set one series on a channel you
can simply write the series' name after the channel name.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                # "y": { "set": [ "Kinds", "Popularity" ] },
                "y": ["Kinds", "Popularity"],
                # "x": { "set": [ "Genres" ] },
                "x": "Genres",
            }
        }
    )
)
```

In any case, you can simply omit the `channel` object, `ipyvizzu` will
automatically recognize the channels by their names.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            # "channels": {
            "y": "Kinds",
            "x": ["Genres", "Popularity"]
            # }
        }
    )
)
```

Instead of creating nested objects, you can set the styles like this.

<div id="tutorial_05"></div>

```python
chart.animate(
    Style(
        {
            # "plot": { "xAxis": { "label": { "fontSize": "150%" } } },
            "plot.xAxis.label.fontSize": "150%",
            "title.backgroundColor": "#A0A0A0",
        }
    )
)
```

This is how you can reuse a previously stored animation.

<div id="tutorial_06"></div>

```python
chart.animate(animation)
```

You can also get back to a state that you previously stored.

<div id="tutorial_07"></div>

```python
chart.animate(snapshot)
```

<script src="../shorthands_store.js"></script>

docs/tutorial/shorthands_store.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Store function",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              align: "stretch",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "When just one series is used",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { detach: "Kinds" },
                x: { attach: "Kinds" },
              },
              align: "none",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "When you use set and no other channel options",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: ["Kinds", "Popularity"],
                x: "Genres",
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "You don't have to use the channel object",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              y: "Kinds",
              x: ["Genres", "Popularity"],
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Shorthand for styles",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              "plot.xAxis.label.fontSize": "150%",
              "title.backgroundColor": "#A0A0A0",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate(
            {
              style: null,
              config: {
                title: "Store function",
                align: "stretch",
                channels: {
                  y: { set: ["Popularity", "Kinds"] },
                  x: { set: "Genres" },
                  label: { attach: "Popularity" },
                },
                color: { set: "Kinds" },
              },
            },
            0,
          );
        },
        (chart) => {
          return chart.animate({
            config: {
              title: "When you use set and no other channel options",
            },
          });
        },
        (chart) => {
          return chart.animate({
            channels: {
              // x: { attach: [ "Kinds" ] },
              x: {
                attach: "Kinds",
              },
              // y: { detach: [ "Kinds" ] },
              y: {
                detach: "Kinds",
              },
            },
            align: "none",
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            style: null,
            config: {
              title: "Store function",
              align: "stretch",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/orientation_split_polar.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Orientation, split & polar

Now that you are familiar with the basic logic and operation of `ipyvizzu`,
let's dive in with some more advanced features that you can use to create
animated data stories and show the data from different perspectives.

Switching orientation means that you put a measure from one axis to the other to
see the data from a different perspective. This is once again a state you should
only use temporarily.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"attach": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {
                    "detach": ["Popularity"],
                },
                "x": {
                    "attach": ["Popularity"],
                },
            }
        }
    )
)
```

By turning the split parameter on, you can see stacked elements side-by-side,
which enables the comparison of the components.

<div id="tutorial_02"></div>

```python
chart.animate(Config({"split": True}))
```

Merging the components by turning the split parameter off.

<div id="tutorial_03"></div>

```python
chart.animate(Config({"split": False}))
```

We aggregate the data by removing the `Genres` dimension from the x-axis.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {
                    "detach": ["Genres"],
                }
            }
        }
    )
)
```

Switching from cartesian coordinates to polar. When doing so, it is worth
setting the axis range on the axis with the dimension so that the viewers can
easily compare the values shown. If you want to return to the default cartesian
coordinates, just set the `coordSystem` parameter to `"cartesian"`.

!!! info
    The range of the x-axis is automatically set to `max:133%` as this is the
    standard way to show radial charts.

<div id="tutorial_05"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {
                    "range": {
                        "min": "-30%",
                    },
                },
            },
            "coordSystem": "polar",
        }
    )
)
```

<script src="../orientation_split_polar.js"></script>

docs/tutorial/orientation_split_polar.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Switch the orientation = arrange by other axis",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { attach: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  detach: "Popularity",
                },
                x: {
                  attach: "Popularity",
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Split stacked values = show side-by-side",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              split: true,
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Merge",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              split: false,
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Aggregate",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: {
                  detach: "Genres",
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Polar coordinates",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  range: {
                    min: "-30%",
                  },
                },
              },
              coordSystem: "polar",
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/index.md METASEP
# Tutorial

This is the tutorial of `ipyvizzu` - the `Python` integration of the free,
open-source `JavaScript`/`C++` library
[`Vizzu`](https://lib.vizzuhq.com/latest/). You can create animated charts, data
stories, interactive reports and dashboards with it in Jupyter and similar
notebooks and app building platforms.

This is an excellent starting point to get acquainted with `ipyvizzu`, as it
walks you through the installation of the library, introduces the logic it
employs and the different settings to control how your animated charts look and
behave.

The tutorial is organized into chapters that introduce the concept and the
details of `ipyvizzu` step-by-step. You can find the list of chapters at the end
of this page and in the menu.

## Basic logic of ipyvizzu

The foundation of an `ipyvizzu` chart is the animation. The animation contains
states describing the chart's configuration, such as the data series on the
chart, the coordinate system, labels, titles, etc. A static chart is the result
of a single animation state. When there are more states, `ipyvizzu`
automatically transitions between these. The animate method initiates the
animation into a new state by describing the new chart and how `ipyvizzu` should
transition to it.

![Vizzu](../assets/api-overview.svg){ class='image-center' }

The animate method has non-keyword and keyword arguments. The non-keyword
arguments sets the chart, and the (optional) keyword arguments determines how
`ipyvizzu` should animate to that state.

There are three types of non-keyword arguments:

- `data`: this is where you add the data that you want to visualize
- `config`: this is where you can add or remove series to the chart and set
  general settings like the chart title, the geometry, the alignment etc.
- `style`: this is where you can set how your chart looks

## Installation

```sh
pip install ipyvizzu
```

Visit [Installation chapter](../installation.md) for more options and details.

## Usage

!!! note
    `ipyvizzu` generates `JavaScript` code, then the `vizzu` calls are evaluated
    by the browser. Therefore if a blank space appears where the chart should
    be, check the console log of your browser. `vizzu` reports its errors there.
    If you get a `vizzu` error in your browser console that is not
    straightforward to understand, please clean your browser cache first,
    because it might be caused by an older version being stored in your browser.

docs/tutorial/group_stack.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Group/stack

The following example shows how to group and stack elements of a bar chart.

To get a stacked chart, you need to add a new dimension to the same channel
where the measure is: the y-axis. However, since doing only this would result in
multiple column chart elements with the same color stacked on top of each other,
we also add the same dimension to the color channel.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity"]},
                    "x": {"set": ["Genres"]},
                },
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"attach": ["Kinds"]},
                "color": {"attach": ["Kinds"]},
            }
        }
    )
)
```

By detaching this newly added dimension from the y-axis and attaching it to the
x-axis, you get a grouped bar chart in a way that is easy to follow for the
viewer.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"detach": ["Kinds"]},
                "x": {"attach": ["Kinds"]},
            },
        }
    )
)
```

In order to change the category via which the elements are grouped, just change
the order of the dimension with another one on the same axis.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"set": ["Kinds", "Genres"]},
            },
        }
    )
)
```

To stack a grouped chart, you just have to do the same thing the other way
around: detach the dimension from the x-axis and attach it to the y-axis.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"attach": "Kinds"},
                "x": {"detach": "Kinds"},
            },
        }
    )
)
```

<script src="../group_stack.js"></script>

docs/tutorial/group_stack.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Creating a stacked chart",
              channels: {
                y: { set: "Popularity" },
                x: { set: "Genres" },
              },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  attach: "Kinds",
                },
                color: {
                  attach: "Kinds",
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title:
                "...then you can add it to another channel = group elements",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { detach: "Kinds" },
                x: { attach: "Kinds" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Regrouping the chart",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: { set: ["Kinds", "Genres"] },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "...doing it the other way is how you stack your chart",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: { detach: "Kinds" },
                y: { attach: "Kinds" },
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/geometry.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Geometry

In `ipyvizzu` you can set the geometric elements used to represent your data by
the geometry property within the config object. This is where the library shines
\- beautifully animating between the geometries!

Switching the geometry to area.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity"]},
                    "x": {"set": ["Genres"]},
                },
            }
        )
    )
    ```

```python
chart.animate(Config({"geometry": "area"}))
```

Drawing a line chart.

<div id="tutorial_02"></div>

```python
chart.animate(Config({"geometry": "line"}))
```

Switching the geometry to circle. This setting is the most useful when used
together with the size channel, as shown in the next chapter of the tutorial.

<div id="tutorial_03"></div>

```python
chart.animate(Config({"geometry": "circle"}))
```

Rectangle geometry is the default setting in `ipyvizzu`, used for most common
charts like bar and column charts.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "geometry": "rectangle ",
        }
    )
)
```

<script src="../geometry.js"></script>

docs/tutorial/geometry.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Geometry: area",
              channels: {
                y: { set: "Popularity" },
                x: { set: "Genres" },
              },
            },
          });
        },
        (chart) => {
          return chart.animate({
            geometry: "area",
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            title: "Geometry: line",
          });
        },
        (chart) => {
          return chart.animate({
            geometry: "line",
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            title: "Geometry: circle",
          });
        },
        (chart) => {
          return chart.animate({
            geometry: "circle",
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            title: "Geometry: rectangle - default",
          });
        },
        (chart) => {
          return chart.animate({
            geometry: "rectangle",
          });
        },
      ],
    },
  ]);
});

docs/tutorial/filter_add_new_records.md METASEP
# Filtering & adding new records

Filtering enables you to zoom in or out within a chart, allowing the viewer to
focus on certain selected elements, or get more context. You can also add new
records to the data on the chart which makes it easy to work with real-time
sources.

!!! note
    Currently `filter` and `set_filter` methods only accept JavaScript
    expression as string. The data fields can be accessed via the `record`
    object, see the examples below.

We add two items from the `Genres` dimension - using the `||` operator - to the
filter, so the chart elements that belong to the other two items will vanish
from the chart.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data1 = Data()
    data1.add_df(df)

    chart = Chart()

    chart.animate(data1)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"attach": ["Kinds"]},
            }
        )
    )
    ```

```python
filter1 = Data.filter(
    "record['Genres'] == 'Pop' || record['Genres'] == 'Metal'"
)

chart.animate(filter1)
```

Now we add a cross-filter that includes items from both the `Genres` and the
`Kinds` dimensions. This way we override the filter from the previous state. If
we weren't update the filter, `ipyvizzu` would use it in subsequent states.

<div id="tutorial_02"></div>

```python
filter2 = Data.filter(
    "(record['Genres'] == 'Pop' || record['Genres'] == 'Metal')"
    + " && record['Kinds'] == 'Smooth'"
)

chart.animate(filter2)
```

Switching the filter off to get back to the original view.

<div id="tutorial_03"></div>

```python
chart.animate(Data.filter(None))
```

Here we add another record to the data set and update the chart accordingly.

<div id="tutorial_04"></div>

```python
records = [
    ["Soul", "Hard", 91],
    ["Soul", "Smooth", 57],
    ["Soul", "Experimental", 115],
]

data2 = Data()
data2.add_records(records)

chart.animate(data2)
```

!!! info
    Combining this option with the [store](./shorthands_store.md) function makes
    it easy to update previously configured states with fresh data since this
    function saves the config and style parameters of the chart into a variable
    but not the data.

<script src="../filter_add_new_records.js"></script>

docs/tutorial/filter_add_new_records.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Filter by one dimension",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { attach: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            data: {
              filter: (record) =>
                record.Genres === "Pop" || record.Genres === "Metal",
            },
          });
        },
      ],
    },
    {
      initDataFilter: (record) =>
        record.Genres === "Pop" || record.Genres === "Metal",
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Filter by two dimensions",
            },
          });
        },
        (chart) => {
          return chart.animate({
            data: {
              filter: (record) =>
                (record.Genres === "Pop" || record.Genres === "Metal") &&
                record.Kinds === "Smooth",
            },
          });
        },
      ],
    },
    {
      initDataFilter: (record) =>
        (record.Genres === "Pop" || record.Genres === "Metal") &&
        record.Kinds === "Smooth",
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Filter off",
            },
          });
        },
        (chart) => {
          return chart.animate({
            data: {
              filter: null,
            },
          });
        },
      ],
    },
    {
      initDataFilter: (record) => record.Genres !== "Soul",
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Adding new records",
            },
          });
        },
        (chart) => {
          const expandedData = JSON.parse(JSON.stringify(data));

          expandedData.series[0].values.splice(5, 0, "Soul");
          expandedData.series[0].values.splice(9, 0, "Soul");
          expandedData.series[0].values.splice(14, 0, "Soul");

          expandedData.series[1].values.splice(5, 0, "Hard");
          expandedData.series[1].values.splice(9, 0, "Smooth");
          expandedData.series[1].values.splice(14, 0, "Experimental");

          expandedData.series[2].values.splice(5, 0, 91);
          expandedData.series[2].values.splice(9, 0, 57);
          expandedData.series[2].values.splice(14, 0, 115);

          expandedData.filter = null;

          return chart.animate(
            {
              data: expandedData,
            },
            2,
          );
        },
      ],
    },
  ]);
});

docs/tutorial/events.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Events

You can register handlers for various events. There are mouse events (`click`,
`mouseon`), animation events (`begin`, `update`, `complete`), and rendering
events that are called before rendering the chart elements. Handlers can be
registered/unregistered with the `on`, `off` method pair.

!!! note
    Currently `on` method only accept handler's `JavaScript` expression as
    string. The event can be accessed via the `event` object, see the examples
    below.

We are registering a handler for the `click` event which will show an alert
block with information about the clicked marker.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                },
                "label": {"attach": ["Popularity"]},
                "color": {"set": ["Kinds"]},
            }
        )
    )
    ```

```python
click_handler = "alert(JSON.stringify(event.data));"

click = chart.on("click", click_handler)
```

Unregistering the previously registered handler.

```python
chart.off(click)
```

Here we override the axis label color for `Jazz` to red and all others to gray.

<div id="tutorial_02"></div>

```python
label_draw_handler = (
    "event.renderingContext.fillStyle ="
    + " (event.data.text === 'Jazz') ? 'red' : 'gray';"
)

label_draw = chart.on("plot-axis-label-draw", label_draw_handler)
```

Unregistering the previously registered handler.

```python
chart.off(label_draw)
```

The default behaviour of all events can be blocked by calling the event's
`preventDefault` method. Here we block the drawing of the `Vizzu` logo in the
bottom right corner of the chart.

<div id="tutorial_03"></div>

```python
logo_draw_handler = "event.preventDefault();"

logo_draw = logo_chart.on("logo-draw", logo_draw_handler)
```

Unregistering the previously registered handler.

```python
chart.off(logo_draw)
```

<script src="../events.js"></script>

docs/tutorial/events.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  const clickHandler = (event) => {
    alert(JSON.stringify(event.data)); // eslint-disable-line no-alert
  };

  const labelDrawHandler = (event) => {
    event.renderingContext.fillStyle =
      event.data.text === "Jazz" ? "red" : "gray";
  };

  const logoDrawHandler = (event) => {
    event.preventDefault();
  };

  mdchart.create([
    {
      anims: [
        (chart) => {
          try {
            chart.off("click", clickHandler);
          } catch (error) {
            if (!error.toString().includes("unknown event handler")) {
              throw error;
            }
          }
          return chart.animate({
            config: {
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
              title: "Click event added to markers",
            },
          });
        },
        (chart) => {
          chart.on("click", clickHandler);
          chart.render.updateFrame(true);
          return chart;
        },
      ],
    },
    {
      anims: [
        (chart) => {
          try {
            chart.off("plot-axis-label-draw", labelDrawHandler);
          } catch (error) {
            if (!error.toString().includes("unknown event handler")) {
              throw error;
            }
          }
          return chart.animate({
            config: {
              title: "Changing the canvas context before label draw",
            },
          });
        },
        (chart) => {
          chart.on("plot-axis-label-draw", labelDrawHandler);
          chart.render.updateFrame(true);
          return chart;
        },
      ],
    },
    {
      anims: [
        (chart) => {
          try {
            chart.off("logo-draw", logoDrawHandler);
          } catch (error) {
            if (!error.toString().includes("unknown event handler")) {
              throw error;
            }
          }
          return chart.animate({
            config: {
              title: "Prevent default behavior",
            },
          });
        },
        (chart) => {
          chart.on("logo-draw", logoDrawHandler);
          chart.render.updateFrame(true);
          return chart;
        },
      ],
    },
  ]);
});

docs/tutorial/data.md METASEP
# Data

## Data types

`ipyvizzu` currently supports two types of data series: dimensions and measures.
Dimensions slice the data cube `ipyvizzu` uses, whereas measures are values
within the cube.

Dimensions are categorical series that can contain strings and numbers, but both
will be treated as strings. Temporal data such as dates or timestamps should
also be added as dimensions. By default, `ipyvizzu` will draw the elements on
the chart in the order they are provided in the data set. Thus we suggest adding
temporal data in a sorted format from oldest to newest.

Measures at the moment can only be numerical.

## Adding data

There are multiple ways you can add data to `ipyvizzu`.

- Using pandas DataFrame
- Specify data by series - column after column if you think of a spreadsheet
- Specify data by records - row after row
- Using data cube form
- Using JSON

??? tip
    You should set the data in the first animate call.

    ```python
    chart.animate(data)
    ```

| Genres | Kinds        | Popularity |
| ------ | ------------ | ---------- |
| Pop    | Hard         | 114        |
| Rock   | Hard         | 96         |
| Jazz   | Hard         | 78         |
| Metal  | Hard         | 52         |
| Pop    | Smooth       | 56         |
| Rock   | Experimental | 36         |
| Jazz   | Smooth       | 174        |
| Metal  | Smooth       | 121        |
| Pop    | Experimental | 127        |
| Rock   | Experimental | 83         |
| Jazz   | Experimental | 94         |
| Metal  | Experimental | 58         |

### Using `pandas` DataFrame

Use
[`add_df`](../reference/ipyvizzu/animation.md#ipyvizzu.animation.Data.add_df)
method for adding data frame to
[`Data`](../reference/ipyvizzu/animation.md#ipyvizzu.animation.Data).

```python
import pandas as pd
from ipyvizzu import Data


data = {
    "Genres": [
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
    ],
    "Kinds": [
        "Hard",
        "Hard",
        "Hard",
        "Hard",
        "Smooth",
        "Experimental",
        "Smooth",
        "Smooth",
        "Experimental",
        "Experimental",
        "Experimental",
        "Experimental",
    ],
    "Popularity": [
        114,
        96,
        78,
        52,
        56,
        36,
        174,
        121,
        127,
        83,
        94,
        58,
    ],
}
df = pd.DataFrame(data)

data = Data()
data.add_df(df)
```

!!! info
    `ipyvizzu` makes a difference between two types of data, numeric (measure)
    and not numeric (dimension). A column's `dtype` specifies that the column is
    handled as a measure or as a dimension.

It is also possible to add the data frame's index as a series column while
adding the data frame

```python
import pandas as pd
from ipyvizzu import Data


df = pd.DataFrame(
    {"Popularity": [114, 96, 78]}, index=["x", "y", "z"]
)

data = Data()
data.add_df(df, include_index="IndexColumnName")
```

or later with the
[`add_df_index`](../reference/ipyvizzu/animation.md#ipyvizzu.animation.Data.add_df_index)
method.

```python
import pandas as pd
from ipyvizzu import Data


df = pd.DataFrame(
    {"Popularity": [114, 96, 78]}, index=["x", "y", "z"]
)

data = Data()
data.add_df(df)
data.add_df_index(df, name="IndexColumnName")
```

!!! note
    If you want to work with `pandas` `DataFrame` and `ipyvizzu`, you need to
    install `pandas` or install it as an extra:

    ```sh
    pip install ipyvizzu[pandas]
    ```

#### Using csv

Download `music_data.csv` [here](../assets/data/music_data.csv).

```python
import pandas as pd
from ipyvizzu import Data


df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
)

data = Data()
data.add_df(df)
```

#### Using Excel spreadsheet

Download `music_data.xlsx` [here](../assets/data/music_data.xlsx).

```python
import pandas as pd
from ipyvizzu import Data


df = pd.read_excel(
    "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.xlsx"
)

data = Data()
data.add_df(df)
```

#### Using Google Sheets

```python
import pandas as pd
from ipyvizzu import Data


google_sheet_id = "<Google Sheet id>"
worksheet_name = "<Worksheet name>"

df = pd.read_csv(
    f"https://docs.google.com/spreadsheets/d/{google_sheet_id}/gviz/tq?tqx=out:csv&sheet={worksheet_name}"
)

data = Data()
data.add_df(df)
```

For example if the url is
`https://docs.google.com/spreadsheets/d/abcd1234/edit#gid=0` then
`google_sheet_id` here is `abcd1234`.

#### Using SQLite

```python
import pandas as pd
import sqlite3
from ipyvizzu import Data


# establish a connection to the SQLite database
conn = sqlite3.connect("mydatabase.db")
# read data from a SQLite table into a pandas DataFrame
df = pd.read_sql("SELECT * FROM mytable", conn)
# close the connection
conn.close()

data = Data()
data.add_df(df)
```

!!! note
    You'll need to adjust the SQL query and the database connection parameters
    to match your specific use case.

#### Using MySQL

```python
import pandas as pd
import mysql.connector
from ipyvizzu import Data


# establish a connection to the MySQL database
conn = mysql.connector.connect(
    user="myusername",
    password="mypassword",
    host="myhost",
    database="mydatabase",
)
# read data from a MySQL table into a pandas DataFrame
df = pd.read_sql("SELECT * FROM mytable", con=conn)
# close the connection
conn.close()

data = Data()
data.add_df(df)
```

!!! note
    You'll need to adjust the SQL query and the database connection parameters
    to match your specific use case.

#### Using PostgreSQL

```python
import pandas as pd
import psycopg2
from ipyvizzu import Data


# establish a connection to the PostgreSQL database
conn = psycopg2.connect(
    user="myusername",
    password="mypassword",
    host="myhost",
    port="5432",
    database="mydatabase",
)
# read data from a PostgreSQL table into a pandas DataFrame
df = pd.read_sql("SELECT * FROM mytable", con=conn)
# close the connection
conn.close()

data = Data()
data.add_df(df)
```

!!! note
    You'll need to adjust the SQL query and the database connection parameters
    to match your specific use case.

#### Using Microsoft SQL Server

```python
import pandas as pd
import pyodbc
from ipyvizzu import Data


# establish a connection to the Microsoft SQL Server database
conn = pyodbc.connect(
    "Driver={SQL Server};"
    "Server=myserver;"
    "Database=mydatabase;"
    "UID=myusername;"
    "PWD=mypassword"
)
# read data from a SQL Server table into a pandas DataFrame
df = pd.read_sql("SELECT * FROM mytable", con=conn)
# close the connection
conn.close()

data = Data()
data.add_df(df)
```

!!! note
    You'll need to adjust the SQL query and the database connection parameters
    to match your specific use case.

### Using `numpy` Array

Use
[`add_np_array`](../reference/ipyvizzu/animation.md#ipyvizzu.animation.Data.add_np_array)
method for adding `numpy` Array to
[`Data`](../reference/ipyvizzu/animation.md#ipyvizzu.animation.Data).

```python
import numpy as np
from ipyvizzu import Data


numpy_array = np.array(
    [
        ["Pop", "Hard", 114],
        ["Rock", "Hard", 96],
        ["Jazz", "Hard", 78],
        ["Metal", "Hard", 52],
        ["Pop", "Smooth", 56],
        ["Rock", "Experimental", 36],
        ["Jazz", "Smooth", 174],
        ["Metal", "Smooth", 121],
        ["Pop", "Experimental", 127],
        ["Rock", "Experimental", 83],
        ["Jazz", "Experimental", 94],
        ["Metal", "Experimental", 58],
    ]
)

data = Data()
data.add_np_array(
    numpy_array,
    column_name={0: "Genres", 1: "Kinds", 2: "Popularity"},
    column_dtype={2: int},
)
```

!!! info
    - Arrays with dimensions higher than 2 are not supported.
    - If `column_name` dictionary is not added, column indices will be used as
      names.
    - If `column_dtype` dictionary is not added, every column will use
      `numpy_array.dtype`.

!!! note
    If you want to work with `numpy` Array and `ipyvizzu`, you need to install
    `numpy` or install it as an extra:

    ```sh
    pip install ipyvizzu[numpy]
    ```

### Specify data by series

When you specify the data by series or by records, it has to be in first normal
form. Here is an example of that:

```python
from ipyvizzu import Data


data = Data()
data.add_series(
    "Genres",
    [
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
        "Pop",
        "Rock",
        "Jazz",
        "Metal",
    ],
    type="dimension",
)
data.add_series(
    "Kinds",
    [
        "Hard",
        "Hard",
        "Hard",
        "Hard",
        "Smooth",
        "Experimental",
        "Smooth",
        "Smooth",
        "Experimental",
        "Experimental",
        "Experimental",
        "Experimental",
    ],
    type="dimension",
)
data.add_series(
    "Popularity",
    [114, 96, 78, 52, 56, 36, 174, 121, 127, 83, 94, 58],
    type="measure",
)
```

### Specify data by records

```python
from ipyvizzu import Data


data = Data()

data.add_series("Genres", type="dimension")
data.add_series("Kinds", type="dimension")
data.add_series("Popularity", type="measure")

record = ["Pop", "Hard", 114]

data.add_record(record)

records = [
    ["Rock", "Hard", 96],
    ["Jazz", "Hard", 78],
    ["Metal", "Hard", 52],
    ["Pop", "Smooth", 56],
    ["Rock", "Experimental", 36],
    ["Jazz", "Smooth", 174],
    ["Metal", "Smooth", 121],
    ["Pop", "Experimental", 127],
    ["Rock", "Experimental", 83],
    ["Jazz", "Experimental", 94],
    ["Metal", "Experimental", 58],
]

data.add_records(records)
```

Where records can be lists as shown above or dictionaries:

```python
records = [
    {
        "Genres": "Pop",
        "Kinds": "Hard",
        "Popularity": 114,
    },
    {
        "Genres": "Rock",
        "Kinds": "Hard",
        "Popularity": 96,
    },
    # ...
]
```

### Using data cube form

!!! note
    In the example below, the record `Rock,Experimental,36` has been replaced
    with `Rock,Smooth,36` in order to illustrate that only data with same
    dimensions can be used in the data cube form.

<table>
  <tbody><tr><th colspan="2" rowspan="2"></th><th colspan="4" style="text-align:center">Genres</th></tr>
  <tr>
      <td>Pop</td><td>Rock</td><td>Jazz</td><td>Metal</td>
  </tr>
  <tr><th rowspan="3" style="text-align:center">Kinds</th>
      <td style="text-align:center">Hard</td>
      <td>114</td><td>96</td><td>78</td><td>52</td>
  </tr>
  <tr><td style="text-align:center">Smooth</td>
      <td>56</td><td>36</td><td>74</td><td>121</td>
  </tr>
  <tr>
      <td style="text-align:center">Experimental</td>
      <td>127</td><td>83</td><td>94</td><td>58</td>
  </tr>
  <tr><td colspan="2"></td><th colspan="4" style="text-align:center">Popularity</th></tr>
</tbody></table>

```python
from ipyvizzu import Data


data = Data()

data.add_dimension("Genres", ["Pop", "Rock", "Jazz", "Metal"])
data.add_dimension("Kinds", ["Hard", "Smooth", "Experimental"])

data.add_measure(
    "Popularity",
    [
        [114, 96, 78, 52],
        [56, 36, 174, 121],
        [127, 83, 94, 58],
    ],
)
```

### Using JSON

Download `music_data.json` [here](../assets/data/music_data.json) (in this
example the data stored in the data cube form).

```python
from ipyvizzu import Data


data = Data.from_json("../assets/data/music_data.json")
```

docs/tutorial/color_palette_fonts.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Color palette & fonts

This and the next chapter provide a quick intro to the styling of the charts.
You can either use the `Style` object like in the following examples or use
`CSS`. By using `CSS`, it's easier to set the same style for multiple charts on
one page or re-use style settings.

If you use `CSS`, don't change the set parameters later on via the `Style`
object.

The font sizes automatically adjust to the chart size to help readability, and
can also be set separately or for specific groups.

The color palette is changed to the colors we add here. The order of the
dimension’s items in the data set determine which color belongs to which item as
the colors are added one-by-one. If you want to use the same setting via `CSS`,
you should add
`--vizzu-plot-marker-colorPalette: #9355e8FF #123456FF #BDAF10FF;`.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config, Style, ChartProperty

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                },
                "label": {"attach": ["Popularity"]},
                "color": {"set": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Style(
        {
            "plot": {
                "marker": {
                    "colorPalette": "#9355e8FF #123456FF #BDAF10FF"
                }
            }
        }
    )
)
```

The actual style settings of the chart can be logged in the browser console via
the `STYLE` property.

```python
chart.log(ChartProperty.STYLE)
```

Changing the title font size will only affect the title; all other font sizes
remain the same. `CSS` version: `--vizzu-title-fontSize: 50;`.

<div id="tutorial_02"></div>

```python
chart.animate(Style({"title": {"fontSize": 50}}))
```

This is how to set the font size back to its default value.

<div id="tutorial_03"></div>

```python
chart.animate(Style({"title": {"fontSize": None}}))
```

In case you change the font size of the whole chart with the top-level
`fontSize` parameter then every font on the chart will grow/shrink
proportionally. The size refers to the font size of the axis labels by default.

<div id="tutorial_04"></div>

```python
chart.animate(Style({"fontSize": 20}))
```

You can reset styles to default on any levels by setting them to `None`.

<div id="tutorial_05"></div>

```python
chart.animate(Style(None))
```

For information on all available style parameters see the [Style](./style.md)
chapter or the
[Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/interfaces/Styles.Chart/#properties).

<script src="../color_palette_fonts.js"></script>

docs/tutorial/color_palette_fonts.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Color palette",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              plot: {
                marker: {
                  colorPalette: "#9355e8FF #123456FF #BDAF10FF",
                },
              },
            },
          });
        },
        (chart) => {
          console.log(chart.style); // eslint-disable-line no-console
          return chart;
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Title font size",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              title: {
                fontSize: 50,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Title font size - back to default",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              title: {
                fontSize: null,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Setting all font sizes in one step",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              fontSize: 20,
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Setting all style settings back to default",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: null,
          });
        },
      ],
    },
  ]);
});

docs/tutorial/chart_settings.md METASEP
# Chart settings

You can change the behaviour of the chart with the constructor arguments and the
chart properties detailed below.

## Constructor arguments

### Chart size

The size of the chart can be changed with `width` and `height`
[constructor](../reference/ipyvizzu/chart.md#ipyvizzu.chart.Chart.__init__)
arguments.

!!! info
    `width` and `height` constructor arguments are optional, the default values
    are `800px` and `480px`. You can set them to any valid cssText value.

```python
from ipyvizzu import Chart


chart = Chart(width="100%", height="500px")
```

### Display behavior

There are multiple options for the logic of where and how the chart is displayed
within the notebook and this behavior can be changed with the `display`
[constructor](../reference/ipyvizzu/chart.md#ipyvizzu.chart.Chart.__init__)
argument.

!!! info
    `display` constructor argument is optional, the default value is
    [DisplayTarget.ACTUAL](../reference/ipyvizzu/template.md#ipyvizzu.template.DisplayTarget).

!!! note
    Not all options work in all environments, check the
    [Environments chapter](../environments/index.md) for more details.

#### Actual

![actual](../assets/actual.gif){ class='image-center' }

Chart is relocated and displayed after each cell that has been run. This is set
by default or if `display` is set to `DisplayTarget.ACTUAL`.

```python
from ipyvizzu import Chart, DisplayTarget


chart = Chart(display=DisplayTarget.ACTUAL)
```

#### Begin

![begin](../assets/begin.gif){ class='image-center' }

Chart is displayed after the cell with the chart constructor if `display` is set
to `DisplayTarget.BEGIN`.

```python
from ipyvizzu import Chart, DisplayTarget


chart = Chart(display=DisplayTarget.BEGIN)
```

#### End

![end](../assets/end.gif){ class='image-center' }

If `display` is set to `DisplayTarget.END`, then in case one cell is excuted,
the chart will be displayed after the cell. If multiple cells are run at once,
the chart appears after the last cell set to run.

```python
from ipyvizzu import Chart, DisplayTarget


chart = Chart(display=DisplayTarget.END)
```

!!! tip
    By combining the above display options with the
    [store](./shorthands_store.md) function you can replay the original
    animation when you replay a cell. Another way to replay animations is to use
    our new extension
    [ipyvizzu-story](https://vizzuhq.github.io/ipyvizzu-story/) that enables you
    to build, present and share animated data stories in data science notebooks
    with a very similar syntax to `ipyvizzu`'s.

!!! info
    `DisplayTarget.ACTUAL`, `DisplayTarget.BEGIN` and `DisplayTarget.END` use
    `IPython.display.display_javascript` function.

#### Manual

Chart is displayed only when a display function is called if `display` is set to
`DisplayTarget.MANUAL`.

!!! note
    Even though it runs in more environments, the disadvantage of using `MANUAL`
    [DisplayTarget](../reference/ipyvizzu/template.md#ipyvizzu.template.DisplayTarget)
    is that the chart cannot be modified after calling a display function,
    without all the cells modifying the chart being rerun.

One of the display functions is the `_repr_html_` method which is supported in
most environments.

```python
from ipyvizzu import Chart, DisplayTarget

chart = Chart(display=DisplayTarget.MANUAL)

# ...

chart
```

The other display function is the `show` method.

```python
from ipyvizzu import Chart, DisplayTarget


chart = Chart(display=DisplayTarget.MANUAL)

# ...

chart.show()
```

!!! info
    `DisplayTarget.MANUAL` with the `show` method uses
    `IPython.display.display_javascript` function.

### Vizzu library

`ipyvizzu` requires and automatically downloads the
[Vizzu](https://lib.vizzuhq.com/latest/) JavaScript/C++ library from
[jsDelivr CDN](https://www.jsdelivr.com/package/npm/vizzu), but you can also use
a self-hosted version.

!!! info
    `vizzu` constructor argument is optional, the default value is
    [Chart.VIZZU](../reference/ipyvizzu/chart.md#ipyvizzu.chart.Chart.VIZZU)

Install `Vizzu` via [npm](https://www.npmjs.com/package/vizzu):

```sh
npm install vizzu
```

After it is hosted on a server, you can use that url.

```python
from ipyvizzu import Chart


chart = Chart(vizzu="<url>/vizzu.min.js")
```

## Properties

### Analytics

The usage statistics feature in `ipyvizzu` allows aggregate usage data
collection using [Plausible](https://plausible.io/)'s algorithm. Enabling this
feature helps us follow the progress and overall trends of our library, allowing
us to focus our resources effectively and better serve our users.

We do not track, collect, or store any personal data or personally identifiable
information. All data is isolated to a single day, a single site, and a single
device only.

Usage statistics feature is optional, and by default, it is enabled (default
value: `True`). Users can choose to opt-out if they prefer not to participate in
data collection. Please note that even when this feature is enabled, publishing
anything made with `ipyvizzu` remains GDPR compatible.

To disable usage statistics feature, set
[analytics](../reference/ipyvizzu/chart.md#ipyvizzu.chart.Chart.analytics)
property to `False`.

```python
from ipyvizzu import Chart


chart = Chart()
chart.analytics = False
```

### Scroll into view

When the scroll into view feature is turned on, `ipyvizzu` is able to
automatically scroll to the chart being animated to view in the browser.

If manual scrolling is detected while auto-scrolling, `ipyvizzu` will stop
auto-scroll until the notebook is replayed again.

!!! info
    Scroll into view feature is optional, the default value is `False` .

!!! note
    Scroll into view feature does not work in all environments, check the
    [Environments chapter](../environments/index.md) for more details.

To enable scroll into view feature, set
[scroll_into_view](../reference/ipyvizzu/chart.md#ipyvizzu.chart.Chart.scroll_into_view)
property to `True`.

```python
from ipyvizzu import Chart


chart = Chart()
chart.scroll_into_view = True
```

docs/tutorial/chart_presets.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Chart presets

Throughout this tutorial, we have shown you how to create charts with `ipyvizzu`
using a chart type-agnostic, uniform way without being limited to a predefined
set of available charts. But sometimes, when you know the chart type you want to
use, it is easier to start with that and skip configuring it from scratch. For
this reason, `ipyvizzu` provides preset chart configurations for many known
chart types. See the [preset gallery](../examples/presets/index.md) for all
available presets.

Use the preset methods of the `Config` class to build a chart based on a preset.
These methods return chart configuration objects that can be passed to the
`animate` method. For example, this is how to create a stacked bubble chart
using its preset.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config, Style

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)
    ```

```python
chart.animate(
    Config.stackedBubble(
        {
            "size": "Popularity",
            "color": "Kinds",
            "stackedBy": "Genres",
        }
    )
)
```

Presets will override all channels, removing all previously set series from the
chart. Using a preset will also explicitly set most chart configuration
parameters. Exceptions to this are the `legend`, `title`, `reverse`, and `sort`
properties that can be set while using a preset. Here's an example of a preset
where chart elements are sorted by value.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config.radialStackedBar(
        {
            "angle": "Popularity",
            "radius": "Genres",
            "stackedBy": "Kinds",
            "sort": "byValue",
        }
    )
)
```

As you will see, the preset doesn't override the previously configured sorting
and wouldn't affect the rest of the chart config parameters mentioned above
either.

Presets will affect chart configuration, but you might also want to set the
style or the underlying data.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config.radialBar(
        {
            "angle": "Popularity",
            "radius": "Genres",
        }
    ),
    Style({"plot.xAxis.interlacing.color": "#ffffff00"}),
)
```

<script src="../chart_presets.js"></script>

docs/tutorial/chart_presets.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Using a preset",
            },
          });
        },
        (chart) => {
          return chart.animate(
            chart.constructor.presets.stackedBubble({
              size: "Popularity",
              color: "Kinds",
              stackedBy: "Genres",
            }),
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Set sorting for a chart preset",
            },
          });
        },
        (chart) => {
          return chart.animate(
            chart.constructor.presets.radialStackedBar({
              angle: "Popularity",
              radius: "Genres",
              stackedBy: "Kinds",
              sort: "byValue",
            }),
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Setting style for a preset",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: chart.constructor.presets.radialBar({
              angle: "Popularity",
              radius: "Genres",
            }),
            style: {
              "plot.xAxis.interlacing.color": "#ffffff00",
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/chart_layout.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Chart layout

`ipyvizzu` has three separate parts of the chart layout: the plot area that
contains the chart, the title containing the chart title on the top, and the
legend on the left. `ipyvizzu` automatically hides the legend when it’s
unnecessary to show it. When the title is not in use, `ipyvizzu` hides that part
automatically as well. Each of these parts have their own paddings on all four
sides that adjust to the chart size by default, but can also be set with the
appropriate settings in the `Style` object. All size parameters can be set in
pixel, percentage and em.

We add different background colors to the parts of the layout to show how they
are aligned.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config, Style

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                },
                "label": {"attach": ["Popularity"]},
                "color": {"set": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Style(
        {
            "title": {"backgroundColor": "#A0A0A0"},
            "plot": {"backgroundColor": "#D2D2D2"},
            "legend": {"backgroundColor": "#808080"},
        }
    )
)
```

Setting the width of the legend.

<div id="tutorial_02"></div>

```python
chart.animate(Style({"legend": {"width": 50}}))
```

Setting the legend width back to its default value.

<div id="tutorial_03"></div>

```python
chart.animate(Style({"legend": {"width": None}}))
```

Changing the title paddings. By default, the title is horizontally centered
above the chart. In this example, we set the title’s left padding, resulting in
the text moving to the right.

<div id="tutorial_04"></div>

```python
chart.animate(
    Style(
        {
            "title": {
                "paddingTop": 20,
                "paddingBottom": 20,
                "paddingLeft": 200,
            }
        }
    )
)
```

Setting the title paddings back to their default values.

<div id="tutorial_05"></div>

```python
chart.animate(
    Style(
        {
            "title": {
                "paddingTop": None,
                "paddingBottom": None,
                "paddingLeft": None,
            }
        }
    )
)
```

Changing the paddings of the plot area to position the plot. The texts on the
axes are drawn on the padding of the plot and not the plot itself.

<div id="tutorial_06"></div>

```python
chart.animate(
    Style({"plot": {"paddingLeft": 100, "paddingRight": 100}})
)
```

Setting the plot paddings back to their default values.

<div id="tutorial_07"></div>

```python
chart.animate(
    Style({"plot": {"paddingLeft": None, "paddingRight": None}})
)
```

<script src="../chart_layout.js"></script>

docs/tutorial/chart_layout.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Plot, title and legend background",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              title: {
                backgroundColor: "#A0A0A0",
              },
              plot: {
                backgroundColor: "#D2D2D2",
              },
              legend: {
                backgroundColor: "#808080",
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Legend width",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              legend: {
                width: 50,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            style: {
              legend: {
                width: null,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Title padding",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              title: {
                paddingTop: 20,
                paddingBottom: 20,
                paddingLeft: 200,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            style: {
              title: {
                paddingTop: null,
                paddingBottom: null,
                paddingLeft: null,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Plot padding",
            },
          });
        },
        (chart) => {
          return chart.animate({
            style: {
              plot: {
                paddingLeft: 100,
                paddingRight: 100,
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            style: {
              plot: {
                paddingLeft: null,
                paddingRight: null,
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/channels_legend.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Channels & legend

Besides the x-axis and the y-axis, there are five more channels in `ipyvizzu`
you can use to visualize your data. Similarly to the axes you can put any number
of dimensions and/or one measure to a channel. In the following example the four
most commonly used channels are shown. The fifth, `noop` channel is introduced
later in the
[Without coordinates & noop channel](./without_coordinates_noop_channel.md)
chapter.

Data on the label channel will be written on the markers on the chart.
`ipyvizzu` automatically determines the best way to position these labels, but
you can set them differently with the `Style` object introduced in the
[Color palette & fonts](./color_palette_fonts.md) chapter.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity"]},
                    "x": {"set": ["Genres"]},
                },
            }
        )
    )
    ```

```python
chart.animate(
    Config({"channels": {"label": {"attach": ["Popularity"]}}})
)
```

The `lightness` channel sets the lightness of the markers. In this case the same
measure (`Popularity`) is added to it that is on the y-axis, meaning that
columns’ height and lightness represent the same values. The legend for the
`lightness` channel is turned on using the `legend` property.

!!! info
    This is an example when we explicitly instruct `ipyvizzu` to show the
    legend. By default `ipyvizzu` automatically shows/hides the legend when it's
    necessary. You can also turn it off with the `legend`: `None` command or set
    back to automatic mode with `legend`: `"auto"`.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {"lightness": {"attach": ["Popularity"]}},
            "legend": "lightness",
        }
    )
)
```

The `color` channel sets the color of the markers. The same dimension (`Genres`)
is put on it that is on the x-axis resulting in each bar having a different
color. If a measure is put on the `color` channel, a color range will be used.

!!! info
    The value on the `lightness` channel is removed in this step as it doesn’t
    make sense to use it together with the `color` channel in this case.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {"color": {"attach": ["Genres"]}},
            "legend": "color",
        }
    )
)
```

The `size` channel sets the size of the markers if the geometry is circle -
where size sets the radius of the circles - or line - where size determines line
width. It is ignored when using rectangle or area geometry. This is why we
change the geometry to circle in the example.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "channels": {"size": {"set": ["Popularity"]}},
            "geometry": "circle",
        }
    )
)
```

<script src="../channels_legend.js"></script>

docs/tutorial/channels_legend.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Label",
              channels: {
                y: { set: "Popularity" },
                x: { set: "Genres" },
              },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                label: {
                  attach: "Popularity",
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Lightness - legend on",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                lightness: {
                  attach: "Popularity",
                },
              },
              legend: "lightness",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Color",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                lightness: {
                  set: null,
                },
                color: {
                  attach: "Genres",
                },
              },
              legend: "color",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Size - change of geometry required",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                size: {
                  set: "Popularity",
                },
              },
              geometry: "circle",
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/changing_dimensions.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Changing dimensions

The simplest of dimension-changing operations are aggregate and drill-down.
These features basically mean that you either add or remove an additional
dimension to/from an axis or another channel.

Let’s aggregate together the elements by getting the `Genres` dimension off the
x-axis. By taking it off the chart, only one chart element remains for every
color, and `ipyvizzu` automatically calculates and shows the aggregate value of
the elements.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"attach": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"set": None},
            }
        }
    )
)
```

When you simultaneously add and remove dimensions, the partitioning of the
underlying data to markers on the chart changes. There are multiple ways to
transition through these kinds of operations using.

By default, the markers are aggregated to the common base of the two states,
then drilled down to the target state, as shown below.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {
                    "detach": ["Kinds"],
                },
                "x": {
                    "set": ["Genres"],
                },
                "color": {
                    "set": None,
                },
            }
        }
    )
)
```

You can change this setting and drill down to the union of the two states
instead, and then aggregate to the target state:

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {
                    "detach": ["Genres"],
                    "attach": ["Kinds"],
                },
            }
        }
    ),
    regroupStrategy="drilldown",
)
```

There is also the option to fade the chart between the states:

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {
                    "detach": ["Kinds"],
                    "attach": ["Genres"],
                },
            }
        }
    ),
    regroupStrategy="fade",
)
```

To simply drill down, the same dimension is put back on the y-axis.

<div id="tutorial_05"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {
                    "attach": ["Kinds"],
                },
                "color": {
                    "set": ["Kinds"],
                },
            }
        }
    )
)
```

<script src="../changing_dimensions.js"></script>

docs/tutorial/changing_dimensions.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Aggregate",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { attach: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: {
                  set: null,
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Changing dimensions",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { detach: ["Kinds"] },
                x: { set: ["Genres"] },
                color: { set: null },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Changing dimensions by drilling down",
            },
          });
        },
        (chart) => {
          return chart.animate(
            {
              config: {
                channels: {
                  x: { detach: ["Genres"], attach: ["Kinds"] },
                },
              },
            },
            { regroupStrategy: "drilldown" },
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Changing dimensions with fading",
            },
          });
        },
        (chart) => {
          return chart.animate(
            {
              config: {
                channels: {
                  x: { detach: ["Kinds"], attach: ["Genres"] },
                },
              },
            },
            { regroupStrategy: "fade" },
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Drill-down",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { attach: ["Kinds"] },
                color: { set: ["Kinds"] },
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/axes_title_tooltip.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Axes, title, tooltip

To build a chart with `ipyvizzu`, you have to add data series to the channels.
Channels will be explained more in-depth later, but for now, think of channels
as different elements of the chart we can bind data to. The simplest and most
often used channels are the x and y-axes.

The first step is to create a simple column chart, adding one of the dimensions
from the data set we added in the previous chapter (`Genres`) to the x-axis and
the measure (`Popularity`) to the y-axis using the set property.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, ChartProperty, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"set": ["Popularity"]},
                "x": {"set": ["Genres"]},
            }
        }
    )
)
```

In the next step, the chart is rearranged by putting both series on the y-axis
using once again the set property, resulting in a single column chart.
`ipyvizzu` automatically animates between the initial state and this one.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"set": ["Popularity", "Genres"]},
                "x": {"set": None},
            }
        }
    )
)
```

Instead of set, you can use attach and detach to add or remove series to/from
the channels.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"detach": ["Popularity"]},
                "x": {"attach": ["Popularity"]},
            }
        }
    )
)
```

Using attach & detach makes it easier to build your animated charts
step-by-step, however you either have to keep in mind what you had on which
channel in the previous step or add the following code to access the actual
configuration of the chart.

Add the following code to log the actual configuration of the chart in the
browser console.

```python
chart.log(ChartProperty.CONFIG)
```

Setting the chart title with the title command.

<div id="tutorial_04"></div>

```python
chart.animate(Config({"title": "My first chart"}))
```

Switching on the tooltips that appear on the chart elements when the user hovers
over them with their mouse by adding the (`"tooltip"`, `True`) parameters to the
`chart.feature` method.

<div id="tutorial_05"></div>

```python
chart.feature("tooltip", True)
```

<script src="../axes_title_tooltip.js"></script>

docs/tutorial/axes_title_tooltip.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "Popularity" },
                x: { set: "Genres" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: { set: null },
                y: { set: ["Genres", "Popularity"] },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { detach: "Popularity" },
                x: { attach: "Popularity" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          console.log(chart.config); // eslint-disable-line no-console
          return chart;
        },
        (chart) => {
          return chart.animate({ title: "My first chart" });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          chart.feature("tooltip", true);
          return chart;
        },
      ],
    },
  ]);
});

docs/tutorial/animation_options.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Animation options

In `ipyvizzu` you can set the timing and duration of the animation. You can do
this either for the whole animation, or for animation groups such as the
elements moving along the x-axis or the y-axis, appearing or disappearing or
when the coordinate system is changed.

Let’s see first a simple example when a stacked column chart is grouped using
the default animation options.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                },
                "label": {"attach": ["Popularity"]},
                "color": {"set": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"detach": ["Kinds"]},
                "x": {"attach": ["Kinds"]},
            }
        }
    )
)
```

We stack the columns, still with the default options.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"detach": ["Kinds"]},
                "y": {"attach": ["Kinds"]},
            }
        }
    )
)
```

Now we change the animation settings for the elements moving along the y-axis
and also the change in styles, more specifically when the labels on the markers
move from the center of the chart elements to the top of them.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"detach": ["Kinds"]},
                "x": {"attach": ["Kinds"]},
            }
        }
    ),
    y={"duration": 2, "delay": 2},
    style={"duration": 2, "delay": 4},
)
```

This is an example of changing the settings for the whole animation at once.

<div id="tutorial_04"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"detach": ["Kinds"]},
                "y": {"attach": ["Kinds"]},
            }
        }
    ),
    duration=1,
    easing="linear",
)
```

When the two settings are combined, `ipyvizzu` will use the general animation
options and spread the unique settings for specific groups proportionally. This
is why you can see the same animation as two steps before but happening much
quicker since the duration of the whole animation is set to 1 second.

<div id="tutorial_05"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {"detach": ["Kinds"]},
                "x": {"attach": ["Kinds"]},
            }
        }
    ),
    duration=1,
    easing="linear",
    y={"duration": 2, "delay": 2},
    style={"duration": 2, "delay": 4},
)
```

The default unit for animation is seconds, but you can set other units.

<div id="tutorial_06"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"detach": ["Kinds"]},
                "y": {"attach": ["Kinds"]},
            }
        }
    ),
    duration="500ms",
)
```

<script src="../animation_options.js"></script>

docs/tutorial/animation_options.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Default options - step 1",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  detach: "Kinds",
                },
                x: {
                  attach: "Kinds",
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Default options - step 2",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: {
                  detach: "Kinds",
                },
                y: {
                  attach: "Kinds",
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Custom animation settings for specific groups",
            },
          });
        },
        (chart) => {
          return chart.animate(
            {
              config: {
                channels: {
                  x: {
                    attach: "Kinds",
                  },
                  y: {
                    detach: "Kinds",
                  },
                },
              },
            },
            {
              y: {
                duration: 2,
                delay: 2,
              },
              style: {
                duration: 2,
                delay: 4,
              },
            },
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Custom options for the whole animation",
            },
          });
        },
        (chart) => {
          return chart.animate(
            {
              config: {
                channels: {
                  x: {
                    detach: "Kinds",
                  },
                  y: {
                    attach: "Kinds",
                  },
                },
              },
            },
            {
              duration: 1,
              easing: "linear",
            },
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Custom settings for both",
            },
          });
        },
        (chart) => {
          return chart.animate(
            {
              config: {
                channels: {
                  x: {
                    attach: "Kinds",
                  },
                  y: {
                    detach: "Kinds",
                  },
                },
              },
            },
            {
              duration: 1,
              easing: "linear",
              y: {
                duration: 2,
                delay: 2,
              },
              style: {
                duration: 2,
                delay: 4,
              },
            },
          );
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Custom unit for duration",
            },
          });
        },
        (chart) => {
          return chart.animate(
            {
              config: {
                channels: {
                  x: {
                    detach: "Kinds",
                  },
                  y: {
                    attach: "Kinds",
                  },
                },
              },
            },
            {
              duration: "500ms",
            },
          );
        },
      ],
    },
  ]);
});

docs/tutorial/animation_control_keyframes.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Animation control & keyframes

Using the `control` property provided by the chart you can play, pause, stop,
seek or reverse the animations.

In this step, we seek forward to `50%` of progress after the animation starts.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config, Keyframe

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"attach": ["Kinds"]},
            }
        )
    )
    ```

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"attach": ["Kinds"]},
                "y": {"detach": ["Kinds"]},
            },
        }
    )
)
chart.control.seek("50%")
```

You can also control the initial position and play state of the animation
through the keyword arguments of the animate method.

<div id="tutorial_02"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {"detach": ["Kinds"]},
                "y": {"attach": ["Kinds"]},
            },
        }
    ),
    playState="paused",
    position=0.5,
)
chart.control.play()
```

You may want to control multiple animations as a single one.

You can do this by boundling them together and passing them to a single
`animate` call. To do this, you need to create a `Keyframe` object from the
arguments of every single `animate` call and then passing them into a single
`animate` call.

<div id="tutorial_03"></div>

```python
chart.animate(
    Keyframe(
        Config(
            {
                "channels": {
                    "x": {"attach": ["Kinds"]},
                    "y": {"detach": ["Kinds"]},
                },
            }
        ),
        duration=0.5,
    ),
    Keyframe(
        Config(
            {
                "channels": {
                    "x": {"detach": ["Kinds"]},
                    "y": {"attach": ["Kinds"]},
                }
            }
        ),
        duration=1,
    ),
)
```

<script src="../animation_control_keyframes.js"></script>

docs/tutorial/animation_control_keyframes.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title:
                "Jumping from 0% to 50% progress at the begining of the animation",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { set: "Kinds" },
            },
          });
        },
        (chart) => {
          chart = chart.animate({
            config: {
              channels: {
                x: {
                  attach: "Kinds",
                },
                y: {
                  detach: "Kinds",
                },
              },
            },
          });
          chart.activated.then((control) => control.seek("50%"));
          return chart;
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Using initial animation control parameters",
            },
          });
        },
        (chart) => {
          chart = chart.animate(
            {
              config: {
                channels: {
                  x: {
                    detach: ["Kinds"],
                  },
                  y: {
                    attach: ["Kinds"],
                  },
                },
              },
            },
            {
              playState: "paused",
              position: 0.5,
            },
          );
          chart.activated.then((control) => control.play());
          return chart;
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Using keyframes",
            },
          });
        },
        (chart) => {
          return chart.animate([
            {
              target: {
                config: {
                  channels: {
                    x: {
                      attach: ["Kinds"],
                    },
                    y: {
                      detach: ["Kinds"],
                    },
                  },
                  title: "Using keyframes",
                },
              },
              options: {
                duration: 0.5,
              },
            },
            {
              target: {
                config: {
                  channels: {
                    x: {
                      detach: ["Kinds"],
                    },
                    y: {
                      attach: ["Kinds"],
                    },
                  },
                },
              },
              options: {
                duration: 1,
              },
            },
          ]);
        },
      ],
    },
  ]);
});

docs/tutorial/align_range.md METASEP
---
csv_url: ../../assets/data/music_data.csv
---

# Align & range

`ipyvizzu` offers different options to align your chart elements and to set the
range of values shown on the axes. Alignment can be used to create charts like a
stream chart where the elements are vertically centered. A good example for
using range is when you fix the y-axis so that it would not adapt to the data
being shown.

Centered alignment. The effect of this parameter depends on the orientation of
the chart. For example, on a column chart, elements will be vertically centered,
whereas on a bar chart, horizontally.

!!! info
    In the first example, the y-axis labels are hidden because they don't
    properly represent the values shown on the column chart anymore, as the
    chart elements float off the x-axis.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)

    chart.animate(
        Config(
            {
                "channels": {
                    "y": {"set": ["Popularity", "Kinds"]},
                    "x": {"set": ["Genres"]},
                    "label": {"attach": ["Popularity"]},
                },
                "color": {"attach": ["Kinds"]},
            }
        )
    )
    ```

Change align and configures the y axis labels to disappear during the animation.

```python
chart.animate(
    Config({"align": "center", "channels": {"y": {"labels": False}}})
)
```

Stretched alignment. This way the elements will proportionally fill the entire
plot area, effectively showing proportions in stacked charts. This is why the
scale will also switch from values to percentages when used.

<div id="tutorial_02"></div>

```python
chart.animate(Config({"align": "stretch"}))
```

Getting back to the default alignment.

<div id="tutorial_03"></div>

```python
chart.animate(
    Config({"align": "none", "channels": {"y": {"labels": True}}})
)
```

You can set the range of an axis by setting the minimum and maximum values of
it. Both parameters are optional so that you can set only one of those, and you
either set specific values or a relative value by adding the `%` sign. In this
example, we set the range of the y-axis in a way that the max value is `150%` of
the biggest element’s value.

<div id="tutorial_04"></div>

```python
chart.animate(Config({"channels": {"y": {"range": {"max": "150%"}}}}))
```

You can also set the range for an axis with a dimension on it. You can even use
this feature to filter certain elements, just like in the following example.

<div id="tutorial_05"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "x": {
                    "range": {
                        "min": -2,
                        "max": 3,
                    }
                }
            }
        }
    )
)
```

Ranges have certain defaults depending on the chart's configuration, based on
common data viz guidelines because we wanted to make it easy for you to create
sleek charts. For example, in the cartesian coordinate system, the range will be
automatically set to the `max:110%` for an axis with a measure on it. Polar
coordinates work differently, as you can see for yourself in the
[Orientation, split & polar chapter](./orientation_split_polar.md).

Whenever you want to set your ranges back to the default value, just set them to
`"auto"`.

<div id="tutorial_06"></div>

```python
chart.animate(
    Config(
        {
            "channels": {
                "y": {
                    "range": {"max": "auto"},
                },
                "x": {
                    "range": {
                        "min": "auto",
                        "max": "auto",
                    }
                },
            }
        }
    )
)
```

<script src="../align_range.js"></script>

docs/tutorial/align_range.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Align: center",
              channels: {
                y: { set: ["Popularity", "Kinds"] },
                x: { set: "Genres" },
                label: { attach: "Popularity" },
              },
              color: { attach: "Kinds" },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              align: "center",
              channels: {
                y: {
                  labels: false,
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Align: stretch = % view",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              align: "stretch",
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Align: none - default",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              align: "none",
              channels: {
                y: {
                  labels: true,
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Axis range set proportionally to shown values",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  range: {
                    max: "150%",
                  },
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title:
                "Axis range set explicitly on an axis with discrete series",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: {
                  range: {
                    min: -2,
                    max: 3,
                  },
                },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Back to the default ranges",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: {
                  range: {
                    max: "auto",
                  },
                },
                x: {
                  range: {
                    min: "auto",
                    max: "auto",
                  },
                },
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/tutorial/aggregating_data.md METASEP
---
data_url: ../../assets/data/music_data.js
---

# Aggregating data

The default logic of `ipyvizzu` is to show the sum of values that are in the
categories added to a chart. So if we create a simple vertical bar chart by
adding the `Popularity` measure to the y-axis, the height of the bar will be the
sum of all `Popularity` values and when we add `Genres` to the x-axis, the
height of the bars will be the sum of `Popularity` values in each category
within `Genres`.

<div id="tutorial_01"></div>

??? info "Info - How to setup Chart"
    ```python
    import pandas as pd
    from ipyvizzu import Chart, Data, Config

    df = pd.read_csv(
        "https://ipyvizzu.vizzuhq.com/latest/assets/data/music_data.csv"
    )
    data = Data()
    data.add_df(df)

    chart = Chart()

    chart.animate(data)
    ```

```python
chart.animate(Config({"channels": {"y": {"set": ["Popularity"]}}}))

chart.animate(Config({"channels": {"x": {"set": ["Genres"]}}}))
```

Next to the default logic of sum, there are a handful of other aggregation
logics that are available in `ipyvizzu`: `min`, `max`, `mean`, `count` and
`distinct`. Let's go through them to see how they work.

Minimum value: the height of the bars show the minimum value in the `Popularity`
measure in each of the `Genres`.

<div id="tutorial_02"></div>

```javascript
chart.animate(
    Config({
        "channels": {
            "y": {
                "set": ["min(Popularity)"]
            }
        }
    })
)
```

Maximum value: the height of the bars show the maximum value in the `Popularity`
measure in each of the `Genres`.

<div id="tutorial_03"></div>

```javascript
chart.animate(
    Config({
        "channels": {
            "y": {
                "set": ["max(Popularity)"]
            }
        }
    })
)
```

Mean value: the height of the bars show the mean value of the `Popularity`
measure in each of the `Genres`.

<div id="tutorial_04"></div>

```javascript
chart.animate(
    Config({
        "channels": {
            "y": {
                "set": ["mean(Popularity)"]
            }
        }
    })
)
```

Count: the height of the bars show the number of items (rows if you will) in
each of the `Genres`.

<div id="tutorial_05"></div>

```javascript
chart.animate(
    Config({
        "channels": {
            "y": {
                "set": ["count()"]
            }
        }
    })
)
```

Distinct: the height of the bars show the number of distinct categories of
`Kinds` in each of the `Genres`.

!!! note
    Distinct aggregation logic relates to dimensions like `Genres` and not to
    measures like `Popularity`.

<div id="tutorial_06"></div>

```javascript
chart.animate(
    Config({
        "channels": {
            "y": {
                "set": ["distinct(Kinds)"]
            }
        }
    })
)
```

Sum: this is how you can get back to the default aggregation logic of `ipyvizzu`
that sums the `Popularity` values in each of the `Genres`.

<div id="tutorial_07"></div>

```javascript
chart.animate(
        Config({
            "channels": {
                "y": {
                    "set": ["sum(Popularity)"]
                }
            }
        })
```

<script src="../aggregating_data.js"></script>

docs/tutorial/aggregating_data.js METASEP
const dataLoaded = import("../assets/data/music_data.js");
const mdChartLoaded = import("../assets/javascripts/mdchart.js");

Promise.all([dataLoaded, mdChartLoaded]).then((results) => {
  const data = results[0].default;
  const MdChart = results[1].default;
  const mdchart = new MdChart(data, "./vizzu.js", "tutorial");

  mdchart.create([
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Sum of all Popularity Values",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "Popularity" },
              },
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              title: "Sum of Popularity by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                x: { set: "Genres" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Minimum of Popularity by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "min(Popularity)" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Maximum of Popularity by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "max(Popularity)" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Mean of Popularity by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "mean(Popularity)" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Count of items by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "count()" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Distinct Kinds by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "distinct(Kinds)" },
              },
            },
          });
        },
      ],
    },
    {
      anims: [
        (chart) => {
          return chart.animate({
            config: {
              title: "Sum of Popularity by Genre",
            },
          });
        },
        (chart) => {
          return chart.animate({
            config: {
              channels: {
                y: { set: "sum(Popularity)" },
              },
            },
          });
        },
      ],
    },
  ]);
});

docs/showcases/titanic.md METASEP
---
csv_url: ./titanic.csv
---

# Passengers of the Titanic

<div class="showcase">
  <iframe  id="showcase" src="./main.html" width="100%" scrolling="no" frameborder="0"></iframe>
</div>
<script src="../../assets/javascripts/iframe/autoheight.js"></script>
<script src="../../assets/javascripts/iframe/click.js"></script>

```python
import pandas as pd
from ipyvizzu import Chart, Data, Config

df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data = Data()
data.add_df(df)

chart = Chart()

chart.animate(data)

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))

chart.animate(
    Config(
        {
            "x": ["Count", "Sex", "Survived"],
            "y": None,
            "coordSystem": "polar",
        }
    )
)
```

docs/showcases/sales.md METASEP
---
csv_url: ./sales.csv
---

# Sales

<div class="showcase">
  <iframe  id="showcase" src="./main.html" width="100%" scrolling="no" frameborder="0"></iframe>
</div>
<script src="../../assets/javascripts/iframe/autoheight.js"></script>
<script src="../../assets/javascripts/iframe/click.js"></script>

```python
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style

df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/sales/sales.csv"
)
data = Data()
data.add_df(df)

chart = Chart()

chart.animate(data)

chart.animate(
    Data.filter("record['Product'] == 'Shoes'"),
    Config(
        {
            "x": "Region",
            "y": ["Sales", "Product"],
            "label": "Sales",
            "color": "Product",
            "title": "Sales of Shoes",
        }
    ),
)

chart.animate(
    Data.filter(
        "record['Product'] == 'Shoes' || record['Product'] == 'Handbags'"
    ),
    Config({"title": "Sales of Shoes & Handbags"}),
    delay=1,
)

chart.animate(
    Data.filter("record['Product'] != 'Accessories'"),
    Config({"title": "Sales of Shoes, Handbags & Gloves"}),
    delay=1,
)

chart.animate(
    Data.filter(None),
    Config({"title": "Sales of All Products"}),
    delay=1,
)

chart.animate(
    Config(
        {
            "y": ["Revenue [$]", "Product"],
            "label": "Revenue [$]",
            "title": "Revenue of All Products",
        }
    ),
    delay=1,
)

chart.animate(
    Config({"x": ["Region", "Revenue [$]"], "y": "Product"}), delay=2
)

chart.animate(Config({"x": "Revenue [$]", "y": "Product"}))

chart.animate(
    Config({"coordSystem": "polar", "sort": "byValue"}), delay=1
)
```

docs/showcases/nadal.md METASEP
---
csv_url: ./nadal.csv
---

# Rafael Nadal's matches

<div class="showcase">
  <iframe  id="showcase" src="./main.html" width="100%" scrolling="no" frameborder="0"></iframe>
</div>
<script src="../../assets/javascripts/iframe/autoheight.js"></script>
<script src="../../assets/javascripts/iframe/click.js"></script>

```python
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget

df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/nadal/nadal.csv",
    dtype={
        "Year": str,
        "Round": str,
        "Round2": str,
        "Order_GS": str,
        "Order_all": str,
        "Total_GS": str,
        "Top": str,
    },
)
data = Data()
data.add_df(df)

chart = Chart(display=DisplayTarget.END)
chart.animate(data)

chart.animate(
    data.filter("record.Year != 'Total'"),
    Config(
        {
            "x": "Year",
            "y": "Round2",
            "color": {
                "set": "Result_Num",
                "range": {"min": -1, "max": 1},
            },
            "size": None,
            "orientation": "horizontal",
            "geometry": "rectangle",
            "title": "Rafael Nadal's matches at the Roland Garros",
            "legend": "size",
        }
    ),
    Style(
        {
            "title": {
                "paddingTop": 50,
                "paddingBottom": 0,
            },
            "plot": {
                "marker": {
                    "borderWidth": 3,
                    "borderOpacity": 0,
                    "colorPalette": "#1EB55FFF #AD0000FF #AEAEAEFF",
                    "colorGradient": "#AEAEAEFF 0.000000, #AD0000FF 0.500000, #1EB55FFF 1.000000",
                },
                "paddingLeft": 20,
                "paddingBottom": "3.5em",
                "paddingTop": "2.5em",
                "xAxis": {"interlacing": {"color": "#ffffff00"}},
                "yAxis": {"label": {"fontSize": "120%"}},
            },
            "logo": {"width": 100},
        }
    ),
)

chart.animate(
    Config(
        {"lightness": "Won", "title": "Won 112 out of 116 (96.5%)"}
    ),
    Style(
        {"plot": {"marker": {"maxLightness": 0, "minLightness": 0.8}}}
    ),
    delay=4,
)

chart.animate(
    Config(
        {"lightness": "Lost", "title": "Lost 3 times, retired once"}
    ),
    delay=4,
)

chart.animate(
    Config({"lightness": None, "title": ""}),
    Style(
        {
            "plot": {
                "marker": {"maxLightness": None, "minLightness": None}
            }
        }
    ),
    delay=4,
)

chart.animate(
    Config(
        {
            "lightness": "3SetWin",
            "title": "90 wins (80%) in straight sets",
        }
    ),
    Style(
        {"plot": {"marker": {"maxLightness": 0, "minLightness": 0.8}}}
    ),
)

chart.animate(
    Config(
        {
            "lightness": "Straightwin",
            "title": "Won 4 titles without dropping a set",
        }
    ),
    delay=3,
)

chart.animate(
    Config({"lightness": None, "title": ""}),
    Style(
        {
            "plot": {
                "marker": {"maxLightness": None, "minLightness": None}
            }
        }
    ),
    delay=4,
)

chart.animate(
    Config(
        {
            "lightness": "Novak",
            "title": "Played the most times against Djokovic - 10 matches",
        }
    ),
    Style(
        {"plot": {"marker": {"maxLightness": 0, "minLightness": 0.8}}}
    ),
)

chart.animate(
    Config(
        {
            "lightness": "Roger",
            "title": "Second on this list is Federer - with 6 encounters",
        }
    ),
    delay=4,
)

chart.animate(
    Config(
        {
            "lightness": "Final",
            "title": "Rafa won all of his 14 finals",
        }
    ),
    delay=4,
)

chart.animate(
    data.filter("record.Year != 'Total' && record.Round == 'F'"),
    Config(
        {
            "y": {"set": "Round2", "range": {"max": 1, "min": -5}},
            "x": "Count",
            "lightness": None,
            "noop": "Year",
            "label": None,
            "title": "",
        }
    ),
    Style(
        {
            "plot": {
                "marker": {
                    "borderWidth": 0,
                    "colorPalette": "#C6652A #CDA02E #47B0FF #329564 #5C88F2 #91A9B5 #DBC4B1",
                    "maxLightness": None,
                    "minLightness": None,
                    "label": {
                        "position": "center",
                        "format": "dimensionsFirst",
                    },
                },
                "xAxis": {
                    "title": {"color": "#ffffff00"},
                    "label": {"color": "#ffffff00"},
                    "interlacing": {"color": "#ffffff00"},
                },
                "yAxis": {
                    "title": {"color": "#ffffff00"},
                    "label": {"color": "#ffffff00", "fontSize": None},
                },
            }
        }
    ),
    delay=3,
)

chart.animate(
    data.filter(
        """
        record.Year == "Total" &&
        record.Tournament == "Roland Garros" &&
        record.Player == "Nadal"
        """
    ),
    Config(
        {
            "noop": ["Level", "Round2"],
            "label": ["Player", "Tournament", "Count"],
            "y": {"set": ["Player", "Tournament"]},
        }
    ),
    duration=0,
)

chart.animate(Config({"noop": "Level"}), duration=0)

chart.animate(
    data.filter(
        "record.Year == 'Total' && record.Round == 'GS' && record.Top == '1'"
    ),
    Config(
        {
            "y": {
                "set": ["Player", "Tournament", "Level"],
                "range": {"max": None, "min": None},
            },
            "title": "Rafa won the same Grand Slam title the most times",
            "color": "Level",
            "legend": "color",
            "noop": None,
            "sort": "byValue",
        }
    ),
)

chart.animate(
    data.filter('record.Year == "Total" && record.Top == "1"'),
    Config(
        {
            "y": {
                "set": ["Player", "Tournament", "Level"],
                "range": {"max": 19, "min": 7},
            },
            "x": ["Count"],
            "title": "Winning the same ATP title - Rafa is 1st, 2nd, 3rd & 4th!",
        }
    ),
    delay=5,
)

chart.animate(
    data.filter(
        'record.Year == "Total" && record.Round == "GS" && record.Top == "1"'
    ),
    Config(
        {
            "y": {
                "set": ["Player", "Tournament", "Level"],
                "range": {"max": None, "min": None},
            },
            "x": ["Count"],
            "title": "",
            "color": "Level",
        }
    ),
    delay=5,
)

chart.animate(Config({"x": ["Count", "Total_GS"], "label": "Player"}))

chart.animate(
    data.filter("record.Year == 'Total' && record.Round == 'GS'"),
    Config(
        {
            "y": {
                "set": ["Player"],
                "range": {"max": None, "min": None},
            },
            "x": ["Count", "Tournament", "Level", "Total_GS"],
            "title": "Rafa also leads in the number of total Grand Slams won",
        }
    ),
)

chart.animate(
    Config({"label": ["Total_GS"]}),
    Style(
        {
            "plot": {
                "marker": {
                    "label": {
                        "position": "right",
                        "filter": "color(#666666FF)",
                    }
                }
            }
        }
    ),
)
```

docs/showcases/musicformats.md METASEP
---
csv_url: ./musicformats.csv
---

# Music formats (Year by Year)

<div class="showcase">
  <iframe  id="showcase" src="./main.html" width="100%" scrolling="no" frameborder="0"></iframe>
</div>
<script src="../../assets/javascripts/iframe/autoheight.js"></script>
<script src="../../assets/javascripts/iframe/click.js"></script>

```python
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style, DisplayTarget

df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/musicformats/musicformats.csv",
    dtype={"Year": str},
)
data = Data()
data.add_df(df)

config = {
    "channels": {
        "y": {
            "set": ["Format"],
        },
        "x": {"set": ["Revenue [m$]"]},
        "label": {"set": ["Revenue [m$]"]},
        "color": {"set": ["Format"]},
    },
    "sort": "byValue",
}

style = Style(
    {
        "plot": {
            "paddingLeft": 100,
            "paddingTop": 25,
            "yAxis": {
                "color": "#ffffff00",
                "label": {"paddingRight": 10},
            },
            "xAxis": {
                "title": {"color": "#ffffff00"},
                "label": {
                    "color": "#ffffff00",
                    "numberFormat": "grouped",
                },
            },
            "marker": {
                "colorPalette": "#b74c20FF #c47f58FF #1c9761FF"
                + " #ea4549FF #875792FF #3562b6FF"
                + " #ee7c34FF #efae3aFF"
            },
        },
    }
)

chart = Chart(display=DisplayTarget.END)

chart.animate(data, style)

for year in range(1973, 2021):
    config["title"] = f"Music Revenue by Format - Year by Year {year}"
    chart.animate(
        Data.filter(f"parseInt(record.Year) == {year}"),
        Config(config),
        duration=0.2,
        x={"easing": "linear", "delay": 0},
        y={"delay": 0},
        show={"delay": 0},
        hide={"delay": 0},
        title={"duration": 0, "delay": 0},
    )

chart.animate(
    Config(
        {
            "channels": {
                "x": {"attach": ["Year"]},
                "label": {"set": None},
            }
        }
    ),
    duration=0.3,
)

chart.animate(
    Data.filter("record.Year == '2020' || record.Year == '1972'"),
    Config({"title": "Lets see the total of the last 47 years"}),
    duration=2,
)

chart.animate(Config({"sort": "none"}), delay=0, duration=2)

for year in reversed(range(1973, 2020)):
    chart.animate(
        Data.filter(
            f"parseInt(record.Year) >= {year} || record.Year == '1972'"
        ),
        Config({"split": True}),
        Style({"plot.xAxis.interlacing.color": "#ffffff"}),
        duration=0.005,
    )

chart.animate(
    Data.filter("record.Year != '1972'"),
    Config({"split": False}),
    duration=1.5,
)

chart.animate(
    Config({"channels": {"x": {"detach": ["Year"]}}}), duration=0
)

chart.animate(
    Config({"channels": {"label": {"set": ["Revenue [m$]"]}}}),
    duration=0.1,
)

chart.animate(
    Config(
        {
            "channels": {
                "x": {"attach": ["Year"]},
                "label": {"detach": ["Revenue [m$]"]},
            }
        }
    ),
    duration=1,
)

chart.animate(
    Config(
        {
            "channels": {
                "x": {"set": ["Year"]},
                "y": {
                    "set": ["Revenue [m$]", "Format"],
                    "range": {"min": None, "max": None},
                },
                "color": {"set": ["Format"]},
            },
            "title": "Music Revenue by Format in the USA 1973 - 2020",
            "split": True,
        }
    ),
    Style(
        {
            "plot": {
                "paddingLeft": 7.5,
                "paddingTop": 25,
                "xAxis": {
                    "label": {
                        "fontSize": 9,
                        "angle": 2.0,
                        "color": "#8e8e8e",
                    }
                },
                "yAxis": {
                    "interlacing": {"color": "#ffffff00"},
                    "title": {"color": "#ffffff00"},
                    "label": {"color": "#ffffff00"},
                },
            }
        }
    ),
    duration=2,
)

chart.animate(Config({"geometry": "area"}), duration=1)

chart.animate(
    Config(
        {
            "channels": {
                "x": {"set": ["Year"]},
                "y": {"range": {"max": "110%"}},
            },
            "align": "center",
            "split": False,
        }
    ),
    Style({"plot.marker.borderWidth": 1}),
    duration=1,
)
```

docs/showcases/music.md METASEP
---
csv_url: ./music.csv
---

# Music formats

<div class="showcase">
  <iframe  id="showcase" src="./main.html" width="100%" scrolling="no" frameborder="0"></iframe>
</div>
<script src="../../assets/javascripts/iframe/autoheight.js"></script>
<script src="../../assets/javascripts/iframe/click.js"></script>

```python
import pandas as pd
from ipyvizzu import Chart, Data, Config, Style

df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/music/music.csv",
    dtype={"Year": str},
)
data = Data()
data.add_df(df)

chart = Chart()

chart.animate(data)

chart.animate(
    Config(
        {
            "x": "Year",
            "y": ["Format", "Revenue [m$]"],
            "color": "Format",
            "geometry": "area",
            "align": "center",
            "title": "Music Revenue by Format 1973-2020",
        }
    ),
    Style(
        {
            "plot": {
                "xAxis": {"label": {"fontSize": 9, "angle": 2.0}},
                "marker": {
                    "colorPalette": "#b74c20FF #c47f58FF #1c9761FF"
                    + " #ea4549FF #875792FF #3562b6FF"
                    + " #ee7c34FF #efae3aFF"
                },
            }
        }
    ),
)

chart.animate(
    Config(
        {
            "align": "stretch",
            "title": "Music Revenue by Format 1973-2020(%)",
        }
    ),
    delay=1,
)

chart.animate(
    Config(
        {
            "align": "center",
            "title": "Music Revenue by Format 1973-2020",
        }
    ),
    delay=1,
)

chart.animate(Config({"split": True}), delay=1)

chart.animate(
    Data.filter(
        "record.Format == 'Vinyl' ||record.Format == 'Streaming'"
    ),
    Config({"title": "Revenue of Vinyl & Streaming 1973-2020"}),
    delay=1,
)

chart.animate(
    Data.filter(None),
    Config(
        {"title": "Music Revenue by Format 1973-2020", "split": False}
    ),
    delay=1,
)

chart.animate(
    Config(
        {
            "x": "Year",
            "y": "Revenue [m$]",
            "noop": "Format",
            "align": "none",
            "geometry": "line",
        }
    ),
    delay=1,
)
```

docs/examples/index.md METASEP
# Examples

The `ipyvizzu` examples are grouped into four categories.

- [Preset charts](./presets/index.md): Examples of the well-known chart types
  `ipyvizzu` offers a shorthand for, as described in the
  [Chart presets](../tutorial/chart_presets.md) chapter of the Tutorial.
- [Analytical operations](./analytical_operations/index.md): A collection of
  examples to help you apply animated transitions that show another facet of the
  data under analysis. Also a great source of inspiration for finding the next
  chart when you're building a story.
- [Static charts](./static/index.md): Examples of well-known chart types
  configured with the original chart type-agnostic syntax of `ipyvizzu`.

docs/environments/index.md METASEP
# Environments

`ipyvizzu` can be used in a lot of different environments. We grouped these into
several categories. We would love to add more environments and examples, so if
you miss anything from our list, please open an issue in our
[Github repo](https://github.com/vizzuhq/ipyvizzu).

docs/dev/index.md METASEP
# Development

We have compiled some information on the development of `ipyvizzu` here. If
you're interested in contributing to our open-source tool (which we highly
encourage), please refer to the Contributing chapter. Our community upholds a
strict Code of Conduct that we expect all members to follow. Plus, we've got you
covered with info on our code's test coverage.

docs/assets/logo-white.svg METASEP
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 750 192" xmlns="http://www.w3.org/2000/svg">
	<g fill="#ffffff">
		<path d="M 14,0 92.5,190 171,0 133,0 92.5,106.2 52,0 Z"/>
		<path d="m 196,0 v 188 h 35 V 0 Z"/>
		<path d="M 297,188 405,0 H 366 L 258.5,188 Z" />
		<path d="M 465.5,188 573.5,0 h -39 L 427,188 Z" />
		<path d="m 597.5,0 v 120 c 0,42.5 33,72 70.75,71.5 C 704.5,192 738.72,162 739,120 V 0 H 704 V 120 C 703.76,144.13 690.64,158.5 668.25,158.5 646.14,158.65 632.5,144.5 632.5,120 V 0 Z" />
		<circle r="24.5" cx="286.5" cy="24.75" />
		<circle r="24.5" cx="455" cy="24.75" />
		<circle r="24.5" cx="380.5" cy="163" />
		<circle r="24.5" cx="549" cy="163" />
	</g>
</svg>
docs/assets/ipyvizzu-promo.gif METASEP

docs/assets/favicon.svg METASEP
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg version="1.1" width="32" height="32" xmlns="http://www.w3.org/2000/svg">
	<rect x="0" y="0" width="32" height="32" rx="4" ry="4" style="fill:white;stroke:#ffffff;stroke-width:0" />
	<polygon points="6,29 21,3 26,3 11,29" style="fill:#000000;stroke:#000000;stroke-width:0" />
	<circle cx="10" cy="6" r="3" stroke="#ef2821" stroke-width="0" fill="#ef2821" />
	<circle cx="22" cy="26" r="3" stroke="#00abf9" stroke-width="0" fill="#00abf9" />
</svg>
docs/assets/end.gif METASEP

docs/assets/begin.gif METASEP

docs/assets/api-overview.svg METASEP
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1024" height="780" viewBox="0 0 1024 780">
<g id="code_structure4">
<path id="Shape_2_" d="M137.000,404.000 L474.000,404.000 L349.000,215.000 L337.000,215.000 L137.000,404.000 zM526.000,404.000 L791.000,404.000 L375.000,215.000 L363.000,215.000 L526.000,404.000 z" fill="#4474CD" fill-opacity="0.051" />
<path id="Rounded-Rectangl" d="M526.000,404.000 L790.438,404.000 L790.438,452.000 L526.000,452.000 L526.000,404.000 z" fill="#F49620" />
<path id="anim-options" d="M775.835,432.444 C775.416,433.909 774.775,435.260 773.912,436.499 C773.049,437.738 772.145,438.619 771.200,439.142 C771.200,439.142 770.781,437.928 770.781,437.928 C771.883,437.083 772.770,435.770 773.439,433.991 C774.109,432.211 774.451,430.237 774.465,428.067 C774.465,428.067 774.465,427.723 774.465,427.723 C774.465,426.219 774.308,424.821 773.993,423.528 C773.677,422.235 773.239,421.077 772.677,420.053 C772.114,419.029 771.482,418.230 770.781,417.657 C770.781,417.657 771.200,416.444 771.200,416.444 C772.145,416.966 773.045,417.840 773.901,419.065 C774.757,420.289 775.398,421.639 775.824,423.114 C776.250,424.590 776.463,426.169 776.463,427.852 C776.463,429.449 776.254,430.980 775.835,432.444 zM765.060,427.379 C766.052,427.601 766.856,427.866 767.472,428.174 C768.088,428.482 768.544,428.853 768.842,429.286 C769.139,429.719 769.287,430.247 769.287,430.870 C769.287,431.909 768.872,432.741 768.041,433.368 C767.211,433.995 766.133,434.308 764.808,434.308 C763.877,434.308 763.053,434.143 762.337,433.814 C761.621,433.484 761.061,433.024 760.656,432.433 C760.251,431.843 760.049,431.203 760.049,430.516 C760.049,430.516 762.036,430.516 762.036,430.516 C762.072,431.182 762.339,431.710 762.837,432.100 C763.334,432.491 763.992,432.686 764.808,432.686 C765.560,432.686 766.163,432.534 766.618,432.229 C767.073,431.925 767.300,431.519 767.300,431.010 C767.300,430.473 767.098,430.056 766.693,429.759 C766.289,429.461 765.583,429.205 764.577,428.990 C763.571,428.776 762.772,428.518 762.181,428.217 C761.591,427.916 761.154,427.558 760.871,427.143 C760.588,426.728 760.447,426.233 760.447,425.660 C760.447,424.708 760.849,423.902 761.655,423.243 C762.461,422.585 763.490,422.255 764.743,422.255 C766.061,422.255 767.130,422.595 767.950,423.276 C768.770,423.956 769.180,424.826 769.180,425.886 C769.180,425.886 767.182,425.886 767.182,425.886 C767.182,425.342 766.951,424.873 766.489,424.479 C766.027,424.085 765.445,423.888 764.743,423.888 C764.020,423.888 763.454,424.046 763.046,424.361 C762.638,424.676 762.434,425.088 762.434,425.596 C762.434,426.076 762.624,426.438 763.003,426.681 C763.383,426.924 764.068,427.157 765.060,427.379 zM755.548,426.402 C755.541,425.564 755.349,424.944 754.973,424.543 C754.597,424.142 754.012,423.942 753.217,423.942 C752.573,423.942 752.007,424.114 751.520,424.457 C751.033,424.801 750.653,425.252 750.381,425.811 C750.381,425.811 750.381,434.093 750.381,434.093 L748.394,434.093 L748.394,422.470 L750.274,422.470 C750.274,422.470 750.338,423.931 750.338,423.931 C751.226,422.814 752.386,422.255 753.819,422.255 C756.275,422.255 757.514,423.641 757.535,426.412 C757.535,426.412 757.535,434.093 757.535,434.093 L755.548,434.093 C755.548,434.093 755.548,426.402 755.548,426.402 zM743.393,433.556 C742.588,434.057 741.662,434.308 740.617,434.308 C739.041,434.308 737.764,433.760 736.787,432.664 C735.809,431.569 735.321,430.118 735.321,428.314 C735.321,428.314 735.321,428.174 735.321,428.174 C735.321,427.035 735.544,426.011 735.992,425.102 C736.440,424.192 737.063,423.490 737.861,422.996 C738.660,422.502 739.571,422.255 740.595,422.255 C742.178,422.255 743.458,422.803 744.435,423.899 C745.413,424.994 745.902,426.452 745.902,428.271 C745.902,428.271 745.902,428.410 745.902,428.410 C745.902,429.542 745.685,430.557 745.252,431.456 C744.818,432.355 744.199,433.055 743.393,433.556 zM743.007,425.075 C742.401,424.284 741.598,423.888 740.595,423.888 C739.614,423.888 738.823,424.278 738.221,425.059 C737.619,425.839 737.319,426.957 737.319,428.410 C737.319,429.699 737.618,430.734 738.216,431.515 C738.814,432.296 739.614,432.686 740.617,432.686 C741.626,432.686 742.428,432.290 743.023,431.499 C743.617,430.708 743.914,429.599 743.914,428.174 C743.914,426.899 743.612,425.866 743.007,425.075 zM731.690,420.515 C731.303,420.515 731.011,420.407 730.814,420.193 C730.617,419.978 730.519,419.709 730.519,419.387 C730.519,419.065 730.617,418.793 730.814,418.571 C731.011,418.349 731.303,418.238 731.690,418.238 C732.077,418.238 732.370,418.349 732.571,418.571 C732.771,418.793 732.871,419.065 732.871,419.387 C732.871,419.709 732.771,419.978 732.571,420.193 C732.370,420.407 732.077,420.515 731.690,420.515 zM726.716,434.308 C725.828,434.308 725.159,434.039 724.707,433.502 C724.256,432.965 724.031,432.202 724.031,431.214 C724.031,431.214 724.031,424.006 724.031,424.006 L721.914,424.006 L721.914,422.470 L724.031,422.470 L724.031,419.655 L726.018,419.655 L726.018,422.470 L728.188,422.470 L728.188,424.006 L726.018,424.006 C726.018,424.006 726.018,431.223 726.018,431.223 C726.018,431.689 726.115,432.039 726.308,432.272 C726.501,432.505 726.831,432.621 727.296,432.621 C727.525,432.621 727.840,432.578 728.242,432.492 C728.242,432.492 728.242,434.094 728.242,434.094 C727.719,434.237 727.210,434.308 726.716,434.308 zM716.296,434.308 C714.885,434.308 713.775,433.860 712.966,432.965 C712.966,432.965 712.966,438.562 712.966,438.562 L710.979,438.562 L710.979,422.470 L712.794,422.470 C712.794,422.470 712.891,423.759 712.891,423.759 C713.700,422.756 714.825,422.255 716.264,422.255 C717.660,422.255 718.765,422.781 719.578,423.834 C720.391,424.887 720.797,426.352 720.797,428.228 C720.797,428.228 720.797,428.410 720.797,428.410 C720.797,430.179 720.393,431.605 719.583,432.686 C718.774,433.767 717.678,434.308 716.296,434.308 zM717.972,425.080 C717.413,424.321 716.647,423.942 715.673,423.942 C714.470,423.942 713.568,424.475 712.966,425.542 C712.966,425.542 712.966,431.096 712.966,431.096 C713.560,432.156 714.470,432.686 715.695,432.686 C716.647,432.686 717.404,432.308 717.967,431.552 C718.529,430.797 718.810,429.674 718.810,428.185 C718.810,426.874 718.531,425.839 717.972,425.080 zM705.978,433.556 C705.173,434.057 704.247,434.308 703.201,434.308 C701.626,434.308 700.349,433.760 699.372,432.664 C698.394,431.569 697.906,430.118 697.906,428.314 C697.906,428.314 697.906,428.174 697.906,428.174 C697.906,427.035 698.129,426.011 698.577,425.102 C699.024,424.192 699.648,423.490 700.446,422.996 C701.245,422.502 702.156,422.255 703.180,422.255 C704.763,422.255 706.043,422.803 707.020,423.899 C707.998,424.994 708.487,426.452 708.487,428.271 C708.487,428.271 708.487,428.410 708.487,428.410 C708.487,429.542 708.270,430.557 707.837,431.456 C707.403,432.355 706.784,433.055 705.978,433.556 zM705.592,425.075 C704.986,424.284 704.183,423.888 703.180,423.888 C702.199,423.888 701.408,424.278 700.806,425.059 C700.204,425.839 699.904,426.957 699.904,428.410 C699.904,429.699 700.203,430.734 700.801,431.515 C701.398,432.296 702.199,432.686 703.201,432.686 C704.211,432.686 705.013,432.290 705.608,431.499 C706.202,430.708 706.499,429.599 706.499,428.174 C706.499,426.899 706.197,425.866 705.592,425.075 zM688.001,426.423 C688.001,425.592 687.811,424.971 687.432,424.559 C687.052,424.148 686.415,423.942 685.520,423.942 C684.782,423.942 684.170,424.162 683.683,424.602 C683.196,425.043 682.913,425.635 682.834,426.380 C682.834,426.380 682.834,434.093 682.834,434.093 L680.836,434.093 C680.836,434.093 680.836,426.477 680.836,426.477 C680.836,424.787 680.009,423.942 678.355,423.942 C677.051,423.942 676.160,424.497 675.680,425.607 C675.680,425.607 675.680,434.093 675.680,434.093 L673.693,434.093 L673.693,422.470 L675.573,422.470 C675.573,422.470 675.626,423.759 675.626,423.759 C676.478,422.756 677.628,422.255 679.075,422.255 C680.700,422.255 681.807,422.878 682.394,424.124 C682.781,423.566 683.284,423.114 683.903,422.771 C684.523,422.427 685.255,422.255 686.100,422.255 C688.649,422.255 689.946,423.605 689.989,426.305 C689.989,426.305 689.989,434.093 689.989,434.093 L688.001,434.093 C688.001,434.093 688.001,426.423 688.001,426.423 zM669.546,420.515 C669.160,420.515 668.868,420.407 668.671,420.193 C668.474,419.978 668.375,419.709 668.375,419.387 C668.375,419.065 668.474,418.793 668.671,418.571 C668.868,418.349 669.160,418.238 669.546,418.238 C669.933,418.238 670.227,418.349 670.427,418.571 C670.627,418.793 670.728,419.065 670.728,419.387 C670.728,419.709 670.627,419.978 670.427,420.193 C670.227,420.407 669.933,420.515 669.546,420.515 zM663.380,426.402 C663.373,425.564 663.181,424.944 662.806,424.543 C662.430,424.142 661.844,423.942 661.049,423.942 C660.405,423.942 659.839,424.114 659.352,424.457 C658.865,424.801 658.485,425.252 658.213,425.811 C658.213,425.811 658.213,434.093 658.213,434.093 L656.226,434.093 L656.226,422.470 L658.106,422.470 C658.106,422.470 658.170,423.931 658.170,423.931 C659.058,422.814 660.218,422.255 661.651,422.255 C664.107,422.255 665.346,423.641 665.368,426.412 C665.368,426.412 665.368,434.093 665.368,434.093 L663.380,434.093 C663.380,434.093 663.380,426.402 663.380,426.402 zM651.156,432.868 C650.232,433.828 649.129,434.308 647.847,434.308 C646.701,434.308 645.761,433.984 645.027,433.336 C644.293,432.688 643.926,431.866 643.926,430.870 C643.926,429.660 644.386,428.720 645.306,428.051 C646.227,427.381 647.521,427.046 649.190,427.046 C649.190,427.046 651.123,427.046 651.123,427.046 C651.123,427.046 651.123,426.133 651.123,426.133 C651.123,425.438 650.916,424.885 650.500,424.473 C650.085,424.062 649.473,423.856 648.663,423.856 C647.954,423.856 647.360,424.035 646.880,424.393 C646.400,424.751 646.160,425.184 646.160,425.693 C646.160,425.693 644.162,425.693 644.162,425.693 C644.162,425.113 644.368,424.552 644.780,424.011 C645.192,423.471 645.750,423.043 646.456,422.728 C647.161,422.413 647.936,422.255 648.782,422.255 C650.121,422.255 651.170,422.590 651.929,423.260 C652.688,423.929 653.082,424.851 653.111,426.026 C653.111,426.026 653.111,431.375 653.111,431.375 C653.111,432.442 653.247,433.291 653.519,433.921 C653.519,433.921 653.519,434.093 653.519,434.093 C653.519,434.093 651.435,434.093 651.435,434.093 C651.320,433.864 651.227,433.456 651.156,432.868 zM651.123,428.453 C651.123,428.453 649.566,428.453 649.566,428.453 C647.131,428.453 645.913,429.166 645.913,430.591 C645.913,431.214 646.121,431.701 646.536,432.052 C646.952,432.403 647.485,432.578 648.137,432.578 C648.760,432.578 649.351,432.417 649.910,432.095 C650.468,431.773 650.873,431.354 651.123,430.838 C651.123,430.838 651.123,428.453 651.123,428.453 zM642.336,437.928 C642.336,437.928 641.928,439.142 641.928,439.142 C640.976,438.612 640.066,437.724 639.200,436.478 C637.509,434.043 636.664,431.132 636.664,427.744 C636.664,426.126 636.881,424.572 637.314,423.082 C637.748,421.593 638.394,420.239 639.253,419.022 C640.113,417.804 641.004,416.945 641.928,416.444 C641.928,416.444 642.336,417.754 642.336,417.754 C641.291,418.556 640.433,419.781 639.764,421.428 C639.094,423.075 638.727,424.919 638.662,426.960 C638.662,426.960 638.652,427.873 638.652,427.873 C638.652,430.638 639.157,433.037 640.166,435.071 C640.775,436.288 641.498,437.240 642.336,437.928 zM624.477,427.379 C625.469,427.601 626.273,427.866 626.889,428.174 C627.505,428.482 627.961,428.853 628.259,429.286 C628.556,429.719 628.704,430.247 628.704,430.870 C628.704,431.909 628.289,432.741 627.458,433.368 C626.627,433.995 625.550,434.308 624.225,434.308 C623.294,434.308 622.470,434.143 621.754,433.814 C621.038,433.484 620.478,433.024 620.073,432.433 C619.668,431.843 619.466,431.203 619.466,430.516 C619.466,430.516 621.453,430.516 621.453,430.516 C621.489,431.182 621.756,431.710 622.254,432.100 C622.751,432.491 623.409,432.686 624.225,432.686 C624.977,432.686 625.580,432.534 626.035,432.229 C626.490,431.925 626.717,431.519 626.717,431.010 C626.717,430.473 626.515,430.056 626.110,429.759 C625.706,429.461 625.000,429.205 623.994,428.990 C622.988,428.776 622.189,428.518 621.598,428.217 C621.008,427.916 620.571,427.558 620.288,427.143 C620.005,426.728 619.864,426.233 619.864,425.660 C619.864,424.708 620.266,423.902 621.072,423.243 C621.878,422.585 622.907,422.255 624.160,422.255 C625.478,422.255 626.547,422.595 627.367,423.276 C628.187,423.956 628.597,424.826 628.597,425.886 C628.597,425.886 626.599,425.886 626.599,425.886 C626.599,425.342 626.368,424.873 625.906,424.479 C625.444,424.085 624.862,423.888 624.160,423.888 C623.437,423.888 622.871,424.046 622.463,424.361 C622.055,424.676 621.851,425.088 621.851,425.596 C621.851,426.076 622.041,426.438 622.420,426.681 C622.800,426.924 623.485,427.157 624.477,427.379 zM612.022,438.669 C611.184,438.669 610.364,438.490 609.562,438.132 C608.760,437.774 608.147,437.283 607.725,436.660 C607.725,436.660 608.756,435.468 608.756,435.468 C609.608,436.521 610.650,437.047 611.882,437.047 C612.849,437.047 613.603,436.775 614.143,436.231 C614.684,435.686 614.954,434.920 614.954,433.932 C614.954,433.932 614.954,432.933 614.954,432.933 C614.160,433.850 613.075,434.308 611.700,434.308 C610.339,434.308 609.238,433.760 608.396,432.664 C607.555,431.569 607.134,430.075 607.134,428.185 C607.134,426.373 607.553,424.932 608.391,423.861 C609.229,422.791 610.339,422.255 611.721,422.255 C613.139,422.255 614.245,422.756 615.040,423.759 C615.040,423.759 615.137,422.470 615.137,422.470 L616.952,422.470 C616.952,422.470 616.952,433.814 616.952,433.814 C616.952,435.318 616.507,436.503 615.615,437.369 C614.723,438.236 613.526,438.669 612.022,438.669 zM614.954,425.607 C614.346,424.497 613.433,423.942 612.215,423.942 C611.248,423.942 610.493,424.318 609.949,425.070 C609.404,425.822 609.132,426.935 609.132,428.410 C609.132,429.721 609.401,430.751 609.938,431.499 C610.475,432.247 611.227,432.621 612.194,432.621 C613.447,432.621 614.367,432.052 614.954,430.913 C614.954,430.913 614.954,425.607 614.954,425.607 zM605.007,424.178 C603.704,424.178 602.819,424.733 602.354,425.843 C602.354,425.843 602.354,434.093 602.354,434.093 L600.367,434.093 L600.367,422.470 L602.300,422.470 C602.300,422.470 602.332,423.813 602.332,423.813 C602.984,422.774 603.908,422.255 605.104,422.255 C605.491,422.255 605.784,422.305 605.985,422.405 C605.985,422.405 605.985,424.253 605.985,424.253 C605.684,424.203 605.358,424.178 605.007,424.178 zM595.296,432.868 C594.372,433.828 593.269,434.308 591.988,434.308 C590.842,434.308 589.902,433.984 589.168,433.336 C588.434,432.688 588.067,431.866 588.067,430.870 C588.067,429.660 588.527,428.720 589.447,428.051 C590.367,427.381 591.662,427.046 593.330,427.046 C593.330,427.046 595.264,427.046 595.264,427.046 C595.264,427.046 595.264,426.133 595.264,426.133 C595.264,425.438 595.056,424.885 594.641,424.473 C594.226,424.062 593.613,423.856 592.804,423.856 C592.095,423.856 591.501,424.035 591.021,424.393 C590.541,424.751 590.301,425.184 590.301,425.693 C590.301,425.693 588.303,425.693 588.303,425.693 C588.303,425.113 588.509,424.552 588.921,424.011 C589.332,423.471 589.891,423.043 590.597,422.728 C591.302,422.413 592.077,422.255 592.922,422.255 C594.261,422.255 595.310,422.590 596.070,423.260 C596.829,423.929 597.223,424.851 597.251,426.026 C597.251,426.026 597.251,431.375 597.251,431.375 C597.251,432.442 597.387,433.291 597.660,433.921 C597.660,433.921 597.660,434.093 597.660,434.093 C597.660,434.093 595.576,434.093 595.576,434.093 C595.461,433.864 595.368,433.456 595.296,432.868 zM595.264,428.453 C595.264,428.453 593.706,428.453 593.706,428.453 C591.271,428.453 590.054,429.166 590.054,430.591 C590.054,431.214 590.262,431.701 590.677,432.052 C591.092,432.403 591.626,432.578 592.278,432.578 C592.901,432.578 593.492,432.417 594.050,432.095 C594.609,431.773 595.013,431.354 595.264,430.838 C595.264,430.838 595.264,428.453 595.264,428.453 zM581.385,434.093 L578.560,425.284 L575.810,434.093 L574.199,434.093 L570.826,422.470 L572.802,422.470 L575.090,431.171 L577.797,422.470 L579.398,422.470 L582.159,431.354 L584.393,422.470 L586.380,422.470 L582.996,434.093 L581.385,434.093 zM568.011,434.093 L563.961,428.711 L562.715,430.011 L562.715,434.093 L560.728,434.093 L560.728,417.593 L562.715,417.593 L562.715,427.572 L563.779,426.294 L567.399,422.470 L569.816,422.470 L565.293,427.325 L570.342,434.093 L568.011,434.093 zM557.731,426.536 L556.399,427.546 L554.401,424.452 L552.467,427.470 L551.124,426.493 L553.284,423.528 L550.039,422.562 L550.534,420.942 L553.778,422.144 L553.681,418.452 L555.325,418.452 L555.217,422.198 L558.408,421.017 L558.902,422.648 L555.604,423.625 L557.731,426.536 zM548.256,426.536 L546.924,427.546 L544.926,424.452 L542.993,427.470 L541.650,426.493 L543.809,423.528 L540.565,422.562 L541.059,420.942 L544.303,422.144 L544.206,418.452 L545.850,418.452 L545.743,422.198 L548.933,421.017 L549.427,422.648 L546.129,423.625 L548.256,426.536 zM670.524,434.093 L668.536,434.093 L668.536,422.470 L670.524,422.470 L670.524,434.093 zM732.667,434.093 L730.680,434.093 L730.680,422.470 L732.667,422.470 L732.667,434.093 z" fill="#FFFFFF" />
<path id="Color-Fill-1" d="M437.381,606.646 L437.381,654.525 L172.934,654.525 L172.934,606.646 L437.381,606.646 z" fill="#F4C30A" />
<path id="Rectangle_1_" d="M437.381,546.000 L437.381,593.879 L172.934,593.879 L172.934,546.000 L437.381,546.000 z" fill="#07AF73" />
<path id="Rectangle_1_2" d="M437.381,485.354 L437.381,533.232 L172.934,533.232 L172.934,485.354 L437.381,485.354 z" fill="#4474CD" />
<path id="style" d="M225.529,631.851 C225.557,632.997 225.892,633.922 226.533,634.628 C227.174,635.333 227.989,635.686 228.977,635.686 C229.679,635.686 230.273,635.543 230.760,635.256 C231.247,634.970 231.673,634.590 232.038,634.117 C232.038,634.117 233.252,635.063 233.252,635.063 C232.278,636.560 230.817,637.308 228.869,637.308 C227.294,637.308 226.012,636.791 225.024,635.756 C224.035,634.721 223.541,633.337 223.541,631.604 C223.541,631.604 223.541,631.239 223.541,631.239 C223.541,630.086 223.762,629.056 224.202,628.150 C224.642,627.244 225.258,626.535 226.050,626.023 C226.841,625.511 227.699,625.255 228.622,625.255 C230.133,625.255 231.308,625.753 232.146,626.748 C232.984,627.744 233.403,629.169 233.403,631.024 C233.403,631.024 233.403,631.851 233.403,631.851 C233.403,631.851 225.529,631.851 225.529,631.851 zM231.415,630.068 C231.358,629.058 231.086,628.276 230.599,627.720 C230.112,627.166 229.453,626.888 228.622,626.888 C227.820,626.888 227.147,627.180 226.603,627.763 C226.059,628.347 225.722,629.165 225.593,630.218 C225.593,630.218 231.415,630.218 231.415,630.218 C231.415,630.218 231.415,630.068 231.415,630.068 zM218.879,620.593 L220.867,620.593 L220.867,637.093 L218.879,637.093 L218.879,620.593 zM208.814,641.787 C208.814,641.787 208.438,641.755 208.438,641.755 L207.697,641.615 L207.697,640.004 C207.697,640.004 208.234,640.047 208.234,640.047 C208.907,640.047 209.431,639.911 209.807,639.639 C210.183,639.367 210.493,638.869 210.737,638.146 C210.737,638.146 211.177,636.964 211.177,636.964 L207.031,625.470 L209.201,625.470 L212.101,634.182 L214.808,625.470 L216.935,625.470 C216.935,625.470 212.262,638.887 212.262,638.887 C211.539,640.821 210.389,641.787 208.814,641.787 zM202.497,636.502 C202.046,635.965 201.821,635.202 201.821,634.214 C201.821,634.214 201.821,627.006 201.821,627.006 L199.704,627.006 L199.704,625.470 L201.821,625.470 L201.821,622.655 L203.808,622.655 L203.808,625.470 L205.978,625.470 L205.978,627.006 L203.808,627.006 C203.808,627.006 203.808,634.223 203.808,634.223 C203.808,634.689 203.905,635.039 204.098,635.272 C204.291,635.505 204.621,635.621 205.086,635.621 C205.315,635.621 205.630,635.578 206.032,635.492 C206.032,635.492 206.032,637.094 206.032,637.094 C205.509,637.237 205.000,637.308 204.506,637.308 C203.618,637.308 202.949,637.039 202.497,636.502 zM194.296,630.379 C195.288,630.601 196.091,630.866 196.707,631.174 C197.323,631.482 197.780,631.853 198.077,632.286 C198.374,632.719 198.523,633.247 198.523,633.870 C198.523,634.909 198.107,635.741 197.277,636.368 C196.446,636.995 195.368,637.308 194.043,637.308 C193.112,637.308 192.289,637.143 191.573,636.814 C190.856,636.484 190.296,636.024 189.891,635.433 C189.487,634.843 189.285,634.203 189.285,633.516 C189.285,633.516 191.272,633.516 191.272,633.516 C191.308,634.182 191.574,634.710 192.072,635.100 C192.570,635.491 193.227,635.686 194.043,635.686 C194.795,635.686 195.398,635.534 195.853,635.229 C196.308,634.925 196.535,634.519 196.535,634.010 C196.535,633.473 196.333,633.056 195.929,632.759 C195.524,632.461 194.818,632.205 193.812,631.990 C192.806,631.776 192.008,631.518 191.417,631.217 C190.826,630.916 190.389,630.558 190.106,630.143 C189.823,629.728 189.682,629.233 189.682,628.660 C189.682,627.708 190.085,626.902 190.890,626.243 C191.696,625.585 192.726,625.255 193.979,625.255 C195.296,625.255 196.365,625.595 197.185,626.276 C198.005,626.956 198.415,627.826 198.415,628.886 C198.415,628.886 196.417,628.886 196.417,628.886 C196.417,628.342 196.186,627.873 195.724,627.479 C195.263,627.085 194.681,626.888 193.979,626.888 C193.255,626.888 192.690,627.046 192.282,627.361 C191.873,627.676 191.669,628.088 191.669,628.596 C191.669,629.076 191.859,629.438 192.239,629.681 C192.618,629.924 193.304,630.157 194.296,630.379 z" fill="#FFFFFF" />
<path id="config" d="M246.954,580.369 C246.062,581.236 244.865,581.669 243.361,581.669 C242.523,581.669 241.703,581.490 240.901,581.132 C240.099,580.774 239.486,580.283 239.064,579.660 C239.064,579.660 240.095,578.468 240.095,578.468 C240.947,579.521 241.989,580.047 243.221,580.047 C244.188,580.047 244.941,579.775 245.482,579.231 C246.023,578.686 246.293,577.920 246.293,576.932 C246.293,576.932 246.293,575.933 246.293,575.933 C245.498,576.850 244.413,577.308 243.038,577.308 C241.678,577.308 240.577,576.760 239.735,575.664 C238.894,574.569 238.473,573.075 238.473,571.185 C238.473,569.373 238.892,567.932 239.730,566.861 C240.568,565.791 241.678,565.255 243.060,565.255 C244.478,565.255 245.584,565.756 246.379,566.759 C246.379,566.759 246.476,565.470 246.476,565.470 L248.291,565.470 C248.291,565.470 248.291,576.814 248.291,576.814 C248.291,578.318 247.846,579.503 246.954,580.369 zM246.293,568.607 C245.685,567.497 244.771,566.942 243.554,566.942 C242.587,566.942 241.832,567.318 241.287,568.070 C240.743,568.822 240.471,569.935 240.471,571.410 C240.471,572.721 240.740,573.751 241.277,574.499 C241.814,575.247 242.566,575.621 243.533,575.621 C244.786,575.621 245.706,575.052 246.293,573.913 C246.293,573.913 246.293,568.607 246.293,568.607 zM234.788,563.515 C234.402,563.515 234.110,563.407 233.913,563.193 C233.716,562.978 233.618,562.709 233.618,562.387 C233.618,562.065 233.716,561.793 233.913,561.571 C234.110,561.349 234.402,561.238 234.788,561.238 C235.175,561.238 235.469,561.349 235.669,561.571 C235.870,561.793 235.970,562.065 235.970,562.387 C235.970,562.709 235.870,562.978 235.669,563.193 C235.469,563.407 235.175,563.515 234.788,563.515 zM230.953,562.054 C230.309,562.054 229.811,562.243 229.460,562.620 C229.109,562.997 228.934,563.538 228.934,564.241 C228.934,564.241 228.934,565.470 228.934,565.470 L231.415,565.470 L231.415,567.006 L228.934,567.006 L228.934,577.093 L226.947,577.093 L226.947,567.006 L225.110,567.006 L225.110,565.470 L226.947,565.470 C226.947,565.470 226.947,564.278 226.947,564.278 C226.947,563.031 227.280,562.068 227.946,561.388 C228.612,560.708 229.553,560.367 230.771,560.367 C231.229,560.367 231.684,560.428 232.135,560.549 C232.135,560.549 232.028,562.151 232.028,562.151 C231.691,562.086 231.333,562.054 230.953,562.054 zM220.985,569.402 C220.977,568.564 220.786,567.944 220.410,567.543 C220.034,567.142 219.449,566.942 218.654,566.942 C218.009,566.942 217.443,567.114 216.956,567.457 C216.469,567.801 216.090,568.252 215.818,568.811 C215.818,568.811 215.818,577.093 215.818,577.093 L213.830,577.093 L213.830,565.470 L215.710,565.470 C215.710,565.470 215.775,566.931 215.775,566.931 C216.663,565.814 217.823,565.255 219.255,565.255 C221.711,565.255 222.951,566.641 222.972,569.412 C222.972,569.412 222.972,577.093 222.972,577.093 L220.985,577.093 C220.985,577.093 220.985,569.402 220.985,569.402 zM208.830,576.556 C208.024,577.057 207.099,577.308 206.053,577.308 C204.477,577.308 203.201,576.760 202.223,575.664 C201.246,574.569 200.757,573.118 200.757,571.314 C200.757,571.314 200.757,571.174 200.757,571.174 C200.757,570.035 200.981,569.011 201.429,568.102 C201.876,567.192 202.499,566.490 203.298,565.996 C204.096,565.502 205.007,565.255 206.032,565.255 C207.614,565.255 208.894,565.803 209.872,566.899 C210.849,567.994 211.338,569.452 211.338,571.271 C211.338,571.271 211.338,571.410 211.338,571.410 C211.338,572.542 211.122,573.557 210.688,574.456 C210.255,575.355 209.636,576.055 208.830,576.556 zM208.443,568.075 C207.838,567.284 207.034,566.888 206.032,566.888 C205.050,566.888 204.259,567.278 203.658,568.059 C203.056,568.839 202.755,569.957 202.755,571.410 C202.755,572.699 203.054,573.734 203.652,574.515 C204.250,575.296 205.050,575.686 206.053,575.686 C207.063,575.686 207.865,575.290 208.459,574.499 C209.054,573.708 209.351,572.599 209.351,571.174 C209.351,569.899 209.048,568.866 208.443,568.075 zM192.067,574.601 C192.618,575.324 193.406,575.686 194.430,575.686 C195.139,575.686 195.758,575.471 196.288,575.041 C196.818,574.612 197.112,574.074 197.169,573.430 C197.169,573.430 199.049,573.430 199.049,573.430 C199.013,574.096 198.784,574.730 198.362,575.331 C197.939,575.933 197.375,576.413 196.670,576.771 C195.964,577.129 195.218,577.308 194.430,577.308 C192.847,577.308 191.589,576.780 190.654,575.723 C189.720,574.667 189.252,573.222 189.252,571.389 C189.252,571.389 189.252,571.056 189.252,571.056 C189.252,569.924 189.460,568.918 189.875,568.037 C190.291,567.156 190.887,566.473 191.664,565.986 C192.441,565.499 193.359,565.255 194.419,565.255 C195.723,565.255 196.806,565.646 197.669,566.426 C198.532,567.207 198.992,568.220 199.049,569.466 C199.049,569.466 197.169,569.466 197.169,569.466 C197.112,568.714 196.827,568.096 196.315,567.613 C195.803,567.130 195.171,566.888 194.419,566.888 C193.410,566.888 192.627,567.251 192.072,567.978 C191.517,568.705 191.240,569.756 191.240,571.131 C191.240,571.131 191.240,571.507 191.240,571.507 C191.240,572.846 191.515,573.878 192.067,574.601 zM235.766,577.093 L233.779,577.093 L233.779,565.470 L235.766,565.470 L235.766,577.093 z" fill="#FFFFFF" />
<path id="data" d="M228.504,516.093 C228.390,515.864 228.296,515.456 228.225,514.868 C227.301,515.828 226.198,516.308 224.916,516.308 C223.770,516.308 222.831,515.984 222.097,515.336 C221.362,514.688 220.995,513.866 220.995,512.870 C220.995,511.660 221.456,510.720 222.376,510.051 C223.296,509.381 224.590,509.046 226.259,509.046 C226.259,509.046 228.193,509.046 228.193,509.046 C228.193,509.046 228.193,508.133 228.193,508.133 C228.193,507.438 227.985,506.885 227.570,506.473 C227.154,506.062 226.542,505.856 225.733,505.856 C225.024,505.856 224.429,506.035 223.950,506.393 C223.470,506.751 223.230,507.184 223.230,507.693 C223.230,507.693 221.232,507.693 221.232,507.693 C221.232,507.113 221.438,506.552 221.849,506.011 C222.261,505.471 222.820,505.043 223.525,504.728 C224.231,504.413 225.006,504.255 225.851,504.255 C227.190,504.255 228.239,504.590 228.998,505.260 C229.757,505.929 230.151,506.851 230.180,508.026 C230.180,508.026 230.180,513.375 230.180,513.375 C230.180,514.442 230.316,515.291 230.588,515.921 C230.588,515.921 230.588,516.093 230.588,516.093 C230.588,516.093 228.504,516.093 228.504,516.093 zM228.193,510.453 C228.193,510.453 226.635,510.453 226.635,510.453 C224.200,510.453 222.983,511.166 222.983,512.591 C222.983,513.214 223.190,513.701 223.606,514.052 C224.021,514.403 224.555,514.578 225.206,514.578 C225.829,514.578 226.420,514.417 226.979,514.095 C227.537,513.773 227.942,513.354 228.193,512.838 C228.193,512.838 228.193,510.453 228.193,510.453 zM215.528,515.502 C215.076,514.965 214.851,514.202 214.851,513.214 C214.851,513.214 214.851,506.006 214.851,506.006 L212.735,506.006 L212.735,504.470 L214.851,504.470 L214.851,501.656 L216.838,501.656 L216.838,504.470 L219.008,504.470 L219.008,506.006 L216.838,506.006 C216.838,506.006 216.838,513.223 216.838,513.223 C216.838,513.689 216.935,514.039 217.128,514.272 C217.322,514.505 217.651,514.621 218.117,514.621 C218.346,514.621 218.661,514.578 219.062,514.492 C219.062,514.492 219.062,516.094 219.062,516.094 C218.539,516.237 218.031,516.308 217.536,516.308 C216.648,516.308 215.979,516.039 215.528,515.502 zM209.072,514.868 C208.148,515.828 207.045,516.308 205.763,516.308 C204.617,516.308 203.677,515.984 202.943,515.336 C202.209,514.688 201.842,513.866 201.842,512.870 C201.842,511.660 202.302,510.720 203.222,510.051 C204.143,509.381 205.437,509.046 207.106,509.046 C207.106,509.046 209.039,509.046 209.039,509.046 C209.039,509.046 209.039,508.133 209.039,508.133 C209.039,507.438 208.832,506.885 208.416,506.473 C208.001,506.062 207.389,505.856 206.579,505.856 C205.870,505.856 205.276,506.035 204.796,506.393 C204.316,506.751 204.077,507.184 204.077,507.693 C204.077,507.693 202.078,507.693 202.078,507.693 C202.078,507.113 202.284,506.552 202.696,506.011 C203.108,505.471 203.666,505.043 204.372,504.728 C205.077,504.413 205.852,504.255 206.698,504.255 C208.037,504.255 209.086,504.590 209.845,505.260 C210.604,505.929 210.998,506.851 211.027,508.026 C211.027,508.026 211.027,513.375 211.027,513.375 C211.027,514.442 211.163,515.291 211.435,515.921 C211.435,515.921 211.435,516.093 211.435,516.093 C211.435,516.093 209.351,516.093 209.351,516.093 C209.236,515.864 209.143,515.456 209.072,514.868 zM209.039,510.453 C209.039,510.453 207.482,510.453 207.482,510.453 C205.047,510.453 203.829,511.166 203.829,512.591 C203.829,513.214 204.037,513.701 204.452,514.052 C204.868,514.403 205.401,514.578 206.053,514.578 C206.676,514.578 207.267,514.417 207.826,514.095 C208.384,513.773 208.789,513.354 209.039,512.838 C209.039,512.838 209.039,510.453 209.039,510.453 zM197.169,514.847 C196.374,515.821 195.268,516.308 193.850,516.308 C192.503,516.308 191.406,515.756 190.557,514.654 C189.709,513.551 189.285,512.111 189.285,510.335 C189.285,510.335 189.285,510.185 189.285,510.185 C189.285,508.402 189.707,506.968 190.552,505.883 C191.397,504.798 192.503,504.255 193.871,504.255 C195.232,504.255 196.310,504.721 197.105,505.652 C197.105,505.652 197.105,499.593 197.105,499.593 L199.092,499.593 L199.092,516.093 L197.266,516.093 C197.266,516.093 197.169,514.847 197.169,514.847 zM197.105,507.585 C196.510,506.489 195.597,505.942 194.366,505.942 C193.392,505.942 192.632,506.318 192.088,507.070 C191.544,507.822 191.272,508.935 191.272,510.410 C191.272,511.728 191.544,512.759 192.088,513.504 C192.632,514.249 193.384,514.621 194.344,514.621 C195.604,514.621 196.525,514.056 197.105,512.924 C197.105,512.924 197.105,507.585 197.105,507.585 z" fill="#FFFFFF" />
<path id="*args-(chart-opt" d="M394.509,423.393 C394.297,423.615 393.988,423.726 393.579,423.726 C393.171,423.726 392.865,423.615 392.661,423.393 C392.457,423.171 392.355,422.895 392.355,422.566 C392.355,422.222 392.457,421.936 392.661,421.706 C392.865,421.477 393.171,421.363 393.579,421.363 C393.988,421.363 394.297,421.477 394.509,421.706 C394.720,421.936 394.826,422.222 394.826,422.566 C394.826,422.895 394.720,423.171 394.509,423.393 zM393.569,430.848 C393.977,430.848 394.287,430.963 394.498,431.192 C394.709,431.421 394.815,431.707 394.815,432.051 C394.815,432.380 394.709,432.656 394.498,432.878 C394.287,433.100 393.977,433.211 393.569,433.211 C393.160,433.211 392.854,433.100 392.650,432.878 C392.446,432.656 392.344,432.380 392.344,432.051 C392.344,431.707 392.446,431.421 392.650,431.192 C392.854,430.963 393.160,430.848 393.569,430.848 zM386.796,435.499 C385.933,436.738 385.029,437.619 384.083,438.142 C384.083,438.142 383.664,436.928 383.664,436.928 C384.767,436.083 385.653,434.770 386.323,432.991 C386.993,431.211 387.335,429.237 387.349,427.067 C387.349,427.067 387.349,426.723 387.349,426.723 C387.349,425.219 387.191,423.821 386.876,422.528 C386.561,421.235 386.123,420.077 385.560,419.053 C384.998,418.029 384.366,417.230 383.664,416.657 C383.664,416.657 384.083,415.444 384.083,415.444 C385.029,415.966 385.929,416.840 386.785,418.065 C387.641,419.289 388.282,420.639 388.708,422.114 C389.134,423.590 389.347,425.169 389.347,426.852 C389.347,428.449 389.138,429.980 388.719,431.444 C388.300,432.909 387.659,434.260 386.796,435.499 zM377.944,426.379 C378.936,426.601 379.740,426.866 380.356,427.174 C380.972,427.482 381.428,427.853 381.725,428.286 C382.023,428.719 382.171,429.247 382.171,429.870 C382.171,430.909 381.756,431.741 380.925,432.368 C380.094,432.995 379.017,433.308 377.692,433.308 C376.761,433.308 375.937,433.143 375.221,432.814 C374.505,432.484 373.944,432.024 373.540,431.433 C373.135,430.843 372.933,430.203 372.933,429.516 C372.933,429.516 374.920,429.516 374.920,429.516 C374.956,430.182 375.223,430.710 375.721,431.100 C376.218,431.491 376.875,431.686 377.692,431.686 C378.444,431.686 379.047,431.534 379.502,431.229 C379.956,430.925 380.184,430.519 380.184,430.010 C380.184,429.473 379.981,429.056 379.577,428.759 C379.172,428.461 378.467,428.205 377.461,427.990 C376.455,427.776 375.656,427.518 375.065,427.217 C374.474,426.916 374.038,426.558 373.755,426.143 C373.472,425.728 373.330,425.233 373.330,424.660 C373.330,423.708 373.733,422.902 374.539,422.243 C375.345,421.585 376.374,421.255 377.627,421.255 C378.945,421.255 380.014,421.595 380.834,422.276 C381.654,422.956 382.064,423.826 382.064,424.886 C382.064,424.886 380.066,424.886 380.066,424.886 C380.066,424.342 379.835,423.873 379.373,423.479 C378.911,423.085 378.329,422.888 377.627,422.888 C376.904,422.888 376.338,423.046 375.930,423.361 C375.522,423.676 375.318,424.088 375.318,424.596 C375.318,425.076 375.507,425.438 375.887,425.681 C376.267,425.924 376.952,426.157 377.944,426.379 zM368.432,425.402 C368.425,424.564 368.233,423.944 367.857,423.543 C367.481,423.142 366.896,422.942 366.101,422.942 C365.456,422.942 364.891,423.114 364.404,423.457 C363.917,423.801 363.537,424.252 363.265,424.811 C363.265,424.811 363.265,433.093 363.265,433.093 L361.278,433.093 L361.278,421.470 L363.158,421.470 C363.158,421.470 363.222,422.931 363.222,422.931 C364.110,421.814 365.270,421.255 366.702,421.255 C369.159,421.255 370.398,422.641 370.419,425.412 C370.419,425.412 370.419,433.093 370.419,433.093 L368.432,433.093 C368.432,433.093 368.432,425.402 368.432,425.402 zM356.277,432.556 C355.472,433.057 354.546,433.308 353.500,433.308 C351.925,433.308 350.648,432.760 349.671,431.664 C348.693,430.569 348.204,429.118 348.204,427.314 C348.204,427.314 348.204,427.174 348.204,427.174 C348.204,426.035 348.428,425.011 348.876,424.102 C349.323,423.192 349.946,422.490 350.745,421.996 C351.543,421.502 352.455,421.255 353.479,421.255 C355.061,421.255 356.342,421.803 357.319,422.899 C358.297,423.994 358.785,425.452 358.785,427.271 C358.785,427.271 358.785,427.410 358.785,427.410 C358.785,428.542 358.569,429.557 358.136,430.456 C357.702,431.355 357.083,432.055 356.277,432.556 zM355.890,424.075 C355.285,423.284 354.481,422.888 353.479,422.888 C352.498,422.888 351.706,423.278 351.105,424.059 C350.503,424.839 350.202,425.957 350.202,427.410 C350.202,428.699 350.501,429.734 351.099,430.515 C351.697,431.296 352.498,431.686 353.500,431.686 C354.510,431.686 355.312,431.290 355.907,430.499 C356.501,429.708 356.798,428.599 356.798,427.174 C356.798,425.899 356.496,424.866 355.890,424.075 zM344.574,419.515 C344.187,419.515 343.895,419.407 343.698,419.193 C343.501,418.978 343.403,418.709 343.403,418.387 C343.403,418.065 343.501,417.793 343.698,417.571 C343.895,417.349 344.187,417.238 344.574,417.238 C344.960,417.238 345.254,417.349 345.454,417.571 C345.655,417.793 345.755,418.065 345.755,418.387 C345.755,418.709 345.655,418.978 345.454,419.193 C345.254,419.407 344.960,419.515 344.574,419.515 zM339.600,433.308 C338.712,433.308 338.042,433.039 337.591,432.502 C337.140,431.965 336.914,431.202 336.914,430.214 C336.914,430.214 336.914,423.006 336.914,423.006 L334.798,423.006 L334.798,421.470 L336.914,421.470 L336.914,418.655 L338.902,418.655 L338.902,421.470 L341.072,421.470 L341.072,423.006 L338.902,423.006 C338.902,423.006 338.902,430.223 338.902,430.223 C338.902,430.689 338.998,431.039 339.192,431.272 C339.385,431.505 339.714,431.621 340.180,431.621 C340.409,431.621 340.724,431.578 341.125,431.492 C341.125,431.492 341.125,433.094 341.125,433.094 C340.602,433.237 340.094,433.308 339.600,433.308 zM329.180,433.308 C327.769,433.308 326.659,432.860 325.850,431.965 C325.850,431.965 325.850,437.562 325.850,437.562 L323.863,437.562 L323.863,421.470 L325.678,421.470 C325.678,421.470 325.775,422.759 325.775,422.759 C326.584,421.756 327.708,421.255 329.148,421.255 C330.544,421.255 331.649,421.781 332.462,422.834 C333.274,423.887 333.681,425.352 333.681,427.228 C333.681,427.228 333.681,427.410 333.681,427.410 C333.681,429.179 333.276,430.605 332.467,431.686 C331.658,432.767 330.562,433.308 329.180,433.308 zM330.856,424.080 C330.297,423.321 329.531,422.942 328.557,422.942 C327.354,422.942 326.452,423.475 325.850,424.542 C325.850,424.542 325.850,430.096 325.850,430.096 C326.444,431.156 327.354,431.686 328.578,431.686 C329.531,431.686 330.288,431.308 330.850,430.552 C331.413,429.797 331.694,428.674 331.694,427.185 C331.694,425.874 331.414,424.839 330.856,424.080 zM318.862,432.556 C318.056,433.057 317.131,433.308 316.085,433.308 C314.510,433.308 313.233,432.760 312.256,431.664 C311.278,430.569 310.789,429.118 310.789,427.314 C310.789,427.314 310.789,427.174 310.789,427.174 C310.789,426.035 311.013,425.011 311.461,424.102 C311.908,423.192 312.531,422.490 313.330,421.996 C314.128,421.502 315.040,421.255 316.064,421.255 C317.646,421.255 318.927,421.803 319.904,422.899 C320.882,423.994 321.370,425.452 321.370,427.271 C321.370,427.271 321.370,427.410 321.370,427.410 C321.370,428.542 321.154,429.557 320.721,430.456 C320.287,431.355 319.668,432.055 318.862,432.556 zM318.475,424.075 C317.870,423.284 317.066,422.888 316.064,422.888 C315.083,422.888 314.291,423.278 313.690,424.059 C313.088,424.839 312.787,425.957 312.787,427.410 C312.787,428.699 313.086,429.734 313.684,430.515 C314.282,431.296 315.083,431.686 316.085,431.686 C317.095,431.686 317.897,431.290 318.492,430.499 C319.086,429.708 319.383,428.599 319.383,427.174 C319.383,425.899 319.081,424.866 318.475,424.075 zM302.077,433.308 C301.189,433.308 300.520,433.039 300.069,432.502 C299.618,431.965 299.392,431.202 299.392,430.214 C299.392,430.214 299.392,423.006 299.392,423.006 L297.276,423.006 L297.276,421.470 L299.392,421.470 L299.392,418.655 L301.379,418.655 L301.379,421.470 L303.549,421.470 L303.549,423.006 L301.379,423.006 C301.379,423.006 301.379,430.223 301.379,430.223 C301.379,430.689 301.476,431.039 301.669,431.272 C301.863,431.505 302.192,431.621 302.658,431.621 C302.887,431.621 303.202,431.578 303.603,431.492 C303.603,431.492 303.603,433.094 303.603,433.094 C303.080,433.237 302.572,433.308 302.077,433.308 zM295.342,423.178 C294.039,423.178 293.154,423.733 292.689,424.843 C292.689,424.843 292.689,433.093 292.689,433.093 L290.701,433.093 L290.701,421.470 L292.635,421.470 C292.635,421.470 292.667,422.813 292.667,422.813 C293.319,421.774 294.243,421.255 295.439,421.255 C295.826,421.255 296.119,421.305 296.320,421.405 C296.320,421.405 296.320,423.253 296.320,423.253 C296.019,423.203 295.693,423.178 295.342,423.178 zM285.631,431.868 C284.707,432.828 283.604,433.308 282.323,433.308 C281.177,433.308 280.237,432.984 279.503,432.336 C278.769,431.688 278.402,430.866 278.402,429.870 C278.402,428.660 278.862,427.720 279.782,427.051 C280.702,426.381 281.997,426.046 283.665,426.046 C283.665,426.046 285.599,426.046 285.599,426.046 C285.599,426.046 285.599,425.133 285.599,425.133 C285.599,424.438 285.391,423.885 284.976,423.473 C284.560,423.062 283.948,422.856 283.139,422.856 C282.430,422.856 281.836,423.035 281.356,423.393 C280.876,423.751 280.636,424.184 280.636,424.693 C280.636,424.693 278.638,424.693 278.638,424.693 C278.638,424.113 278.844,423.552 279.256,423.011 C279.667,422.471 280.226,422.043 280.931,421.728 C281.637,421.413 282.412,421.255 283.257,421.255 C284.596,421.255 285.645,421.590 286.405,422.260 C287.164,422.929 287.558,423.851 287.586,425.026 C287.586,425.026 287.586,430.375 287.586,430.375 C287.586,431.442 287.722,432.291 287.994,432.921 C287.994,432.921 287.994,433.093 287.994,433.093 C287.994,433.093 285.910,433.093 285.910,433.093 C285.796,432.864 285.703,432.456 285.631,431.868 zM285.599,427.453 C285.599,427.453 284.041,427.453 284.041,427.453 C281.606,427.453 280.389,428.166 280.389,429.591 C280.389,430.214 280.597,430.701 281.012,431.052 C281.427,431.403 281.961,431.578 282.613,431.578 C283.236,431.578 283.827,431.417 284.385,431.095 C284.944,430.773 285.348,430.354 285.599,429.838 C285.599,429.838 285.599,427.453 285.599,427.453 zM273.772,425.402 C273.765,424.564 273.573,423.944 273.197,423.543 C272.821,423.142 272.236,422.942 271.441,422.942 C270.796,422.942 270.230,423.114 269.743,423.457 C269.256,423.801 268.877,424.252 268.605,424.811 C268.605,424.811 268.605,433.093 268.605,433.093 L266.618,433.093 L266.618,416.593 L268.605,416.593 C268.605,416.593 268.605,422.877 268.605,422.877 C269.486,421.796 270.631,421.255 272.042,421.255 C274.499,421.255 275.738,422.641 275.759,425.412 C275.759,425.412 275.759,433.093 275.759,433.093 L273.772,433.093 C273.772,433.093 273.772,425.402 273.772,425.402 zM257.401,430.601 C257.952,431.324 258.740,431.686 259.764,431.686 C260.473,431.686 261.092,431.471 261.622,431.041 C262.152,430.612 262.446,430.074 262.503,429.430 C262.503,429.430 264.383,429.430 264.383,429.430 C264.347,430.096 264.118,430.730 263.696,431.331 C263.273,431.933 262.709,432.413 262.004,432.771 C261.298,433.129 260.552,433.308 259.764,433.308 C258.181,433.308 256.923,432.780 255.988,431.723 C255.054,430.667 254.586,429.222 254.586,427.389 C254.586,427.389 254.586,427.056 254.586,427.056 C254.586,425.924 254.794,424.918 255.209,424.037 C255.625,423.156 256.221,422.473 256.998,421.986 C257.775,421.499 258.693,421.255 259.753,421.255 C261.057,421.255 262.140,421.646 263.003,422.426 C263.866,423.207 264.326,424.220 264.383,425.466 C264.383,425.466 262.503,425.466 262.503,425.466 C262.446,424.714 262.161,424.096 261.649,423.613 C261.137,423.130 260.505,422.888 259.753,422.888 C258.743,422.888 257.961,423.251 257.406,423.978 C256.851,424.705 256.574,425.756 256.574,427.131 C256.574,427.131 256.574,427.507 256.574,427.507 C256.574,428.846 256.849,429.878 257.401,430.601 zM253.179,436.928 C253.179,436.928 252.771,438.142 252.771,438.142 C251.818,437.612 250.909,436.724 250.042,435.478 C248.352,433.043 247.507,430.132 247.507,426.744 C247.507,425.126 247.724,423.572 248.157,422.082 C248.590,420.593 249.237,419.239 250.096,418.022 C250.955,416.804 251.847,415.945 252.771,415.444 C252.771,415.444 253.179,416.754 253.179,416.754 C252.133,417.556 251.276,418.781 250.606,420.428 C249.937,422.075 249.570,423.919 249.505,425.960 C249.505,425.960 249.494,426.873 249.494,426.873 C249.494,429.638 249.999,432.037 251.009,434.071 C251.618,435.288 252.341,436.240 253.179,436.928 zM235.320,426.379 C236.312,426.601 237.116,426.866 237.732,427.174 C238.348,427.482 238.804,427.853 239.101,428.286 C239.398,428.719 239.547,429.247 239.547,429.870 C239.547,430.909 239.132,431.741 238.301,432.368 C237.470,432.995 236.393,433.308 235.068,433.308 C234.137,433.308 233.313,433.143 232.597,432.814 C231.881,432.484 231.320,432.024 230.916,431.433 C230.511,430.843 230.309,430.203 230.309,429.516 C230.309,429.516 232.296,429.516 232.296,429.516 C232.332,430.182 232.599,430.710 233.097,431.100 C233.594,431.491 234.251,431.686 235.068,431.686 C235.820,431.686 236.423,431.534 236.878,431.229 C237.332,430.925 237.560,430.519 237.560,430.010 C237.560,429.473 237.357,429.056 236.953,428.759 C236.548,428.461 235.843,428.205 234.837,427.990 C233.831,427.776 233.032,427.518 232.441,427.217 C231.850,426.916 231.414,426.558 231.131,426.143 C230.848,425.728 230.706,425.233 230.706,424.660 C230.706,423.708 231.109,422.902 231.915,422.243 C232.721,421.585 233.750,421.255 235.003,421.255 C236.321,421.255 237.390,421.595 238.210,422.276 C239.030,422.956 239.440,423.826 239.440,424.886 C239.440,424.886 237.442,424.886 237.442,424.886 C237.442,424.342 237.211,423.873 236.749,423.479 C236.287,423.085 235.705,422.888 235.003,422.888 C234.280,422.888 233.714,423.046 233.306,423.361 C232.898,423.676 232.694,424.088 232.694,424.596 C232.694,425.076 232.883,425.438 233.263,425.681 C233.643,425.924 234.328,426.157 235.320,426.379 zM222.865,437.669 C222.027,437.669 221.207,437.490 220.405,437.132 C219.602,436.774 218.990,436.283 218.568,435.660 C218.568,435.660 219.599,434.468 219.599,434.468 C220.451,435.521 221.493,436.047 222.725,436.047 C223.692,436.047 224.445,435.775 224.986,435.231 C225.527,434.686 225.797,433.920 225.797,432.932 C225.797,432.932 225.797,431.933 225.797,431.933 C225.002,432.850 223.917,433.308 222.542,433.308 C221.182,433.308 220.081,432.760 219.239,431.664 C218.398,430.569 217.977,429.075 217.977,427.185 C217.977,425.373 218.396,423.932 219.234,422.861 C220.072,421.791 221.182,421.255 222.564,421.255 C223.982,421.255 225.088,421.756 225.883,422.759 C225.883,422.759 225.980,421.470 225.980,421.470 L227.795,421.470 C227.795,421.470 227.795,432.814 227.795,432.814 C227.795,434.318 227.349,435.503 226.458,436.369 C225.566,437.236 224.368,437.669 222.865,437.669 zM225.797,424.607 C225.188,423.497 224.275,422.942 223.058,422.942 C222.091,422.942 221.336,423.318 220.791,424.070 C220.247,424.822 219.975,425.935 219.975,427.410 C219.975,428.721 220.243,429.751 220.781,430.499 C221.318,431.247 222.070,431.621 223.036,431.621 C224.290,431.621 225.210,431.052 225.797,429.913 C225.797,429.913 225.797,424.607 225.797,424.607 zM215.850,423.178 C214.546,423.178 213.662,423.733 213.197,424.843 C213.197,424.843 213.197,433.093 213.197,433.093 L211.209,433.093 L211.209,421.470 L213.143,421.470 C213.143,421.470 213.175,422.813 213.175,422.813 C213.827,421.774 214.751,421.255 215.947,421.255 C216.333,421.255 216.627,421.305 216.827,421.405 C216.827,421.405 216.827,423.253 216.827,423.253 C216.527,423.203 216.201,423.178 215.850,423.178 zM206.139,431.868 C205.215,432.828 204.112,433.308 202.830,433.308 C201.685,433.308 200.745,432.984 200.011,432.336 C199.276,431.688 198.910,430.866 198.910,429.870 C198.910,428.660 199.370,427.720 200.290,427.051 C201.210,426.381 202.504,426.046 204.173,426.046 C204.173,426.046 206.107,426.046 206.107,426.046 C206.107,426.046 206.107,425.133 206.107,425.133 C206.107,424.438 205.899,423.885 205.484,423.473 C205.068,423.062 204.456,422.856 203.647,422.856 C202.938,422.856 202.343,423.035 201.864,423.393 C201.384,423.751 201.144,424.184 201.144,424.693 C201.144,424.693 199.146,424.693 199.146,424.693 C199.146,424.113 199.352,423.552 199.764,423.011 C200.175,422.471 200.734,422.043 201.439,421.728 C202.145,421.413 202.920,421.255 203.765,421.255 C205.104,421.255 206.153,421.590 206.912,422.260 C207.671,422.929 208.065,423.851 208.094,425.026 C208.094,425.026 208.094,430.375 208.094,430.375 C208.094,431.442 208.230,432.291 208.502,432.921 C208.502,432.921 208.502,433.093 208.502,433.093 C208.502,433.093 206.418,433.093 206.418,433.093 C206.304,432.864 206.211,432.456 206.139,431.868 zM206.107,427.453 C206.107,427.453 204.549,427.453 204.549,427.453 C202.114,427.453 200.897,428.166 200.897,429.591 C200.897,430.214 201.104,430.701 201.520,431.052 C201.935,431.403 202.469,431.578 203.120,431.578 C203.743,431.578 204.334,431.417 204.893,431.095 C205.452,430.773 205.856,430.354 206.107,429.838 C206.107,429.838 206.107,427.453 206.107,427.453 zM196.256,425.536 L194.924,426.546 L192.926,423.452 L190.993,426.470 L189.650,425.493 L191.809,422.528 L188.565,421.562 L189.059,419.942 L192.303,421.144 L192.206,417.452 L193.850,417.452 L193.743,421.198 L196.933,420.017 L197.427,421.648 L194.129,422.625 L196.256,425.536 zM345.551,433.093 L343.564,433.093 L343.564,421.470 L345.551,421.470 L345.551,433.093 z" fill="#5F5E5E" />
<path id="Color-Fill-2" d="M399.000,152.000 C399.000,152.000 398.993,153.000 399.000,153.000 C399.007,153.000 245.007,152.993 245.000,153.000 C244.993,153.007 245.008,155.986 245.010,156.000 C245.012,156.014 399.010,156.000 399.000,156.000 C398.982,156.333 398.982,156.667 399.000,157.000 C391.000,165.000 391.000,165.000 391.000,165.000 L397.000,165.000 L407.000,155.000 L407.000,154.000 L397.000,144.000 L391.000,144.000 L399.000,152.000 z" fill="#C995CD" />
<path id="Color-Fill-3" d="M774.000,151.000 C774.000,151.000 773.993,152.000 774.000,152.000 C774.007,152.000 620.007,151.993 620.000,152.000 C619.993,152.007 620.008,154.986 620.010,155.000 C620.012,155.014 774.010,155.000 774.000,155.000 C773.982,155.333 773.982,155.667 774.000,156.000 C766.000,164.000 766.000,164.000 766.000,164.000 L772.000,164.000 L782.000,154.000 L782.000,153.000 L772.000,143.000 L766.000,143.000 L774.000,151.000 z" fill="#C995CD" />
<path id="_2nd_state-copy-" d="M387.840,201.444 C387.421,202.909 386.780,204.260 385.917,205.499 C385.054,206.738 384.150,207.619 383.204,208.142 C383.204,208.142 382.785,206.928 382.785,206.928 C383.888,206.083 384.774,204.770 385.444,202.991 C386.114,201.211 386.456,199.237 386.470,197.067 C386.470,197.067 386.470,196.723 386.470,196.723 C386.470,195.219 386.312,193.821 385.997,192.528 C385.682,191.235 385.244,190.077 384.681,189.053 C384.119,188.029 383.487,187.230 382.785,186.657 C382.785,186.657 383.204,185.444 383.204,185.444 C384.150,185.966 385.050,186.840 385.906,188.065 C386.762,189.289 387.403,190.639 387.829,192.114 C388.255,193.590 388.468,195.169 388.468,196.852 C388.468,198.449 388.259,199.980 387.840,201.444 zM379.359,203.211 C378.951,203.211 378.644,203.100 378.440,202.878 C378.236,202.656 378.134,202.380 378.134,202.051 C378.134,201.707 378.236,201.421 378.440,201.192 C378.644,200.963 378.951,200.848 379.359,200.848 C379.767,200.848 380.077,200.963 380.288,201.192 C380.499,201.421 380.605,201.707 380.605,202.051 C380.605,202.380 380.499,202.656 380.288,202.878 C380.077,203.100 379.767,203.211 379.359,203.211 zM373.569,203.211 C373.160,203.211 372.854,203.100 372.650,202.878 C372.446,202.656 372.344,202.380 372.344,202.051 C372.344,201.707 372.446,201.421 372.650,201.192 C372.854,200.963 373.160,200.848 373.569,200.848 C373.977,200.848 374.287,200.963 374.498,201.192 C374.709,201.421 374.815,201.707 374.815,202.051 C374.815,202.380 374.709,202.656 374.498,202.878 C374.287,203.100 373.977,203.211 373.569,203.211 zM367.779,203.211 C367.370,203.211 367.064,203.100 366.860,202.878 C366.656,202.656 366.554,202.380 366.554,202.051 C366.554,201.707 366.656,201.421 366.860,201.192 C367.064,200.963 367.370,200.848 367.779,200.848 C368.187,200.848 368.497,200.963 368.708,201.192 C368.919,201.421 369.025,201.707 369.025,202.051 C369.025,202.380 368.919,202.656 368.708,202.878 C368.497,203.100 368.187,203.211 367.779,203.211 zM362.128,206.208 C362.128,206.208 361.000,205.435 361.000,205.435 C361.673,204.497 362.024,203.530 362.053,202.534 C362.053,202.534 362.053,200.740 362.053,200.740 L363.997,200.740 C363.997,200.740 363.997,202.298 363.997,202.298 C363.997,203.021 363.820,203.745 363.466,204.468 C363.111,205.191 362.665,205.771 362.128,206.208 zM357.670,203.211 C357.262,203.211 356.956,203.100 356.752,202.878 C356.548,202.656 356.446,202.380 356.446,202.051 C356.446,201.707 356.548,201.421 356.752,201.192 C356.956,200.963 357.262,200.848 357.670,200.848 C358.078,200.848 358.388,200.963 358.599,201.192 C358.811,201.421 358.916,201.707 358.916,202.051 C358.916,202.380 358.811,202.656 358.599,202.878 C358.388,203.100 358.078,203.211 357.670,203.211 zM351.880,203.211 C351.472,203.211 351.166,203.100 350.962,202.878 C350.758,202.656 350.656,202.380 350.656,202.051 C350.656,201.707 350.758,201.421 350.962,201.192 C351.166,200.963 351.472,200.848 351.880,200.848 C352.288,200.848 352.598,200.963 352.809,201.192 C353.021,201.421 353.126,201.707 353.126,202.051 C353.126,202.380 353.021,202.656 352.809,202.878 C352.598,203.100 352.288,203.211 351.880,203.211 zM346.090,203.211 C345.682,203.211 345.376,203.100 345.172,202.878 C344.968,202.656 344.866,202.380 344.866,202.051 C344.866,201.707 344.968,201.421 345.172,201.192 C345.376,200.963 345.682,200.848 346.090,200.848 C346.498,200.848 346.808,200.963 347.019,201.192 C347.231,201.421 347.336,201.707 347.336,202.051 C347.336,202.380 347.231,202.656 347.019,202.878 C346.808,203.100 346.498,203.211 346.090,203.211 zM342.900,206.928 C342.900,206.928 342.492,208.142 342.492,208.142 C341.539,207.612 340.629,206.724 339.763,205.478 C338.073,203.043 337.228,200.132 337.228,196.744 C337.228,195.126 337.444,193.572 337.878,192.082 C338.311,190.593 338.957,189.239 339.817,188.022 C340.676,186.804 341.568,185.945 342.492,185.444 C342.492,185.444 342.900,186.754 342.900,186.754 C341.854,187.556 340.997,188.781 340.327,190.428 C339.657,192.075 339.290,193.919 339.226,195.960 C339.226,195.960 339.215,196.873 339.215,196.873 C339.215,199.638 339.720,202.037 340.730,204.071 C341.338,205.288 342.062,206.240 342.900,206.928 zM328.135,200.628 C328.775,201.333 329.590,201.686 330.578,201.686 C331.280,201.686 331.875,201.543 332.362,201.256 C332.849,200.970 333.275,200.590 333.640,200.117 C333.640,200.117 334.854,201.063 334.854,201.063 C333.880,202.560 332.419,203.308 330.471,203.308 C328.895,203.308 327.614,202.791 326.625,201.756 C325.637,200.721 325.143,199.337 325.143,197.604 C325.143,197.604 325.143,197.239 325.143,197.239 C325.143,196.086 325.363,195.056 325.804,194.150 C326.244,193.244 326.860,192.535 327.651,192.023 C328.442,191.511 329.300,191.255 330.224,191.255 C331.735,191.255 332.910,191.753 333.747,192.748 C334.585,193.744 335.004,195.169 335.004,197.024 C335.004,197.024 335.004,197.851 335.004,197.851 C335.004,197.851 327.130,197.851 327.130,197.851 C327.159,198.997 327.494,199.922 328.135,200.628 zM333.017,196.218 C333.017,196.218 333.017,196.068 333.017,196.068 C332.960,195.058 332.687,194.276 332.201,193.720 C331.713,193.166 331.055,192.888 330.224,192.888 C329.422,192.888 328.749,193.180 328.204,193.763 C327.660,194.347 327.324,195.165 327.195,196.218 C327.195,196.218 333.017,196.218 333.017,196.218 zM321.856,203.308 C320.968,203.308 320.298,203.039 319.847,202.502 C319.396,201.965 319.170,201.202 319.170,200.214 C319.170,200.214 319.170,193.006 319.170,193.006 L317.054,193.006 L317.054,191.470 L319.170,191.470 L319.170,188.655 L321.158,188.655 L321.158,191.470 L323.327,191.470 L323.327,193.006 L321.158,193.006 C321.158,193.006 321.158,200.223 321.158,200.223 C321.158,200.689 321.254,201.039 321.448,201.272 C321.641,201.505 321.970,201.621 322.436,201.621 C322.665,201.621 322.980,201.578 323.381,201.492 C323.381,201.492 323.381,203.094 323.381,203.094 C322.858,203.237 322.350,203.308 321.856,203.308 zM313.391,201.868 C312.467,202.828 311.364,203.308 310.082,203.308 C308.936,203.308 307.997,202.984 307.263,202.336 C306.528,201.688 306.161,200.866 306.161,199.870 C306.161,198.660 306.622,197.720 307.542,197.051 C308.462,196.381 309.756,196.046 311.425,196.046 C311.425,196.046 313.359,196.046 313.359,196.046 C313.359,196.046 313.359,195.133 313.359,195.133 C313.359,194.438 313.151,193.885 312.736,193.473 C312.320,193.062 311.708,192.856 310.899,192.856 C310.190,192.856 309.595,193.035 309.116,193.393 C308.636,193.751 308.396,194.184 308.396,194.693 C308.396,194.693 306.398,194.693 306.398,194.693 C306.398,194.113 306.604,193.552 307.015,193.011 C307.427,192.471 307.986,192.043 308.691,191.728 C309.397,191.413 310.172,191.255 311.017,191.255 C312.356,191.255 313.405,191.590 314.164,192.260 C314.923,192.929 315.317,193.851 315.346,195.026 C315.346,195.026 315.346,200.375 315.346,200.375 C315.346,201.442 315.482,202.291 315.754,202.921 C315.754,202.921 315.754,203.093 315.754,203.093 C315.754,203.093 313.670,203.093 313.670,203.093 C313.556,202.864 313.462,202.456 313.391,201.868 zM313.359,197.453 C313.359,197.453 311.801,197.453 311.801,197.453 C309.366,197.453 308.149,198.166 308.149,199.591 C308.149,200.214 308.356,200.701 308.772,201.052 C309.187,201.403 309.721,201.578 310.372,201.578 C310.995,201.578 311.586,201.417 312.145,201.095 C312.703,200.773 313.108,200.354 313.359,199.838 C313.359,199.838 313.359,197.453 313.359,197.453 zM301.510,195.423 C301.510,194.592 301.320,193.971 300.941,193.559 C300.561,193.148 299.924,192.942 299.029,192.942 C298.291,192.942 297.679,193.162 297.192,193.602 C296.705,194.043 296.422,194.635 296.343,195.380 C296.343,195.380 296.343,203.093 296.343,203.093 L294.345,203.093 C294.345,203.093 294.345,195.477 294.345,195.477 C294.345,193.787 293.518,192.942 291.864,192.942 C290.560,192.942 289.669,193.497 289.189,194.607 C289.189,194.607 289.189,203.093 289.189,203.093 L287.202,203.093 L287.202,191.470 L289.081,191.470 C289.081,191.470 289.135,192.759 289.135,192.759 C289.987,191.756 291.137,191.255 292.583,191.255 C294.209,191.255 295.315,191.878 295.903,193.124 C296.289,192.566 296.792,192.114 297.412,191.771 C298.031,191.427 298.764,191.255 299.609,191.255 C302.158,191.255 303.454,192.605 303.497,195.305 C303.497,195.305 303.497,203.093 303.497,203.093 L301.510,203.093 C301.510,203.093 301.510,195.423 301.510,195.423 zM283.055,189.515 C282.668,189.515 282.376,189.407 282.180,189.193 C281.982,188.978 281.884,188.709 281.884,188.387 C281.884,188.065 281.982,187.793 282.180,187.571 C282.376,187.349 282.668,187.238 283.055,187.238 C283.442,187.238 283.735,187.349 283.936,187.571 C284.136,187.793 284.237,188.065 284.237,188.387 C284.237,188.709 284.136,188.978 283.936,189.193 C283.735,189.407 283.442,189.515 283.055,189.515 zM276.889,195.402 C276.882,194.564 276.690,193.944 276.314,193.543 C275.938,193.142 275.353,192.942 274.558,192.942 C273.913,192.942 273.348,193.114 272.861,193.457 C272.374,193.801 271.994,194.252 271.722,194.811 C271.722,194.811 271.722,203.093 271.722,203.093 L269.735,203.093 L269.735,191.470 L271.615,191.470 C271.615,191.470 271.679,192.931 271.679,192.931 C272.567,191.814 273.727,191.255 275.160,191.255 C277.616,191.255 278.855,192.641 278.876,195.412 C278.876,195.412 278.876,203.093 278.876,203.093 L276.889,203.093 C276.889,203.093 276.889,195.402 276.889,195.402 zM264.664,201.868 C263.741,202.828 262.638,203.308 261.356,203.308 C260.210,203.308 259.270,202.984 258.536,202.336 C257.802,201.688 257.435,200.866 257.435,199.870 C257.435,198.660 257.895,197.720 258.815,197.051 C259.735,196.381 261.030,196.046 262.699,196.046 C262.699,196.046 264.632,196.046 264.632,196.046 C264.632,196.046 264.632,195.133 264.632,195.133 C264.632,194.438 264.424,193.885 264.009,193.473 C263.594,193.062 262.981,192.856 262.172,192.856 C261.463,192.856 260.869,193.035 260.389,193.393 C259.909,193.751 259.669,194.184 259.669,194.693 C259.669,194.693 257.671,194.693 257.671,194.693 C257.671,194.113 257.877,193.552 258.289,193.011 C258.701,192.471 259.259,192.043 259.965,191.728 C260.670,191.413 261.445,191.255 262.290,191.255 C263.629,191.255 264.679,191.590 265.438,192.260 C266.197,192.929 266.591,193.851 266.619,195.026 C266.619,195.026 266.619,200.375 266.619,200.375 C266.619,201.442 266.755,202.291 267.028,202.921 C267.028,202.921 267.028,203.093 267.028,203.093 C267.028,203.093 264.944,203.093 264.944,203.093 C264.829,202.864 264.736,202.456 264.664,201.868 zM264.632,197.453 C264.632,197.453 263.075,197.453 263.075,197.453 C260.640,197.453 259.422,198.166 259.422,199.591 C259.422,200.214 259.630,200.701 260.045,201.052 C260.461,201.403 260.994,201.578 261.646,201.578 C262.269,201.578 262.860,201.417 263.418,201.095 C263.977,200.773 264.381,200.354 264.632,199.838 C264.632,199.838 264.632,197.453 264.632,197.453 zM284.033,203.093 L282.045,203.093 L282.045,191.470 L284.033,191.470 L284.033,203.093 z" fill="#5F5E5E" />
<path id="_2nd_state-copy" d="M759.840,201.444 C759.421,202.909 758.780,204.260 757.917,205.499 C757.054,206.738 756.150,207.619 755.204,208.142 C755.204,208.142 754.785,206.928 754.785,206.928 C755.888,206.083 756.774,204.770 757.444,202.991 C758.114,201.211 758.456,199.237 758.470,197.067 C758.470,197.067 758.470,196.723 758.470,196.723 C758.470,195.219 758.312,193.821 757.997,192.528 C757.682,191.235 757.244,190.077 756.681,189.053 C756.119,188.029 755.487,187.230 754.785,186.657 C754.785,186.657 755.204,185.444 755.204,185.444 C756.150,185.966 757.050,186.840 757.906,188.065 C758.762,189.289 759.403,190.639 759.829,192.114 C760.255,193.590 760.468,195.169 760.468,196.852 C760.468,198.449 760.259,199.980 759.840,201.444 zM751.359,203.211 C750.951,203.211 750.644,203.100 750.440,202.878 C750.236,202.656 750.134,202.380 750.134,202.051 C750.134,201.707 750.236,201.421 750.440,201.192 C750.644,200.963 750.951,200.848 751.359,200.848 C751.767,200.848 752.077,200.963 752.288,201.192 C752.499,201.421 752.605,201.707 752.605,202.051 C752.605,202.380 752.499,202.656 752.288,202.878 C752.077,203.100 751.767,203.211 751.359,203.211 zM745.569,203.211 C745.160,203.211 744.854,203.100 744.650,202.878 C744.446,202.656 744.344,202.380 744.344,202.051 C744.344,201.707 744.446,201.421 744.650,201.192 C744.854,200.963 745.160,200.848 745.569,200.848 C745.977,200.848 746.287,200.963 746.498,201.192 C746.709,201.421 746.815,201.707 746.815,202.051 C746.815,202.380 746.709,202.656 746.498,202.878 C746.287,203.100 745.977,203.211 745.569,203.211 zM739.779,203.211 C739.370,203.211 739.064,203.100 738.860,202.878 C738.656,202.656 738.554,202.380 738.554,202.051 C738.554,201.707 738.656,201.421 738.860,201.192 C739.064,200.963 739.370,200.848 739.779,200.848 C740.187,200.848 740.497,200.963 740.708,201.192 C740.919,201.421 741.025,201.707 741.025,202.051 C741.025,202.380 740.919,202.656 740.708,202.878 C740.497,203.100 740.187,203.211 739.779,203.211 zM734.128,206.208 C734.128,206.208 733.000,205.435 733.000,205.435 C733.673,204.497 734.024,203.530 734.053,202.534 C734.053,202.534 734.053,200.740 734.053,200.740 L735.997,200.740 C735.997,200.740 735.997,202.298 735.997,202.298 C735.997,203.021 735.820,203.745 735.466,204.468 C735.111,205.191 734.665,205.771 734.128,206.208 zM729.670,203.211 C729.262,203.211 728.956,203.100 728.752,202.878 C728.548,202.656 728.446,202.380 728.446,202.051 C728.446,201.707 728.548,201.421 728.752,201.192 C728.956,200.963 729.262,200.848 729.670,200.848 C730.078,200.848 730.388,200.963 730.599,201.192 C730.811,201.421 730.916,201.707 730.916,202.051 C730.916,202.380 730.811,202.656 730.599,202.878 C730.388,203.100 730.078,203.211 729.670,203.211 zM723.880,203.211 C723.472,203.211 723.166,203.100 722.962,202.878 C722.758,202.656 722.656,202.380 722.656,202.051 C722.656,201.707 722.758,201.421 722.962,201.192 C723.166,200.963 723.472,200.848 723.880,200.848 C724.288,200.848 724.598,200.963 724.809,201.192 C725.021,201.421 725.126,201.707 725.126,202.051 C725.126,202.380 725.021,202.656 724.809,202.878 C724.598,203.100 724.288,203.211 723.880,203.211 zM718.090,203.211 C717.682,203.211 717.376,203.100 717.172,202.878 C716.968,202.656 716.866,202.380 716.866,202.051 C716.866,201.707 716.968,201.421 717.172,201.192 C717.376,200.963 717.682,200.848 718.090,200.848 C718.498,200.848 718.808,200.963 719.019,201.192 C719.231,201.421 719.336,201.707 719.336,202.051 C719.336,202.380 719.231,202.656 719.019,202.878 C718.808,203.100 718.498,203.211 718.090,203.211 zM714.900,206.928 C714.900,206.928 714.492,208.142 714.492,208.142 C713.539,207.612 712.629,206.724 711.763,205.478 C710.073,203.043 709.228,200.132 709.228,196.744 C709.228,195.126 709.444,193.572 709.878,192.082 C710.311,190.593 710.957,189.239 711.817,188.022 C712.676,186.804 713.568,185.945 714.492,185.444 C714.492,185.444 714.900,186.754 714.900,186.754 C713.854,187.556 712.997,188.781 712.327,190.428 C711.657,192.075 711.290,193.919 711.226,195.960 C711.226,195.960 711.215,196.873 711.215,196.873 C711.215,199.638 711.720,202.037 712.730,204.071 C713.338,205.288 714.062,206.240 714.900,206.928 zM700.135,200.628 C700.775,201.333 701.590,201.686 702.578,201.686 C703.280,201.686 703.875,201.543 704.362,201.256 C704.849,200.970 705.275,200.590 705.640,200.117 C705.640,200.117 706.854,201.063 706.854,201.063 C705.880,202.560 704.419,203.308 702.471,203.308 C700.895,203.308 699.614,202.791 698.625,201.756 C697.637,200.721 697.143,199.337 697.143,197.604 C697.143,197.604 697.143,197.239 697.143,197.239 C697.143,196.086 697.363,195.056 697.804,194.150 C698.244,193.244 698.860,192.535 699.651,192.023 C700.442,191.511 701.300,191.255 702.224,191.255 C703.735,191.255 704.910,191.753 705.747,192.748 C706.585,193.744 707.004,195.169 707.004,197.024 C707.004,197.024 707.004,197.851 707.004,197.851 C707.004,197.851 699.130,197.851 699.130,197.851 C699.159,198.997 699.494,199.922 700.135,200.628 zM705.017,196.218 C705.017,196.218 705.017,196.068 705.017,196.068 C704.960,195.058 704.687,194.276 704.201,193.720 C703.713,193.166 703.055,192.888 702.224,192.888 C701.422,192.888 700.749,193.180 700.204,193.763 C699.660,194.347 699.324,195.165 699.195,196.218 C699.195,196.218 705.017,196.218 705.017,196.218 zM693.856,203.308 C692.968,203.308 692.298,203.039 691.847,202.502 C691.396,201.965 691.170,201.202 691.170,200.214 C691.170,200.214 691.170,193.006 691.170,193.006 L689.054,193.006 L689.054,191.470 L691.170,191.470 L691.170,188.655 L693.158,188.655 L693.158,191.470 L695.327,191.470 L695.327,193.006 L693.158,193.006 C693.158,193.006 693.158,200.223 693.158,200.223 C693.158,200.689 693.254,201.039 693.448,201.272 C693.641,201.505 693.970,201.621 694.436,201.621 C694.665,201.621 694.980,201.578 695.381,201.492 C695.381,201.492 695.381,203.094 695.381,203.094 C694.858,203.237 694.350,203.308 693.856,203.308 zM685.391,201.868 C684.467,202.828 683.364,203.308 682.082,203.308 C680.936,203.308 679.997,202.984 679.263,202.336 C678.528,201.688 678.161,200.866 678.161,199.870 C678.161,198.660 678.622,197.720 679.542,197.051 C680.462,196.381 681.756,196.046 683.425,196.046 C683.425,196.046 685.359,196.046 685.359,196.046 C685.359,196.046 685.359,195.133 685.359,195.133 C685.359,194.438 685.151,193.885 684.736,193.473 C684.320,193.062 683.708,192.856 682.899,192.856 C682.190,192.856 681.595,193.035 681.116,193.393 C680.636,193.751 680.396,194.184 680.396,194.693 C680.396,194.693 678.398,194.693 678.398,194.693 C678.398,194.113 678.604,193.552 679.015,193.011 C679.427,192.471 679.986,192.043 680.691,191.728 C681.397,191.413 682.172,191.255 683.017,191.255 C684.356,191.255 685.405,191.590 686.164,192.260 C686.923,192.929 687.317,193.851 687.346,195.026 C687.346,195.026 687.346,200.375 687.346,200.375 C687.346,201.442 687.482,202.291 687.754,202.921 C687.754,202.921 687.754,203.093 687.754,203.093 C687.754,203.093 685.670,203.093 685.670,203.093 C685.556,202.864 685.462,202.456 685.391,201.868 zM685.359,197.453 C685.359,197.453 683.801,197.453 683.801,197.453 C681.366,197.453 680.149,198.166 680.149,199.591 C680.149,200.214 680.356,200.701 680.772,201.052 C681.187,201.403 681.721,201.578 682.372,201.578 C682.995,201.578 683.586,201.417 684.145,201.095 C684.703,200.773 685.108,200.354 685.359,199.838 C685.359,199.838 685.359,197.453 685.359,197.453 zM673.510,195.423 C673.510,194.592 673.320,193.971 672.941,193.559 C672.561,193.148 671.924,192.942 671.029,192.942 C670.291,192.942 669.679,193.162 669.192,193.602 C668.705,194.043 668.422,194.635 668.343,195.380 C668.343,195.380 668.343,203.093 668.343,203.093 L666.345,203.093 C666.345,203.093 666.345,195.477 666.345,195.477 C666.345,193.787 665.518,192.942 663.864,192.942 C662.560,192.942 661.669,193.497 661.189,194.607 C661.189,194.607 661.189,203.093 661.189,203.093 L659.202,203.093 L659.202,191.470 L661.081,191.470 C661.081,191.470 661.135,192.759 661.135,192.759 C661.987,191.756 663.137,191.255 664.583,191.255 C666.209,191.255 667.315,191.878 667.903,193.124 C668.289,192.566 668.792,192.114 669.412,191.771 C670.031,191.427 670.764,191.255 671.609,191.255 C674.158,191.255 675.454,192.605 675.497,195.305 C675.497,195.305 675.497,203.093 675.497,203.093 L673.510,203.093 C673.510,203.093 673.510,195.423 673.510,195.423 zM655.055,189.515 C654.668,189.515 654.376,189.407 654.180,189.193 C653.982,188.978 653.884,188.709 653.884,188.387 C653.884,188.065 653.982,187.793 654.180,187.571 C654.376,187.349 654.668,187.238 655.055,187.238 C655.442,187.238 655.735,187.349 655.936,187.571 C656.136,187.793 656.237,188.065 656.237,188.387 C656.237,188.709 656.136,188.978 655.936,189.193 C655.735,189.407 655.442,189.515 655.055,189.515 zM648.889,195.402 C648.882,194.564 648.690,193.944 648.314,193.543 C647.938,193.142 647.353,192.942 646.558,192.942 C645.913,192.942 645.348,193.114 644.861,193.457 C644.374,193.801 643.994,194.252 643.722,194.811 C643.722,194.811 643.722,203.093 643.722,203.093 L641.735,203.093 L641.735,191.470 L643.615,191.470 C643.615,191.470 643.679,192.931 643.679,192.931 C644.567,191.814 645.727,191.255 647.160,191.255 C649.616,191.255 650.855,192.641 650.876,195.412 C650.876,195.412 650.876,203.093 650.876,203.093 L648.889,203.093 C648.889,203.093 648.889,195.402 648.889,195.402 zM636.664,201.868 C635.741,202.828 634.638,203.308 633.356,203.308 C632.210,203.308 631.270,202.984 630.536,202.336 C629.802,201.688 629.435,200.866 629.435,199.870 C629.435,198.660 629.895,197.720 630.815,197.051 C631.735,196.381 633.030,196.046 634.699,196.046 C634.699,196.046 636.632,196.046 636.632,196.046 C636.632,196.046 636.632,195.133 636.632,195.133 C636.632,194.438 636.424,193.885 636.009,193.473 C635.594,193.062 634.981,192.856 634.172,192.856 C633.463,192.856 632.869,193.035 632.389,193.393 C631.909,193.751 631.669,194.184 631.669,194.693 C631.669,194.693 629.671,194.693 629.671,194.693 C629.671,194.113 629.877,193.552 630.289,193.011 C630.701,192.471 631.259,192.043 631.965,191.728 C632.670,191.413 633.445,191.255 634.290,191.255 C635.629,191.255 636.679,191.590 637.438,192.260 C638.197,192.929 638.591,193.851 638.619,195.026 C638.619,195.026 638.619,200.375 638.619,200.375 C638.619,201.442 638.755,202.291 639.028,202.921 C639.028,202.921 639.028,203.093 639.028,203.093 C639.028,203.093 636.944,203.093 636.944,203.093 C636.829,202.864 636.736,202.456 636.664,201.868 zM636.632,197.453 C636.632,197.453 635.075,197.453 635.075,197.453 C632.640,197.453 631.422,198.166 631.422,199.591 C631.422,200.214 631.630,200.701 632.045,201.052 C632.461,201.403 632.994,201.578 633.646,201.578 C634.269,201.578 634.860,201.417 635.418,201.095 C635.977,200.773 636.381,200.354 636.632,199.838 C636.632,199.838 636.632,197.453 636.632,197.453 zM656.033,203.093 L654.045,203.093 L654.045,191.470 L656.033,191.470 L656.033,203.093 z" fill="#5F5E5E" />
<path id="_2nd_state" d="M916.280,77.851 C916.308,78.997 916.643,79.922 917.284,80.628 C917.925,81.333 918.740,81.686 919.728,81.686 C920.430,81.686 921.024,81.543 921.511,81.256 C921.998,80.970 922.424,80.590 922.789,80.117 C922.789,80.117 924.003,81.063 924.003,81.063 C923.029,82.560 921.568,83.308 919.620,83.308 C918.045,83.308 916.763,82.791 915.775,81.756 C914.786,80.721 914.292,79.337 914.292,77.604 C914.292,77.604 914.292,77.239 914.292,77.239 C914.292,76.086 914.513,75.056 914.953,74.150 C915.393,73.244 916.009,72.535 916.801,72.023 C917.592,71.511 918.450,71.255 919.373,71.255 C920.884,71.255 922.059,71.753 922.897,72.748 C923.735,73.744 924.154,75.169 924.154,77.024 C924.154,77.024 924.154,77.851 924.154,77.851 C924.154,77.851 916.280,77.851 916.280,77.851 zM922.166,76.068 C922.109,75.058 921.837,74.276 921.350,73.720 C920.863,73.166 920.204,72.888 919.373,72.888 C918.571,72.888 917.898,73.180 917.354,73.763 C916.810,74.347 916.473,75.165 916.344,76.218 C916.344,76.218 922.166,76.218 922.166,76.218 C922.166,76.218 922.166,76.068 922.166,76.068 zM911.005,83.308 C910.117,83.308 909.448,83.039 908.996,82.502 C908.545,81.965 908.320,81.202 908.320,80.214 C908.320,80.214 908.320,73.006 908.320,73.006 L906.203,73.006 L906.203,71.470 L908.320,71.470 L908.320,68.656 L910.307,68.656 L910.307,71.470 L912.477,71.470 L912.477,73.006 L910.307,73.006 C910.307,73.006 910.307,80.223 910.307,80.223 C910.307,80.689 910.404,81.039 910.597,81.272 C910.790,81.505 911.120,81.621 911.585,81.621 C911.814,81.621 912.129,81.578 912.531,81.492 C912.531,81.492 912.531,83.094 912.531,83.094 C912.008,83.237 911.499,83.308 911.005,83.308 zM902.540,81.868 C901.617,82.828 900.514,83.308 899.232,83.308 C898.086,83.308 897.146,82.984 896.412,82.336 C895.678,81.688 895.311,80.866 895.311,79.870 C895.311,78.660 895.771,77.720 896.691,77.051 C897.611,76.381 898.906,76.046 900.575,76.046 C900.575,76.046 902.508,76.046 902.508,76.046 C902.508,76.046 902.508,75.133 902.508,75.133 C902.508,74.438 902.300,73.885 901.885,73.473 C901.470,73.062 900.857,72.856 900.048,72.856 C899.339,72.856 898.745,73.035 898.265,73.393 C897.785,73.751 897.545,74.184 897.545,74.693 C897.545,74.693 895.547,74.693 895.547,74.693 C895.547,74.113 895.753,73.552 896.165,73.011 C896.577,72.471 897.135,72.043 897.841,71.728 C898.546,71.413 899.321,71.255 900.166,71.255 C901.505,71.255 902.555,71.590 903.314,72.260 C904.073,72.929 904.467,73.851 904.495,75.026 C904.495,75.026 904.495,80.375 904.495,80.375 C904.495,81.442 904.631,82.291 904.904,82.921 C904.904,82.921 904.904,83.093 904.904,83.093 C904.904,83.093 902.820,83.093 902.820,83.093 C902.705,82.864 902.612,82.456 902.540,81.868 zM902.508,77.453 C902.508,77.453 900.951,77.453 900.951,77.453 C898.516,77.453 897.298,78.166 897.298,79.591 C897.298,80.214 897.506,80.701 897.921,81.052 C898.336,81.403 898.870,81.578 899.522,81.578 C900.145,81.578 900.736,81.417 901.294,81.095 C901.853,80.773 902.257,80.354 902.508,79.838 C902.508,79.838 902.508,77.453 902.508,77.453 zM891.852,83.308 C890.964,83.308 890.294,83.039 889.843,82.502 C889.392,81.965 889.166,81.202 889.166,80.214 C889.166,80.214 889.166,73.006 889.166,73.006 L887.050,73.006 L887.050,71.470 L889.166,71.470 L889.166,68.656 L891.154,68.656 L891.154,71.470 L893.324,71.470 L893.324,73.006 L891.154,73.006 C891.154,73.006 891.154,80.223 891.154,80.223 C891.154,80.689 891.250,81.039 891.444,81.272 C891.637,81.505 891.966,81.621 892.432,81.621 C892.661,81.621 892.976,81.578 893.377,81.492 C893.377,81.492 893.377,83.094 893.377,83.094 C892.854,83.237 892.346,83.308 891.852,83.308 zM881.641,76.379 C882.633,76.601 883.437,76.866 884.053,77.174 C884.669,77.482 885.125,77.853 885.423,78.286 C885.720,78.719 885.868,79.247 885.868,79.870 C885.868,80.909 885.453,81.741 884.622,82.368 C883.792,82.995 882.714,83.308 881.389,83.308 C880.458,83.308 879.634,83.143 878.918,82.814 C878.202,82.484 877.642,82.024 877.237,81.433 C876.832,80.843 876.630,80.203 876.630,79.516 C876.630,79.516 878.618,79.516 878.618,79.516 C878.653,80.182 878.920,80.710 879.418,81.100 C879.915,81.491 880.573,81.686 881.389,81.686 C882.141,81.686 882.744,81.534 883.199,81.229 C883.654,80.925 883.881,80.519 883.881,80.010 C883.881,79.473 883.679,79.056 883.274,78.759 C882.870,78.461 882.164,78.205 881.158,77.990 C880.152,77.776 879.353,77.518 878.763,77.217 C878.172,76.916 877.735,76.558 877.452,76.143 C877.169,75.728 877.028,75.233 877.028,74.660 C877.028,73.708 877.431,72.902 878.236,72.243 C879.042,71.585 880.071,71.255 881.325,71.255 C882.642,71.255 883.711,71.595 884.531,72.276 C885.351,72.956 885.761,73.826 885.761,74.886 C885.761,74.886 883.763,74.886 883.763,74.886 C883.763,74.342 883.532,73.873 883.070,73.479 C882.608,73.085 882.026,72.888 881.325,72.888 C880.601,72.888 880.035,73.046 879.627,73.361 C879.219,73.676 879.015,74.088 879.015,74.596 C879.015,75.076 879.205,75.438 879.584,75.681 C879.964,75.924 880.649,76.157 881.641,76.379 zM866.661,81.847 C865.867,82.821 864.760,83.308 863.342,83.308 C861.996,83.308 860.898,82.756 860.050,81.654 C859.201,80.551 858.777,79.111 858.777,77.335 C858.777,77.335 858.777,77.185 858.777,77.185 C858.777,75.402 859.199,73.968 860.044,72.883 C860.889,71.798 861.996,71.255 863.364,71.255 C864.724,71.255 865.802,71.721 866.597,72.652 C866.597,72.652 866.597,66.593 866.597,66.593 L868.584,66.593 L868.584,83.093 L866.758,83.093 C866.758,83.093 866.661,81.847 866.661,81.847 zM866.597,74.585 C866.002,73.489 865.089,72.942 863.858,72.942 C862.884,72.942 862.125,73.318 861.580,74.070 C861.036,74.822 860.764,75.935 860.764,77.410 C860.764,78.728 861.036,79.759 861.580,80.504 C862.125,81.249 862.877,81.621 863.836,81.621 C865.097,81.621 866.017,81.056 866.597,79.924 C866.597,79.924 866.597,74.585 866.597,74.585 zM854.276,75.402 C854.269,74.564 854.077,73.944 853.701,73.543 C853.325,73.142 852.740,72.942 851.945,72.942 C851.300,72.942 850.734,73.114 850.247,73.457 C849.760,73.801 849.381,74.252 849.109,74.811 C849.109,74.811 849.109,83.093 849.109,83.093 L847.121,83.093 L847.121,71.470 L849.001,71.470 C849.001,71.470 849.066,72.931 849.066,72.931 C849.954,71.814 851.114,71.255 852.546,71.255 C855.002,71.255 856.242,72.641 856.263,75.412 C856.263,75.412 856.263,83.093 856.263,83.093 L854.276,83.093 C854.276,83.093 854.276,75.402 854.276,75.402 zM834.564,81.664 C834.564,81.664 839.978,75.649 839.978,75.649 C840.780,74.739 841.333,74.000 841.638,73.430 C841.942,72.861 842.094,72.272 842.094,71.663 C842.094,70.847 841.847,70.177 841.353,69.655 C840.859,69.132 840.200,68.870 839.376,68.870 C838.388,68.870 837.620,69.151 837.072,69.714 C836.524,70.276 836.250,71.058 836.250,72.061 C836.250,72.061 834.263,72.061 834.263,72.061 C834.263,70.621 834.727,69.458 835.654,68.570 C836.581,67.682 837.822,67.238 839.376,67.238 C840.830,67.238 841.979,67.619 842.825,68.382 C843.669,69.144 844.092,70.159 844.092,71.427 C844.092,72.967 843.111,74.800 841.149,76.927 C841.149,76.927 836.959,81.471 836.959,81.471 L844.812,81.471 L844.812,83.093 L834.564,83.093 L834.564,81.664 z" fill="#4474CD" />
<path id="_1st_state" d="M534.263,77.851 C534.292,78.997 534.626,79.922 535.267,80.628 C535.908,81.333 536.723,81.686 537.711,81.686 C538.413,81.686 539.007,81.543 539.494,81.256 C539.981,80.970 540.408,80.590 540.773,80.117 C540.773,80.117 541.987,81.063 541.987,81.063 C541.013,82.560 539.552,83.308 537.604,83.308 C536.028,83.308 534.746,82.791 533.758,81.756 C532.770,80.721 532.276,79.337 532.276,77.604 C532.276,77.604 532.276,77.239 532.276,77.239 C532.276,76.086 532.496,75.056 532.936,74.150 C533.377,73.244 533.993,72.535 534.784,72.023 C535.575,71.511 536.433,71.255 537.357,71.255 C538.868,71.255 540.042,71.753 540.880,72.748 C541.718,73.744 542.137,75.169 542.137,77.024 C542.137,77.024 542.137,77.851 542.137,77.851 C542.137,77.851 534.263,77.851 534.263,77.851 zM540.150,76.068 C540.092,75.058 539.820,74.276 539.333,73.720 C538.846,73.166 538.187,72.888 537.357,72.888 C536.555,72.888 535.881,73.180 535.337,73.763 C534.793,74.347 534.456,75.165 534.327,76.218 C534.327,76.218 540.150,76.218 540.150,76.218 C540.150,76.218 540.150,76.068 540.150,76.068 zM526.980,82.502 C526.529,81.965 526.303,81.202 526.303,80.214 C526.303,80.214 526.303,73.006 526.303,73.006 L524.187,73.006 L524.187,71.470 L526.303,71.470 L526.303,68.656 L528.290,68.656 L528.290,71.470 L530.460,71.470 L530.460,73.006 L528.290,73.006 C528.290,73.006 528.290,80.223 528.290,80.223 C528.290,80.689 528.387,81.039 528.580,81.272 C528.774,81.505 529.103,81.621 529.569,81.621 C529.798,81.621 530.113,81.578 530.514,81.492 C530.514,81.492 530.514,83.094 530.514,83.094 C529.991,83.237 529.483,83.308 528.989,83.308 C528.101,83.308 527.431,83.039 526.980,82.502 zM520.524,81.868 C519.600,82.828 518.497,83.308 517.215,83.308 C516.069,83.308 515.129,82.984 514.395,82.336 C513.661,81.688 513.294,80.866 513.294,79.870 C513.294,78.660 513.754,77.720 514.675,77.051 C515.595,76.381 516.889,76.046 518.558,76.046 C518.558,76.046 520.492,76.046 520.492,76.046 C520.492,76.046 520.492,75.133 520.492,75.133 C520.492,74.438 520.284,73.885 519.868,73.473 C519.453,73.062 518.841,72.856 518.032,72.856 C517.323,72.856 516.728,73.035 516.248,73.393 C515.768,73.751 515.529,74.184 515.529,74.693 C515.529,74.693 513.531,74.693 513.531,74.693 C513.531,74.113 513.736,73.552 514.148,73.011 C514.560,72.471 515.119,72.043 515.824,71.728 C516.529,71.413 517.305,71.255 518.150,71.255 C519.489,71.255 520.538,71.590 521.297,72.260 C522.056,72.929 522.450,73.851 522.479,75.026 C522.479,75.026 522.479,80.375 522.479,80.375 C522.479,81.442 522.615,82.291 522.887,82.921 C522.887,82.921 522.887,83.093 522.887,83.093 C522.887,83.093 520.803,83.093 520.803,83.093 C520.688,82.864 520.595,82.456 520.524,81.868 zM520.492,77.453 C520.492,77.453 518.934,77.453 518.934,77.453 C516.499,77.453 515.282,78.166 515.282,79.591 C515.282,80.214 515.489,80.701 515.905,81.052 C516.320,81.403 516.853,81.578 517.505,81.578 C518.128,81.578 518.719,81.417 519.278,81.095 C519.836,80.773 520.241,80.354 520.492,79.838 C520.492,79.838 520.492,77.453 520.492,77.453 zM507.826,82.502 C507.375,81.965 507.150,81.202 507.150,80.214 C507.150,80.214 507.150,73.006 507.150,73.006 L505.034,73.006 L505.034,71.470 L507.150,71.470 L507.150,68.656 L509.137,68.656 L509.137,71.470 L511.307,71.470 L511.307,73.006 L509.137,73.006 C509.137,73.006 509.137,80.223 509.137,80.223 C509.137,80.689 509.234,81.039 509.427,81.272 C509.620,81.505 509.950,81.621 510.415,81.621 C510.644,81.621 510.960,81.578 511.361,81.492 C511.361,81.492 511.361,83.094 511.361,83.094 C510.838,83.237 510.329,83.308 509.835,83.308 C508.947,83.308 508.278,83.039 507.826,82.502 zM499.625,76.379 C500.617,76.601 501.420,76.866 502.036,77.174 C502.652,77.482 503.109,77.853 503.406,78.286 C503.703,78.719 503.852,79.247 503.852,79.870 C503.852,80.909 503.436,81.741 502.606,82.368 C501.775,82.995 500.697,83.308 499.372,83.308 C498.441,83.308 497.618,83.143 496.902,82.814 C496.185,82.484 495.625,82.024 495.221,81.433 C494.816,80.843 494.614,80.203 494.614,79.516 C494.614,79.516 496.601,79.516 496.601,79.516 C496.637,80.182 496.903,80.710 497.401,81.100 C497.899,81.491 498.556,81.686 499.372,81.686 C500.124,81.686 500.728,81.534 501.182,81.229 C501.637,80.925 501.865,80.519 501.865,80.010 C501.865,79.473 501.662,79.056 501.258,78.759 C500.853,78.461 500.147,78.205 499.141,77.990 C498.135,77.776 497.337,77.518 496.746,77.217 C496.155,76.916 495.718,76.558 495.435,76.143 C495.152,75.728 495.011,75.233 495.011,74.660 C495.011,73.708 495.414,72.902 496.220,72.243 C497.025,71.585 498.055,71.255 499.308,71.255 C500.626,71.255 501.694,71.595 502.514,72.276 C503.334,72.956 503.744,73.826 503.744,74.886 C503.744,74.886 501.746,74.886 501.746,74.886 C501.746,74.342 501.515,73.873 501.054,73.479 C500.592,73.085 500.010,72.888 499.308,72.888 C498.585,72.888 498.019,73.046 497.611,73.361 C497.202,73.676 496.998,74.088 496.998,74.596 C496.998,75.076 497.188,75.438 497.568,75.681 C497.947,75.924 498.633,76.157 499.625,76.379 zM483.850,82.502 C483.399,81.965 483.173,81.202 483.173,80.214 C483.173,80.214 483.173,73.006 483.173,73.006 L481.057,73.006 L481.057,71.470 L483.173,71.470 L483.173,68.656 L485.160,68.656 L485.160,71.470 L487.330,71.470 L487.330,73.006 L485.160,73.006 C485.160,73.006 485.160,80.223 485.160,80.223 C485.160,80.689 485.257,81.039 485.451,81.272 C485.644,81.505 485.973,81.621 486.439,81.621 C486.668,81.621 486.983,81.578 487.384,81.492 C487.384,81.492 487.384,83.094 487.384,83.094 C486.861,83.237 486.353,83.308 485.859,83.308 C484.971,83.308 484.301,83.039 483.850,82.502 zM475.648,76.379 C476.640,76.601 477.444,76.866 478.060,77.174 C478.676,77.482 479.132,77.853 479.430,78.286 C479.727,78.719 479.875,79.247 479.875,79.870 C479.875,80.909 479.460,81.741 478.629,82.368 C477.798,82.995 476.721,83.308 475.396,83.308 C474.465,83.308 473.641,83.143 472.925,82.814 C472.209,82.484 471.648,82.024 471.244,81.433 C470.839,80.843 470.637,80.203 470.637,79.516 C470.637,79.516 472.624,79.516 472.624,79.516 C472.660,80.182 472.927,80.710 473.425,81.100 C473.922,81.491 474.579,81.686 475.396,81.686 C476.148,81.686 476.751,81.534 477.206,81.229 C477.661,80.925 477.888,80.519 477.888,80.010 C477.888,79.473 477.686,79.056 477.281,78.759 C476.876,78.461 476.171,78.205 475.165,77.990 C474.159,77.776 473.360,77.518 472.769,77.217 C472.179,76.916 471.742,76.558 471.459,76.143 C471.176,75.728 471.034,75.233 471.034,74.660 C471.034,73.708 471.437,72.902 472.243,72.243 C473.049,71.585 474.078,71.255 475.331,71.255 C476.649,71.255 477.718,71.595 478.538,72.276 C479.358,72.956 479.768,73.826 479.768,74.886 C479.768,74.886 477.770,74.886 477.770,74.886 C477.770,74.342 477.539,73.873 477.077,73.479 C476.615,73.085 476.033,72.888 475.331,72.888 C474.608,72.888 474.042,73.046 473.634,73.361 C473.226,73.676 473.022,74.088 473.022,74.596 C473.022,75.076 473.211,75.438 473.591,75.681 C473.971,75.924 474.656,76.157 475.648,76.379 zM463.096,69.848 L459.089,71.320 L459.089,69.515 L464.783,67.377 L465.094,67.377 L465.094,83.093 L463.096,83.093 L463.096,69.848 z" fill="#4474CD" />
<g id="frame_" >
<path id="frame_-stroke" d="M231.000,99.000 L231.000,222.000 L45.000,222.000 L45.000,99.000 L231.000,99.000 zM605.500,99.000 L605.500,222.000 L419.500,222.000 L419.500,99.000 L605.500,99.000 zM980.000,99.000 L980.000,222.000 L794.000,222.000 L794.000,99.000 L980.000,99.000 z" fill="none" stroke="#707070" stroke-width="1" />
</g>
<path id="plots" d="M491.000,150.000 L491.000,192.000 L474.000,192.000 L474.000,150.000 L491.000,150.000 zM522.000,136.000 L522.000,192.000 L505.000,192.000 L505.000,136.000 L522.000,136.000 zM552.000,160.000 L552.000,192.000 L535.000,192.000 L535.000,160.000 L552.000,160.000 zM886.000,140.000 C886.000,146.075 881.075,151.000 875.000,151.000 C868.925,151.000 864.000,146.075 864.000,140.000 C864.000,133.925 868.925,129.000 875.000,129.000 C881.075,129.000 886.000,133.925 886.000,140.000 zM906.939,174.692 C906.911,184.822 898.683,193.015 888.553,193.001 C878.424,192.987 870.219,184.771 870.219,174.641 C870.241,164.480 878.495,156.261 888.656,156.281 C898.786,156.323 906.967,164.562 906.939,174.692 zM908.000,146.000 C908.000,149.866 904.866,153.000 901.000,153.000 C897.134,153.000 894.000,149.866 894.000,146.000 C894.000,142.134 897.134,139.000 901.000,139.000 C904.866,139.000 908.000,142.134 908.000,146.000 z" fill="#4474CD" />
</g>
</svg>

docs/assets/actual.gif METASEP

tools/modules/vizzu.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
import re

import ipyvizzu


REPO_PATH = Path(__file__).parent / ".." / ".."

VIZZU_BACKEND_URL = ""
VIZZU_STYLEREF_BACKEND_URL = ""

IPYVIZZU_VERSION = ""
VIZZU_VERSION = ""

IPYVIZZU_SITE_URL = "https://ipyvizzu.vizzuhq.com"
VIZZU_SITE_URL = "https://lib.vizzuhq.com"
VIZZU_CDN_URL = "https://cdn.jsdelivr.net/npm/vizzu"


class Vizzu:
    _ipyvizzu_version = ""
    _vizzu_version = ""

    @staticmethod
    def get_vizzu_backend_url() -> str:
        if VIZZU_BACKEND_URL:
            return VIZZU_BACKEND_URL
        version = Vizzu.get_vizzu_version()
        return f"{VIZZU_CDN_URL}@{version}/dist/vizzu.min.js"

    @staticmethod
    def get_vizzu_styleref_backend_url() -> str:
        if VIZZU_STYLEREF_BACKEND_URL:
            return VIZZU_STYLEREF_BACKEND_URL
        version = Vizzu.get_vizzu_version()
        return f"{VIZZU_CDN_URL}@{version}/dist/vizzu.min.js"

    @staticmethod
    def get_vizzu_version() -> str:
        if VIZZU_VERSION:
            return VIZZU_VERSION
        if not Vizzu._vizzu_version:
            cdn = ipyvizzu.Chart.VIZZU
            Vizzu._vizzu_version = re.search(r"vizzu@([\d.]+)/", cdn).group(1)  # type: ignore
        return Vizzu._vizzu_version

    @staticmethod
    def get_ipyvizzu_version() -> str:
        if IPYVIZZU_VERSION:
            return IPYVIZZU_VERSION
        if not Vizzu._ipyvizzu_version:
            version = ipyvizzu.__version__
            Vizzu._ipyvizzu_version = re.search(r"(\d+.\d+).\d+", version).group(1)  # type: ignore
        return Vizzu._ipyvizzu_version

    @staticmethod
    def set_version(content: str, restore: bool = False) -> str:
        vizzu_version = Vizzu.get_vizzu_version()
        ipyvizzu_version = Vizzu.get_ipyvizzu_version()
        if not restore:
            content = content.replace(
                f"{IPYVIZZU_SITE_URL}/latest/",
                f"{IPYVIZZU_SITE_URL}/{ipyvizzu_version}/",
            )
            content = content.replace(
                f"{VIZZU_SITE_URL}/latest/",
                f"{VIZZU_SITE_URL}/{vizzu_version}/",
            )
        else:
            content = content.replace(
                f"{IPYVIZZU_SITE_URL}/{ipyvizzu_version}/",
                f"{IPYVIZZU_SITE_URL}/latest/",
            )
            content = content.replace(
                f"{VIZZU_SITE_URL}/{vizzu_version}/",
                f"{VIZZU_SITE_URL}/latest/",
            )
        return content

tools/modules/node.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
from subprocess import PIPE, Popen
from typing import Union


class Node:
    @staticmethod
    def node(strict: bool, script: Union[str, Path], *params: str) -> str:
        return Node.run(strict, "node", script, *params)

    @staticmethod
    def npx(strict: bool, script: Union[str, Path], *params: str) -> str:
        return Node.run(strict, "npx", script, *params)

    @staticmethod
    def run(strict: bool, exe: str, script: Union[str, Path], *params: str) -> str:
        with Popen(
            [exe, script, *params],
            stdin=PIPE,
            stdout=PIPE,
            stderr=PIPE,
        ) as node:
            outs, errs = node.communicate()

        if errs:
            print(errs.decode())

        if node.returncode or (strict and errs):
            raise RuntimeError(f"failed to run {Path(script).stem}")

        return outs.decode()

tools/modules/chdir.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import os
from pathlib import Path
import sys
from typing import Union


if sys.version_info >= (3, 11):
    from contextlib import chdir  # pylint: disable=unused-import
else:
    # TODO: remove once support for Python 3.10 is dropped
    from contextlib import contextmanager

    @contextmanager
    def chdir(path: Union[str, Path]):
        old_wd = os.getcwd()
        os.chdir(path)
        try:
            yield
        finally:
            os.chdir(old_wd)

tools/docs/deploy.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
from subprocess import Popen
import sys


REPO_PATH = Path(__file__).parent / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"
MKDOCS_PATH = TOOLS_PATH / "docs"

sys.path.insert(0, str(TOOLS_PATH / "modules"))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
)


class Deploy:
    latest: bool = True

    @staticmethod
    def mike() -> None:
        version = Vizzu.get_ipyvizzu_version()

        params = [
            "mike",
            "deploy",
        ]
        if Deploy.latest:
            params.append("-u")
        params.append(version)
        if Deploy.latest:
            params.append("latest")
        params.append("-F")
        params.append("tools/docs/mkdocs.yml")

        with Popen(
            params,
        ) as process:
            process.communicate()

        if process.returncode:
            raise RuntimeError("failed to run mike")

    @staticmethod
    def set_config(restore: bool) -> None:
        with open(MKDOCS_PATH / "mkdocs.yml", "r", encoding="utf8") as fh_readme:
            content = fh_readme.read()

        if not restore:
            if not Deploy.latest:
                content = content.replace(
                    "- content.action.edit",
                    "# - content.action.edit",
                )
        else:
            if not Deploy.latest:
                content = content.replace(
                    "# - content.action.edit",
                    "- content.action.edit",
                )

        with open(MKDOCS_PATH / "mkdocs.yml", "w", encoding="utf8") as fh_readme:
            fh_readme.write(content)


def main() -> None:
    with chdir(REPO_PATH):
        Deploy.set_config(restore=False)
        Deploy.mike()
        Deploy.set_config(restore=True)


main()

tools/docs/config.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
from typing import Optional

import yaml


class MkdocsConfig:
    # pylint: disable=too-few-public-methods

    @staticmethod
    def _format_url(url: Optional[str]) -> Optional[str]:
        if url and url.endswith("/"):
            return url[:-1]
        return url

    @staticmethod
    def _format(config: dict) -> dict:
        if "site_url" in config:
            config["site_url"] = MkdocsConfig._format_url(config["site_url"])
        return config

    @staticmethod
    def load(config: Path) -> dict:
        with open(config, "rt", encoding="utf8") as f_yml:
            return MkdocsConfig._format(yaml.load(f_yml, Loader=yaml.FullLoader))

tools/ci/version.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import json
from pathlib import Path
import sys


REPO_PATH = Path(__file__).parent / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"

sys.path.insert(0, str(TOOLS_PATH / "modules"))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
)


class Version:
    @staticmethod
    def set_readme_version(restore: bool) -> None:
        with open("README.md", "r", encoding="utf8") as fh_readme:
            content = fh_readme.read()

        content = Vizzu.set_version(content, restore)

        with open("README.md", "w", encoding="utf8") as fh_readme:
            fh_readme.write(content)

    @staticmethod
    def set_src_version(restore: bool) -> None:
        for item in (REPO_PATH / "src").rglob("*.py"):
            with open(item, "r", encoding="utf8") as fh_item:
                content = fh_item.read()

            content = Vizzu.set_version(content, restore)

            with open(item, "w", encoding="utf8") as fh_item:
                fh_item.write(content)


def main() -> None:
    with chdir(REPO_PATH):
        restore = json.loads(sys.argv[1].lower())
        Version.set_readme_version(restore)
        Version.set_src_version(restore)


main()

tools/ci/std_check.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import sys
import subprocess


def main() -> None:
    with subprocess.Popen(
        sys.argv[1:], stdout=subprocess.PIPE, stderr=subprocess.PIPE
    ) as process:
        out, err = process.communicate()
        if out or err or process.returncode:
            if out:
                print(out.decode())
            if err:
                print(err.decode())
            raise RuntimeError(f"failed to run {sys.argv[1]}")


main()

tools/ci/markdown_format.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import mdformat


class Markdown:
    # pylint: disable=too-few-public-methods

    @staticmethod
    def format(content: str) -> str:
        return mdformat.text(  # type: ignore
            content,
            options={"wrap": 80, "end-of-line": "keep", "line-length": 70},
            extensions={
                "gfm",
                "tables",
                "footnote",
                "frontmatter",
                "configblack",
                "admonition",
            },
            codeformatters={
                "python",
                "bash",
                "sh",
                "json",
                "toml",
                "yaml",
                "javascript",
                "js",
                "css",
                "html",
                "xml",
            },
        )

tools/ci/get_tag.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from pathlib import Path
import re
import sys
import requests

REPO_PATH = Path(__file__).parent / ".." / ".."
TOOLS_PATH = REPO_PATH / "tools"

sys.path.insert(0, str(TOOLS_PATH / "modules"))

from chdir import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    chdir,
)
from vizzu import (  # pylint: disable=import-error, wrong-import-position, wrong-import-order
    Vizzu,
)

OWNER = "vizzuhq"
REPO = "vizzu-lib"


if __name__ == "__main__":
    with chdir(REPO_PATH):
        vizzu_version = Vizzu.get_vizzu_version()
        api_url = f"https://api.github.com/repos/{OWNER}/{REPO}/tags"

        response = requests.get(api_url, timeout=10)
        response.raise_for_status()

        tags = response.json()
        patch_versions = [
            int(
                re.search(
                    rf"^v{re.escape(vizzu_version)}\.(\d+)", tag["name"]  # type: ignore
                ).group(1)
            )
            for tag in tags
            if re.search(rf"^v{re.escape(vizzu_version)}\.(\d+)", tag["name"])
        ]
        latest_patch_version = max(patch_versions)
        checkout_ref = f"v{vizzu_version}.{latest_patch_version}"
        print(checkout_ref)

src/ipyvizzu/template.py METASEP
"""A module for storing the JavaScript templates."""

from enum import Enum


class ChartProperty(Enum):
    """An enum class for storing chart properties."""

    CONFIG = "config"
    """An enum key-value for storing config chart property."""

    STYLE = "style"
    """An enum key-value for storing style chart property."""


class DisplayTarget(Enum):
    """An enum class for storing chart display options."""

    BEGIN = "begin"
    """Display all animation steps after the constructor's cell."""

    END = "end"
    """Display all animation steps after the last running cell."""

    ACTUAL = "actual"
    """Display the actual animation step after the currently running cell."""

    MANUAL = "manual"
    """Display all animation steps after calling a show method."""


class DisplayTemplate:
    """A class for storing JavaScript snippet templates."""

    # pylint: disable=too-few-public-methods

    IPYVIZZUJS: str = "{ipyvizzujs}"
    """ipyvizzu JavaScript class."""

    INIT: str = (
        "window.ipyvizzu.createChart(element, "
        + "'{chart_id}', '{vizzu}', '{div_width}', '{div_height}');"
    )
    """Call createChart JavaScript method."""

    CHANGE_ANALYTICS_TO: str = (
        "if (window.IpyVizzu) window.IpyVizzu.changeAnalyticsTo({analytics});"
    )
    """Call changeAnalyticsTo JavaScript method."""

    ANIMATE: str = (
        "window.ipyvizzu.animate(element, "
        + "'{chart_id}', '{anim_id}', '{display_target}', {scroll}, "
        + "lib => {{ return {chart_target} }}, {chart_anim_opts});"
    )
    """Call animate JavaScript method."""

    FEATURE: str = (
        "window.ipyvizzu.feature(element, '{chart_id}', '{name}', {enabled});"
    )
    """Call feature JavaScript method."""

    STORE: str = "window.ipyvizzu.store(element, '{chart_id}', '{id}');"
    """Call store JavaScript method."""

    SET_EVENT: str = (
        "window.ipyvizzu.setEvent(element, "
        + "'{chart_id}', '{id}', '{event}', event => {{ {handler} }});"
    )
    """Call setEvent JavaScript method."""

    CLEAR_EVENT: str = (
        "window.ipyvizzu.clearEvent(element, '{chart_id}', '{id}', '{event}');"
    )
    """Call clearEvent JavaScript method."""

    LOG: str = "window.ipyvizzu.log(element, '{chart_id}', '{chart_property}');"
    """Call log JavaScript method."""

    CONTROL: str = "window.ipyvizzu.control(element, '{method}', {params});"
    """Call animation control JavaScript methods."""

    CLEAR_INHIBITSCROLL: str = (
        "if (window.IpyVizzu) { window.IpyVizzu.clearInhibitScroll(element); }"
    )
    """Call clearInhibitScroll JavaScript method if ipyvizzu JavaScript class exists."""

src/ipyvizzu/schema.py METASEP
"""A module for storing the data schema."""


NAMED_SCHEMA: dict = {
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "values": {"type": "array", "optional": True},
            "type": {"type": "string", "optional": True},
        },
        "required": ["name"],
    },
}
"""Store the schema of the `series`, `dimensions` and `measures` data types."""


RECORD_SCHEMA: dict = {
    "type": "array",
    "items": {"anyOf": [{"type": "array"}, {"type": "object"}]},
}
"""Store the schema of the `records` data type."""


DATA_SCHEMA: dict = {
    "type": "object",
    "oneOf": [
        {
            "properties": {
                "series": NAMED_SCHEMA,
                "records": RECORD_SCHEMA,
                "filter": {"optional": True},
            },
            "additionalProperties": False,
        },
        {
            "properties": {
                "dimensions": NAMED_SCHEMA,
                "measures": NAMED_SCHEMA,
                "filter": {"optional": True},
            },
            "additionalProperties": False,
            "required": ["dimensions", "measures"],
        },
    ],
}
"""Store the schema of the data animation."""

src/ipyvizzu/method.py METASEP
"""A module for working with template methods."""

import json
from typing import Optional

from ipyvizzu.animation import AbstractAnimation, PlainAnimation
from ipyvizzu.event import EventHandler
from ipyvizzu.template import ChartProperty


class Method:
    """A class for storing and dumping any kind of data."""

    # pylint: disable=too-few-public-methods

    _data: dict

    def dump(self) -> dict:
        """
        A method for returning the stored data.

        Returns:
            The stored data.
        """

        return self._data


class Animate(Method):
    """
    A class for dumping chart independent parameters to
    [DisplayTemplate.ANIMATE][ipyvizzu.template.DisplayTemplate] template.
    """

    # pylint: disable=too-few-public-methods

    def __init__(
        self,
        chart_target: AbstractAnimation,
        chart_anim_opts: Optional[dict] = None,
    ):
        """
        Animate constructor.

        It stores and dumps `chart_target` and `chart_anim_opts` parameters.

        Args:
            chart_target:
                AbstractAnimation inherited object such as
                [Data][ipyvizzu.animation.Data]
                [Config][ipyvizzu.animation.Config] or
                [Style][ipyvizzu.animation.Style].
            chart_anim_opts:
                Animation options' dictionary. If it is not set, it dumps `undefined`.
        """

        self._data = {
            "chart_target": chart_target.dump(),
            "chart_anim_opts": PlainAnimation(chart_anim_opts).dump()
            if chart_anim_opts
            else "undefined",
        }


class Feature(Method):
    """
    A class for dumping chart independent parameters to
    [DisplayTemplate.FEATURE][ipyvizzu.template.DisplayTemplate] template.
    """

    # pylint: disable=too-few-public-methods

    def __init__(self, name: str, enabled: bool):
        """
        Feature constructor.

        It stores and dumps `name` and `enabled` parameters.

        Args:
            name: The name of a chart feature.
            enabled: The new state of a chart feature.
        """

        self._data = {"name": name, "enabled": json.dumps(enabled)}


class Store(Method):
    """
    A class for dumping chart independent parameters to
    [DisplayTemplate.STORE][ipyvizzu.template.DisplayTemplate] template.
    """

    # pylint: disable=too-few-public-methods

    def __init__(self, snapshot_id: str):
        """
        Store constructor.

        It stores and dumps `snapshot_id` parameter.

        Args:
            snapshot_id: The id of snapshot object.
        """

        self._data = {"id": snapshot_id}


class EventOn(Method):
    """
    A class for dumping chart independent parameters to
    [DisplayTemplate.SET_EVENT][ipyvizzu.template.DisplayTemplate] template.
    """

    # pylint: disable=too-few-public-methods

    def __init__(self, event_handler: EventHandler):
        """
        EventOn constructor.

        It stores and dumps the `id`, the `event` and the `handler` of the event handler object.

        Args:
            event_handler: An event handler object.
        """

        self._data = {
            "id": event_handler.id,
            "event": event_handler.event,
            "handler": event_handler.handler,
        }


class EventOff(Method):
    """
    A class for dumping chart independent parameters to
    [DisplayTemplate.CLEAR_EVENT][ipyvizzu.template.DisplayTemplate] template.
    """

    # pylint: disable=too-few-public-methods

    def __init__(self, event_handler: EventHandler):
        """
        EventOff constructor.

        It stores and dumps the `id` and the `event` of the event handler object.

        Args:
            event_handler: An event handler object.
        """

        self._data = {"id": event_handler.id, "event": event_handler.event}


class Log(Method):
    """
    A class for dumping chart independent parameters to
    [DisplayTemplate.LOG][ipyvizzu.template.DisplayTemplate] template.
    """

    # pylint: disable=too-few-public-methods

    def __init__(self, chart_property: ChartProperty):
        """
        Log constructor.

        It stores and dumps the value of the chart property object.

        Args:
            chart_property:
                A chart property such as
                [CONFIG][ipyvizzu.template.ChartProperty] and
                [STYLE][ipyvizzu.template.ChartProperty].
        """

        self._data = {"chart_property": chart_property.value}

src/ipyvizzu/json.py METASEP
"""A module for working JavaScript code in json convertible objects."""

import json
from typing import Any, Optional
import uuid


class RawJavaScript:
    """A class for representing raw JavaScript code."""

    # pylint: disable=too-few-public-methods

    def __init__(self, raw: Optional[str]):
        """
        RawJavaScript constructor.

        It stores raw JavaScript code as a string.

        Args:
            raw: JavaScript code as `str`.
        """

        self._raw = raw

    @property
    def raw(self) -> Optional[str]:
        """
        A property for storing raw JavaScript code as a string.

        Returns:
            Raw JavaScript code as `str`.
        """

        return self._raw


class RawJavaScriptEncoder(json.JSONEncoder):
    """
    A class for representing a custom json encoder,
    it can encode objects that contain
    [RawJavaScript][ipyvizzu.json.RawJavaScript] values.
    """

    def __init__(self, *args, **kwargs):
        """
        RawJavaScriptEncoder constructor.

        It extends [JSONEncoder][json.JSONEncoder] with
        an instance variable (`_raw_replacements`).
        The `_raw_replacements` dictionary stores the `uuids` and
        JavaScript codes of the [RawJavaScript][ipyvizzu.json.RawJavaScript] objects.
        """

        json.JSONEncoder.__init__(self, *args, **kwargs)
        self._raw_replacements = {}

    def default(self, o: Any):
        """
        Overrides [JSONEncoder.default][json.JSONEncoder.default] method.
        It replaces [RawJavaScript][ipyvizzu.json.RawJavaScript] object with `uuid` and
        it stores raw JavaScript code with `uuid` key in the `_raw_replacements` dictionary.
        """

        if isinstance(o, RawJavaScript):
            key = uuid.uuid4().hex
            self._raw_replacements[key] = o.raw
            return key
        return json.JSONEncoder.default(self, o)

    def encode(self, o: Any):
        """
        Overrides [JSONEncoder.encode][json.JSONEncoder.encode] method.
        It replaces `uuids` with raw JavaScript code without apostrophes.
        """

        result = json.JSONEncoder.encode(self, o)
        for key, val in self._raw_replacements.items():
            result = result.replace(f'"{key}"', val)
        return result

src/ipyvizzu/event.py METASEP
"""A module for working with JavaScript events"""

import uuid


class EventHandler:
    """A class for representing an event handler."""

    def __init__(self, event: str, handler: str):
        """
        EventHandler constructor.

        It generates a uuid for the event handler,
        stores the event type and the body of the handler function.

        Args:
            event: The type of the event.
            handler: The body of the handler function.
        """

        self._id = uuid.uuid4().hex[:7]
        self._event = event
        self._handler = " ".join(handler.split())

    @property
    def id(self) -> str:  # pylint: disable=invalid-name
        """
        A property for storing an id.

        Returns:
            The uuid of the event handler.
        """

        return self._id

    @property
    def event(self) -> str:
        """
        A property for storing an event type.

        Returns:
            The type of the event.
        """

        return self._event

    @property
    def handler(self) -> str:
        """
        A property for storing an event handler function.

        Returns:
            The body of the handler function.
        """

        return self._handler

src/ipyvizzu/chart.py METASEP
"""A module for working with Vizzu charts."""

import pkgutil
import uuid
from typing import List, Optional, Union

from IPython.display import display_javascript  # type: ignore
from IPython import get_ipython  # type: ignore

from ipyvizzu.animation import AbstractAnimation, Snapshot, AnimationMerger
from ipyvizzu.animationcontrol import AnimationControl
from ipyvizzu.method import Animate, Feature, Store, EventOn, EventOff, Log
from ipyvizzu.template import ChartProperty, DisplayTarget, DisplayTemplate
from ipyvizzu.event import EventHandler
from ipyvizzu.__version__ import __version__


class Chart:
    """A class for representing a wrapper over Vizzu chart."""

    # pylint: disable=too-many-instance-attributes

    VIZZU: str = "https://cdn.jsdelivr.net/npm/vizzu@0.8/dist/vizzu.min.js"
    """A variable for storing the default url of vizzu package."""

    def __init__(
        self,
        vizzu: str = VIZZU,
        width: str = "800px",
        height: str = "480px",
        display: Union[DisplayTarget, str] = DisplayTarget.ACTUAL,
    ):
        """
        Chart constructor.

        Args:
            vizzu: The url of Vizzu JavaScript package.
            width: The width of the chart.
            height: The height of the chart.
            display: The display behaviour of the chart.
        """

        self._chart_id: str = uuid.uuid4().hex[:7]

        self._vizzu: str = vizzu
        self._width: str = width
        self._height: str = height

        self._display_target: DisplayTarget = DisplayTarget(display)
        self._calls: List[str] = []
        self._last_anim: Optional[str] = None
        self._showed: bool = False

        self._initialized: bool = False
        self._analytics: bool = True
        self._scroll_into_view: bool = False

    @staticmethod
    def _register_events() -> None:
        ipy = get_ipython()
        if ipy is not None:
            ipy.events.register("pre_run_cell", Chart._register_pre_run_cell)

    @staticmethod
    def _register_pre_run_cell() -> None:
        display_javascript(DisplayTemplate.CLEAR_INHIBITSCROLL, raw=True)

    @property
    def analytics(self) -> bool:
        """
        A property for enabling/disabling the usage statistics feature.

        The usage statistics feature allows aggregate usage data collection
        using Plausible's algorithm.
        Enabling this feature helps us follow the progress and overall trends of our library,
        allowing us to focus our resources effectively and better serve our users.

        We do not track, collect, or store any personal data or personally identifiable information.
        All data is isolated to a single day, a single site, and a single device only.

        Please note that even when this feature is enabled,
        publishing anything made with `ipyvizzu` remains GDPR compatible.

        Returns:
            The value of the property (default `True`).
        """

        return self._analytics

    @analytics.setter
    def analytics(self, analytics: Optional[bool]) -> None:
        self._analytics = bool(analytics)
        if self._initialized:
            self._display_analytics()

    @property
    def scroll_into_view(self) -> bool:
        """
        A property for turning on/off the scroll into view feature.

        Returns:
            The value of the property (default `False`).
        """

        return self._scroll_into_view

    @scroll_into_view.setter
    def scroll_into_view(self, scroll_into_view: Optional[bool]) -> None:
        self._scroll_into_view = bool(scroll_into_view)

    @property
    def control(self) -> AnimationControl:
        """
        A property for returning a control object of the last animation.

        Raises:
            AssertionError: If called before any animation plays.

        Returns:
            The control object of the last animation.
        """
        assert self._last_anim, "must be used after an animation."
        return AnimationControl(self._chart_id, self._last_anim, self._display)

    def initializing(self) -> None:
        """A method for initializing the chart."""

        if not self._initialized:
            self._initialized = True
            self._display_ipyvizzujs()
            self._display_analytics()
            if self._display_target != DisplayTarget.MANUAL:
                Chart._register_events()
            self._display_chart()

    def _display_ipyvizzujs(self) -> None:
        ipyvizzurawjs = pkgutil.get_data(__name__, "templates/ipyvizzu.js")
        ipyvizzujs = ipyvizzurawjs.decode("utf-8").replace(  # type: ignore
            '"__version__"', f'"{__version__}"'
        )
        self._display(DisplayTemplate.IPYVIZZUJS.format(ipyvizzujs=ipyvizzujs))

    def _display_analytics(self) -> None:
        self._display(
            DisplayTemplate.CHANGE_ANALYTICS_TO.format(
                analytics=str(self._analytics).lower()
            )
        )

    def _display_chart(self) -> None:
        self._display(
            DisplayTemplate.INIT.format(
                chart_id=self._chart_id,
                vizzu=self._vizzu,
                div_width=self._width,
                div_height=self._height,
            )
        )

    def animate(
        self,
        *animations: AbstractAnimation,
        **options: Optional[Union[str, int, float, dict]],
    ) -> None:
        """
        A method for changing the state of the chart.

        Args:
            *animations:
                List of AbstractAnimation inherited objects such as [Data][ipyvizzu.animation.Data],
                [Config][ipyvizzu.animation.Config] and [Style][ipyvizzu.animation.Style].
            **options: Dictionary of animation options for example `duration=1`.
                For information on all available animation options see the
                [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/interfaces/Anim.Options/#properties).

        Raises:
            ValueError: If `animations` is not set.

        Example:
            Reset the chart styles:

                chart.animate(Style(None))
        """  # pylint: disable=line-too-long

        if not animations:
            raise ValueError("No animation was set.")

        animation = AnimationMerger.merge_animations(animations)
        animate = Animate(animation, options)

        self._last_anim = uuid.uuid4().hex[:7]
        self._display(
            DisplayTemplate.ANIMATE.format(
                display_target=self._display_target.value,
                chart_id=self._chart_id,
                anim_id=self._last_anim,
                scroll=str(self._scroll_into_view).lower(),
                **animate.dump(),
            )
        )

    def feature(self, name: str, enabled: bool) -> None:
        """
        A method for turning on/off features of the chart.

        Args:
            name:
                The name of the chart feature.
                For information on all available features see the
                [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/modules/#feature).
            enabled: The new state of the chart feature.

        Example:
            Turn on `tooltip` of the chart:

                chart.feature("tooltip", True)
        """  # pylint: disable=line-too-long

        self._display(
            DisplayTemplate.FEATURE.format(
                chart_id=self._chart_id,
                **Feature(name, enabled).dump(),
            )
        )

    def store(self) -> Snapshot:
        """
        A method for saving and storing the actual state of the chart.

        Returns:
            A Snapshot object wich stores the actual state of the chart.

        Example:
            Save and restore the actual state of the chart:

                snapshot = chart.store()
                ...
                chart.animate(snapshot)
        """

        snapshot_id = uuid.uuid4().hex[:7]
        self._display(
            DisplayTemplate.STORE.format(
                chart_id=self._chart_id, **Store(snapshot_id).dump()
            )
        )
        return Snapshot(snapshot_id)

    def on(  # pylint: disable=invalid-name
        self, event: str, handler: str
    ) -> EventHandler:
        """
        A method for creating and turning on an event handler.

        Args:
            event:
                The type of the event.
                For information on all available events see the
                [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/modules/Event/#type).
            handler: The JavaScript method of the event.

        Returns:
            The turned on event handler object.

        Example:
            Turn on an event handler which prints an alert message
            when someone clicks on the chart:

                handler = chart.on("click", "alert(JSON.stringify(event.data));")
        """  # pylint: disable=line-too-long

        event_handler = EventHandler(event, handler)
        self._display(
            DisplayTemplate.SET_EVENT.format(
                chart_id=self._chart_id,
                **EventOn(event_handler).dump(),
            )
        )
        return event_handler

    def off(self, event_handler: EventHandler) -> None:
        """
        A method for turning off an event handler.

        Args:
            event_handler: A previously created event handler object.

        Example:
            Turn off a previously created event handler:

                chart.off(handler)
        """

        self._display(
            DisplayTemplate.CLEAR_EVENT.format(
                chart_id=self._chart_id,
                **EventOff(event_handler).dump(),
            )
        )

    def log(self, chart_property: ChartProperty) -> None:
        """
        A method for printing chart properties to the browser console.

        Args:
            chart_property:
                A chart property such as
                [CONFIG][ipyvizzu.template.ChartProperty] and
                [STYLE][ipyvizzu.template.ChartProperty].

        Example:
            Log the actual style of the chart to the browser console:

                chart.log(ChartProperty.STYLE)
        """

        self._display(
            DisplayTemplate.LOG.format(
                chart_id=self._chart_id, **Log(chart_property).dump()
            )
        )

    def _repr_html_(self) -> str:
        assert (
            self._display_target == DisplayTarget.MANUAL
        ), "chart._repr_html_() can be used with display=DisplayTarget.MANUAL only"
        assert not self._showed, "cannot be used after chart displayed."
        self._showed = True
        if not self._initialized:
            return ""
        html_id = uuid.uuid4().hex[:7]
        script = (
            self._calls[0]
            + "\n"
            + "\n".join(self._calls[1:]).replace(
                "element", f'document.getElementById("{html_id}")'
            )
        )
        return f'<div id="{html_id}"><script>{script}</script></div>'

    def show(self) -> None:
        """
        A method for displaying the assembled JavaScript code.

        Raises:
            AssertionError: If [display][ipyvizzu.Chart.__init__]
                is not [DisplayTarget.MANUAL][ipyvizzu.template.DisplayTarget].
            AssertionError: If chart already has been displayed.
        """

        assert (
            self._display_target == DisplayTarget.MANUAL
        ), "chart.show() can be used with display=DisplayTarget.MANUAL only"
        assert not self._showed, "cannot be used after chart displayed"
        display_javascript(
            "\n".join(self._calls),
            raw=True,
        )
        self._showed = True

    def _display(self, javascript: str) -> None:
        if not self._initialized:
            self.initializing()
        if self._display_target != DisplayTarget.MANUAL:
            display_javascript(
                javascript,
                raw=True,
            )
        else:
            assert not self._showed, "cannot be used after chart displayed"
            self._calls.append(javascript)

src/ipyvizzu/animationcontrol.py METASEP
"""A module for working with animation control."""

from typing import Union, Callable
import uuid

from ipyvizzu.template import DisplayTemplate
from ipyvizzu.animation import Animation


class AnimationControl:
    """
    A class for controlling animations.
    """

    def __init__(self, prev_id: str, last_id: str, display_method: Callable):
        """
        AnimationControl constructor.

        Args:
            prev_id: Id of the previous animation promise.
            last_id: Id of the animation to be controlled.
            display_method: Displaying function.
        """

        self._ids = ", ".join([f"'{prev_id}'", f"'{last_id}'"])
        self._display = display_method

    def cancel(self) -> None:
        """Cancels the animation, will reject the animation promise."""

        self._display(
            DisplayTemplate.CONTROL.format(
                method="cancel",
                params=self._ids,
            )
        )

    def pause(self) -> None:
        """Pauses the controlled animation."""

        self._display(
            DisplayTemplate.CONTROL.format(
                method="pause",
                params=self._ids,
            )
        )

    def play(self) -> None:
        """Plays/resumes playing of the controlled animation."""

        self._display(
            DisplayTemplate.CONTROL.format(
                method="play",
                params=self._ids,
            )
        )

    def reverse(self) -> None:
        """Changes the direction of the controlled animation."""

        self._display(
            DisplayTemplate.CONTROL.format(
                method="reverse",
                params=self._ids,
            )
        )

    def seek(self, value: Union[int, str]) -> None:
        """
        Seeks the animation to the position specified by time or progress percentage.

        Args:
            value: The position specified by time or progress percentage.
        """

        params = ", ".join([self._ids, f"'{value}'"])
        self._display(
            DisplayTemplate.CONTROL.format(
                method="seek",
                params=params,
            )
        )

    def stop(self) -> None:
        """Stops the current animation seeking it back to its start position."""

        self._display(
            DisplayTemplate.CONTROL.format(
                method="stop",
                params=self._ids,
            )
        )

    def store(self) -> Animation:
        """
        A method for saving and storing the actual state of the animation.

        Returns:
            An `Animation` object wich stores the actual state of the animation.
        """

        animation_id = uuid.uuid4().hex[:7]
        params = ", ".join([self._ids, f"'{animation_id}'"])
        self._display(
            DisplayTemplate.CONTROL.format(
                method="store",
                params=params,
            )
        )
        return Animation(animation_id)

src/ipyvizzu/animation.py METASEP
"""A module for working with chart animations."""

import abc
import json
from os import PathLike
from typing import List, Optional, Tuple, Union
import warnings

import jsonschema  # type: ignore

from ipyvizzu.data.converters.defaults import NAN_DIMENSION, NAN_MEASURE
from ipyvizzu.data.converters.df.defaults import MAX_ROWS
from ipyvizzu.data.converters.numpy.converter import NumpyArrayConverter
from ipyvizzu.data.converters.pandas.converter import PandasDataFrameConverter
from ipyvizzu.data.converters.spark.converter import SparkDataFrameConverter
from ipyvizzu.data.converters.numpy.type_alias import ColumnName, ColumnDtype
from ipyvizzu.data.type_alias import (
    DimensionValue,
    NestedMeasureValues,
    MeasureValue,
    Record,
    Series,
    SeriesValues,
)
from ipyvizzu.json import RawJavaScript, RawJavaScriptEncoder
from ipyvizzu.schema import DATA_SCHEMA


class AbstractAnimation:
    """
    An abstract class for representing animation objects
    that have `dump` and `build` methods.
    """

    def dump(self) -> str:
        """
        A method for converting the built dictionary into string.

        Returns:
            An str that has been json dumped with
                [RawJavaScriptEncoder][ipyvizzu.json.RawJavaScriptEncoder] from a dictionary.
        """

        return json.dumps(self.build(), cls=RawJavaScriptEncoder)

    @abc.abstractmethod
    def build(self) -> dict:
        """
        An abstract method for returning a dictionary with values
        that can be converted into json string.

        Returns:
            A dictionary that stored in the animation object.
        """


class PlainAnimation(dict, AbstractAnimation):
    """
    A class for representing plain animation.
    It can build any dictionary.
    """

    def build(self) -> dict:
        """
        A method for returning the plain animation dictionary.

        Returns:
            A dictionary that stored in the plain animation object.
        """

        return self


class Data(dict, AbstractAnimation):
    """
    A class for representing data animation.
    It can build data option of the chart.
    """

    @classmethod
    def filter(cls, filter_expr: Optional[str] = None) -> "Data":
        """
        A class method for creating a [Data][ipyvizzu.animation.Data]
        class instance with a data filter.

        Args:
            filter_expr: The JavaScript data filter expression.

        Returns:
            (Data): A data animation instance that contains a data filter.

        Example:
            Create a [Data][ipyvizzu.animation.Data] class with a data filter:

                filter = Data.filter("record['Genres'] == 'Pop'")
        """

        data = cls()
        data.set_filter(filter_expr)
        return data

    def set_filter(self, filter_expr: Optional[str] = None) -> None:
        """
        A method for adding a filter to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            filter_expr: The JavaScript data filter expression.

        Example:
            Add a data filter to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                data.set_filter("record['Genres'] == 'Pop'")
        """

        filter_expr_raw_js = (
            RawJavaScript(f"record => {{ return ({' '.join(filter_expr.split())}) }}")
            if filter_expr is not None
            else filter_expr
        )
        self.update({"filter": filter_expr_raw_js})

    @classmethod
    def from_json(cls, filename: Union[str, bytes, PathLike]) -> "Data":
        """
        A method for returning a [Data][ipyvizzu.animation.Data]
        class instance which has been created from a json file.

        Args:
            filename: The path of the data source json file.

        Returns:
            (Data): A data animation instance that has been created from a json file.
        """

        with open(filename, "r", encoding="utf8") as file_desc:
            return cls(json.load(file_desc))

    def add_record(self, record: Record) -> None:
        """
        A method for adding a record to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            record: A list that contains data values.

        Example:
            Adding a record to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                record = ["Pop", "Hard", 114]
                data.add_record(record)
        """

        self._add_value("records", record)

    def add_records(self, records: List[Record]) -> None:
        """
        A method for adding records to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            records: A list that contains data records.

        Example:
            Adding records to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                records = [
                    ["Pop", "Hard", 114],
                    ["Rock", "Hard", 96],
                    ["Pop", "Experimental", 127],
                    ["Rock", "Experimental", 83],
                ]
                data.add_records(records)
        """

        list(map(self.add_record, records))

    def add_series(
        self, name: str, values: Optional[SeriesValues] = None, **kwargs
    ) -> None:
        """
        A method for adding a series to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            name: The name of the series.
            values: The data values of the series.
            **kwargs (Optional):
                Arbitrary keyword arguments.

                For example infer type can be set with the `type` keywod argument.

        Example:
            Adding a series without values to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                data.add_series("Genres")

            Adding a series without values and with infer type to
            a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                data.add_series("Kinds", type="dimension")

            Adding a series with values to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                data.add_series(
                    "Popularity", [114, 96, 127, 83]
                )
        """

        self._add_named_value("series", name, values, **kwargs)

    def add_series_list(self, series: List[Series]) -> None:
        """
        A method for adding list of series to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            series: List of series.
        """

        if series:
            self.setdefault("series", []).extend(series)

    def add_dimension(
        self, name: str, values: Optional[List[DimensionValue]] = None, **kwargs
    ) -> None:
        """
        A method for adding a dimension to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            name: The name of the dimension.
            values: The data values of the dimension.
            **kwargs (Optional): Arbitrary keyword arguments.

        Example:
            Adding a dimension with values to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                data.add_dimension("Genres", ["Pop", "Rock"])
        """

        self._add_named_value("dimensions", name, values, **kwargs)

    def add_measure(
        self, name: str, values: Optional[NestedMeasureValues] = None, **kwargs
    ) -> None:
        """
        A method for adding a measure to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            name: The name of the measure.
            values: The data values of the measure.
            **kwargs (Optional): Arbitrary keyword arguments.

        Example:
            Adding a measure with values to a [Data][ipyvizzu.animation.Data] class instance:

                data = Data()
                data.add_measure(
                    "Popularity",
                    [
                        [114, 96],
                        [127, 83],
                    ],
                )
        """

        self._add_named_value("measures", name, values, **kwargs)

    def add_df(
        self,
        df: Optional[Union["pandas.DataFrame", "pandas.Series"]],  # type: ignore
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
        max_rows: int = MAX_ROWS,
        include_index: Optional[str] = None,
    ) -> None:
        """
        Add a `pandas` `DataFrame` or `Series` to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            df:
                The `pandas` `DataFrame` or `Series` to add.
            default_measure_value:
                The default measure value to fill empty values. Defaults to 0.
            default_dimension_value:
                The default dimension value to fill empty values. Defaults to an empty string.
            max_rows: The maximum number of rows to include in the converted series list.
                If the `df` contains more rows,
                a random sample of the given number of rows will be taken.
            include_index:
                Add the data frame's index as a column with the given name. Defaults to `None`.

        Example:
            Adding a data frame to a [Data][ipyvizzu.animation.Data] class instance:

                df = pd.DataFrame(
                    {
                        "Genres": ["Pop", "Rock", "Pop", "Rock"],
                        "Kinds": ["Hard", "Hard", "Experimental", "Experimental"],
                        "Popularity": [114, 96, 127, 83],
                    }
                )
                data = Data()
                data.add_df(df)
        """

        # pylint: disable=too-many-arguments

        if not isinstance(df, type(None)):
            converter = PandasDataFrameConverter(
                df,
                default_measure_value,
                default_dimension_value,
                max_rows,
                include_index,
            )
            series_list = converter.get_series_list()
            self.add_series_list(series_list)

    def add_data_frame(
        self,
        data_frame: Optional[Union["pandas.DataFrame", "pandas.Series"]],  # type: ignore
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
    ) -> None:
        """
        [Deprecated] This function is deprecated and will be removed in future versions.
        Use [add_df][ipyvizzu.animation.Data.add_df] function instead.

        Add a `pandas` `DataFrame` or `Series` to an existing
        [Data][ipyvizzu.animation.Data] class instance.



        Args:
            data_frame:
                The `pandas` `DataFrame` or `Series` to add.
            default_measure_value:
                The default measure value to fill empty values. Defaults to 0.
            default_dimension_value:
                The default dimension value to fill empty values. Defaults to an empty string.
        """

        # pylint: disable=line-too-long

        reference = "https://ipyvizzu.vizzuhq.com/0.16/reference/ipyvizzu/animation/#ipyvizzu.animation.Data.add_df"
        warnings.warn(
            f"'add_data_frame' is deprecated and will be removed in future versions. Use 'add_df' instead - see {reference}",
            DeprecationWarning,
            stacklevel=2,
        )
        self.add_df(data_frame, default_measure_value, default_dimension_value)

    def add_df_index(
        self,
        df: Optional[Union["pandas.DataFrame", "pandas.Series"]],  # type: ignore
        column_name: str = "Index",
    ) -> None:
        """
        Add the index of a `pandas` `DataFrame` as a series to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            df:
                The `pandas` `DataFrame` or `Series` from which to extract the index.
            column_name:
                Name for the index column to add as a series.

        Example:
            Adding a data frame's index to a
            [Data][ipyvizzu.animation.Data] class instance:

                df = pd.DataFrame(
                    {"Popularity": [114, 96]},
                    index=["x", "y"]
                )
                data = Data()
                data.add_df_index(df, "DataFrameIndex")
                data.add_df(df)
        """

        if not isinstance(df, type(None)):
            converter = PandasDataFrameConverter(df, include_index=column_name)
            series_list = converter.get_series_from_index()
            self.add_series_list(series_list)

    def add_data_frame_index(
        self,
        data_frame: Optional[Union["pandas.DataFrame", "pandas.Series"]],  # type: ignore
        name: str,
    ) -> None:
        """
        [Deprecated] This function is deprecated and will be removed in future versions.
        Use [add_df_index][ipyvizzu.animation.Data.add_df_index] function instead.

        Add the index of a `pandas` `DataFrame` as a series to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            data_frame:
                The `pandas` `DataFrame` or `Series` from which to extract the index.
            name:
                The name of the index series.
        """

        # pylint: disable=line-too-long

        reference = "https://ipyvizzu.vizzuhq.com/0.16/reference/ipyvizzu/animation/#ipyvizzu.animation.Data.add_df_index"
        warnings.warn(
            f"'add_data_frame_index' is deprecated and will be removed in future versions. Use 'add_df_index' instead - see {reference}",
            DeprecationWarning,
            stacklevel=2,
        )
        self.add_df_index(data_frame, name)

    def add_np_array(
        self,
        np_array: Optional["numpy.array"],  # type: ignore
        column_name: Optional[ColumnName] = None,
        column_dtype: Optional[ColumnDtype] = None,
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
    ) -> None:
        """
        Add a `numpy` `array` to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            np_array: The `numpy` `array` to add.
            column_name:
                The name of a column. By default, uses column indices. Can be set with an
                Index:Name pair or, for single-dimensional arrays, with just the Name.
            column_dtype:
                The dtype of a column. By default, uses the np_array's dtype. Can be set
                with an Index:DType pair or, for single-dimensional arrays, with just the DType.
            default_measure_value:
                Default value to use for missing measure values. Defaults to 0.
            default_dimension_value:
                Default value to use for missing dimension values. Defaults to an empty string.

        Example:
            Adding a data frame to a [Data][ipyvizzu.animation.Data] class instance:

                np_array = np.zeros((3, 4))
                data = Data()
                data.add_np_array(np_array)
        """

        # pylint: disable=too-many-arguments

        if not isinstance(np_array, type(None)):
            converter = NumpyArrayConverter(
                np_array,
                column_name,
                column_dtype,
                default_measure_value,
                default_dimension_value,
            )
            series_list = converter.get_series_list()
            self.add_series_list(series_list)

    def add_spark_df(
        self,
        df: Optional["pyspark.sql.DataFrame"],  # type: ignore
        default_measure_value: MeasureValue = NAN_MEASURE,
        default_dimension_value: DimensionValue = NAN_DIMENSION,
        max_rows: int = MAX_ROWS,
    ) -> None:
        """
        Add a `pyspark` `DataFrame` to an existing
        [Data][ipyvizzu.animation.Data] class instance.

        Args:
            df:
                The `pyspark` `DataFrame` to add.
            default_measure_value:
                The default measure value to fill empty values. Defaults to 0.
            default_dimension_value:
                The default dimension value to fill empty values. Defaults to an empty string.
            max_rows: The maximum number of rows to include in the converted series list.
                If the `df` contains more rows,
                a random sample of the given number of rows will be taken.
        """

        if not isinstance(df, type(None)):
            converter = SparkDataFrameConverter(
                df, default_measure_value, default_dimension_value, max_rows
            )
            series_list = converter.get_series_list()
            self.add_series_list(series_list)

    def _add_named_value(
        self,
        dest: str,
        name: str,
        values: Optional[
            Union[
                SeriesValues,
                NestedMeasureValues,
            ]
        ] = None,
        **kwargs,
    ) -> None:
        value = {"name": name, **kwargs}

        if values is not None:
            value["values"] = values

        self._add_value(dest, value)

    def _add_value(self, dest: str, value: Union[dict, list]) -> None:
        self.setdefault(dest, []).append(value)

    def build(self) -> dict:
        """
        A method for validating and returning the data animation dictionary.

        Returns:
            A dictionary that stored in the data animation object.
                It contains a `data` key whose value is the stored animation.
        """

        jsonschema.validate(self, DATA_SCHEMA)
        return {"data": self}


class ConfigAttr(type):
    """
    A metaclass class for the [Config][ipyvizzu.animation.Config] class.
    Returns a [Config][ipyvizzu.animation.Config] class with a chart preset
    if the `__getattr__` method called.

    For information on all available chart presets see the
    [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/modules/Presets/#interfaces).
    """

    @classmethod
    def __getattr__(mcs, name):
        config_attr = mcs("ConfigAttr", (object,), {"name": name})
        return config_attr._get_preset  # pylint: disable=no-member

    def _get_preset(cls, preset):
        config = Config(RawJavaScript(f"lib.presets.{cls.name}({preset})"))
        return config


class Config(AbstractAnimation, metaclass=ConfigAttr):
    """
    A class for representing config animation.
    It can build config option of the chart.
    """

    def __init__(self, data: Optional[Union[dict, RawJavaScript]]):
        """
        Config constructor.

        Args:
            data:
                A config animation dictionary.
                For information on all available config parameters see the
                [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/interfaces/Config.Chart/#properties).
        """  # pylint: disable=line-too-long

        self._data = data

    def build(self) -> dict:
        """
        A method for returning the config animation dictionary.

        Returns:
            A dictionary that stored in the config animation object.
                It contains a `config` key whose value is the stored animation.
        """

        return {"config": self._data}


class Style(AbstractAnimation):
    """
    A class for representing style animation.
    It can build style option of the chart.
    """

    def __init__(self, data: Optional[dict]):
        """
        Style constructor.

        Args:
            data:
                A style animation dictionary.
                For information on all available style parameters see the [Style][styling-properties]
                chapter or the
                [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/interfaces/Styles.Chart/#properties).
        """  # pylint: disable=line-too-long

        self._data = data

    def build(self) -> dict:
        """
        A method for returning the style animation dictionary.

        Returns:
            A dictionary that stored in the style animation object.
                It contains a `style` key whose value is the stored animation.
        """

        return {"style": self._data}


class Keyframe(AbstractAnimation):
    """
    A class for representing keyframe animation.
    It can build keyframe of the chart.
    """

    def __init__(
        self,
        *animations: AbstractAnimation,
        **options: Optional[Union[str, int, float, dict]],
    ):
        """
        Keyframe constructor.

        Args:
            *animations:
                List of AbstractAnimation inherited objects such as [Data][ipyvizzu.animation.Data],
                [Config][ipyvizzu.animation.Config] and [Style][ipyvizzu.animation.Style].
            **options: Dictionary of animation options for example `duration=1`.
                For information on all available animation options see the
                [Vizzu Code reference](https://lib.vizzuhq.com/latest/reference/interfaces/Anim.Options/#properties).

        Raises:
            ValueError: If `animations` is not set.
            ValueError: If initialized with a `Keyframe`.
        """  # pylint: disable=line-too-long

        if not animations:
            raise ValueError("No animation was set.")
        if [animation for animation in animations if isinstance(animation, Keyframe)]:
            raise ValueError("A Keyframe cannot contain a Keyframe.")

        self._keyframe = {}
        self._keyframe["target"] = AnimationMerger.merge_animations(animations).build()
        if options:
            self._keyframe["options"] = options

    def build(self) -> dict:
        """
        A method for returning the keyframe animation dictionary.

        Returns:
            A dictionary that stored in the keyframe animation object.
                It contains a `target` key whose value is the stored animation
                and an optional `options` key whose value is the stored animation options.
        """

        return self._keyframe


class Snapshot(AbstractAnimation):
    """
    A class for representing a stored chart state.
    It can build the snapshot id of the chart.
    """

    def __init__(self, snapshot_id: str):
        """
        Snapshot constructor.

        Args:
            snapshot_id: A snapshot id.
        """

        self._snapshot_id = snapshot_id

    def build(self) -> str:  # type: ignore
        """
        A method for returning the snapshot id str.

        Returns:
            An str snapshot id that stored in the snapshot animation object.
        """

        return self._snapshot_id


class Animation(Snapshot):
    """
    A class for representing a stored animation.
    It can build the snapshot id of the animation.
    """


class AnimationMerger(AbstractAnimation):
    """A class for merging different types of animations."""

    def __init__(self) -> None:
        """AnimationMerger constructor."""

        self._dict: dict = {}
        self._list: list = []

    @classmethod
    def merge_animations(
        cls, animations: Tuple[AbstractAnimation, ...]
    ) -> AbstractAnimation:
        """
        A class method for merging animations.

        Args:
            animations: List of `AbstractAnimation` inherited objects.

        Returns:
            An `AnimationMerger` class with the merged animations.
        """

        if len(animations) == 1 and not isinstance(animations[0], Keyframe):
            return animations[0]

        merger = cls()
        for animation in animations:
            merger.merge(animation)

        return merger

    def merge(self, animation: AbstractAnimation) -> None:
        """
        A method for merging an animation with the previously merged animations.

        Args:
            animation: An animation to be merged with with previously merged animations.

        Raises:
            ValueError: If the type of an animation is already merged.
            ValueError: If `Keyframe` is merged with different type of animation.
        """

        if isinstance(animation, Keyframe):
            if self._dict:
                raise ValueError("Keyframe cannot be merged with other animations.")
            data = animation.build()
            self._list.append(data)
        else:
            if self._list:
                raise ValueError("Keyframe cannot be merged with other animations.")
            data = self._validate(animation)
            self._dict.update(data)

    def _validate(self, animation: AbstractAnimation) -> dict:
        if isinstance(animation, Snapshot):
            raise ValueError("Snapshot cannot be merged with other animations.")
        data = animation.build()
        common_keys = set(data).intersection(self._dict)

        if common_keys:
            raise ValueError(f"{common_keys} is already merged.")

        return data

    def build(self) -> Union[dict, list]:  # type: ignore
        """
        A method for returning a merged list of `Keyframes`
        or a merged dictionary from different types of animations.

        Returns:
            A merged list of [Keyframes][ipyvizzu.animation.Keyframe] or
                a merged dictionary from
                [Data][ipyvizzu.animation.Data],
                [Config][ipyvizzu.animation.Config] and
                [Style][ipyvizzu.animation.Style] animations.
        """

        if self._dict:
            return self._dict
        return self._list

src/ipyvizzu/__version__.py METASEP
"""A module for storing version number."""

__version__ = "0.15.0"

src/ipyvizzu/__init__.py METASEP
"""
Build animated charts in `Jupyter Notebook`
and similar environments with a simple `Python` syntax.

`ipyvizzu` package consists of the following main modules:

* [Chart][ipyvizzu.chart]
* [Animation][ipyvizzu.animation]
* [Animation Control][ipyvizzu.animationcontrol]
* [Method][ipyvizzu.method]
* [Event][ipyvizzu.event]
* [Json][ipyvizzu.json]
* [Template][ipyvizzu.template]
* [Schema][ipyvizzu.schema]
* [Data][ipyvizzu.data]
* [Integrations][ipyvizzu.integrations]

`ipyvizzu` package imports the following objects in `__init__.py`:

* [Chart][ipyvizzu.chart.Chart]
* [Data][ipyvizzu.animation.Data]
* [Config][ipyvizzu.animation.Config]
* [Style][ipyvizzu.animation.Style]
* [Keyframe][ipyvizzu.animation.Keyframe]
* [Snapshot][ipyvizzu.animation.Snapshot]
* [Animation][ipyvizzu.animation.Animation]
* [AbstractAnimation][ipyvizzu.animation.AbstractAnimation]
* [PlainAnimation][ipyvizzu.animation.PlainAnimation]
* [AnimationMerger][ipyvizzu.animation.AnimationMerger]
* [AnimationControl][ipyvizzu.animationcontrol.AnimationControl]
* [InferType][ipyvizzu.data.infer_type.InferType]
* [NumpyArrayConverter][ipyvizzu.data.converters.numpy.converter.NumpyArrayConverter]
* [PandasDataFrameConverter][ipyvizzu.data.converters.pandas.converter.PandasDataFrameConverter]
* [Animate][ipyvizzu.method.Animate]
* [Feature][ipyvizzu.method.Feature]
* [Store][ipyvizzu.method.Store]
* [EventOn][ipyvizzu.method.EventOn]
* [EventOff][ipyvizzu.method.EventOff]
* [Log][ipyvizzu.method.Log]
* [Method][ipyvizzu.method.Method]
* [EventHandler][ipyvizzu.event.EventHandler]
* [RawJavaScript][ipyvizzu.json.RawJavaScript]
* [RawJavaScriptEncoder][ipyvizzu.json.RawJavaScriptEncoder]
* [ChartProperty][ipyvizzu.template.ChartProperty]
* [DisplayTarget][ipyvizzu.template.DisplayTarget]
* [DisplayTemplate][ipyvizzu.template.DisplayTemplate]
"""

from .chart import Chart
from .animation import (
    AbstractAnimation,
    PlainAnimation,
    Data,
    Config,
    Style,
    Keyframe,
    Snapshot,
    Animation,
    AnimationMerger,
)
from .animationcontrol import AnimationControl
from .data.converters.numpy.converter import NumpyArrayConverter
from .data.converters.pandas.converter import PandasDataFrameConverter
from .data.infer_type import InferType
from .method import Method, Animate, Feature, Store, EventOn, EventOff, Log
from .json import RawJavaScript, RawJavaScriptEncoder
from .template import ChartProperty, DisplayTarget, DisplayTemplate
from .event import EventHandler

from .__version__ import __version__

__all__ = [
    "Chart",
    "Data",
    "Config",
    "Style",
    "Keyframe",
    "Snapshot",
    "Animation",
    "AbstractAnimation",
    "PlainAnimation",
    "AnimationMerger",
    "Animate",
    "Feature",
    "Store",
    "EventOn",
    "EventOff",
    "Log",
    "AnimationControl",
    "NumpyArrayConverter",
    "PandasDataFrameConverter",
    "InferType",
    "Method",
    "EventHandler",
    "RawJavaScript",
    "RawJavaScriptEncoder",
    "ChartProperty",
    "DisplayTarget",
    "DisplayTemplate",
]

docs/installation.md METASEP
# Installation

`ipyvizzu` requires the `IPython` and `jsonschema` packages.

!!! info
    `ipyvizzu` requires and downloads the
    [Vizzu](https://github.com/vizzuhq/vizzu-lib) `JavaScript`/`C++`
    [library](https://www.jsdelivr.com/package/npm/vizzu) from `jsDelivr CDN`,
    but you can also use a different or self-hosted version of it. Check
    [Chart settings chapter](./tutorial/chart_settings.md) for more details.

## pypi

Run the following command to install `ipyvizzu` from
[pypi](https://pypi.org/project/ipyvizzu/)

```sh
pip install ipyvizzu
```

and this is how to upgrade it.

```sh
pip install -U ipyvizzu
```

!!! note
    `ipyvizzu` has some extra dependencies such as `pandas`, `pyspark`, `numpy`
    and `fugue`.

    For example if you would like to work with `pandas` `DataFrame` and
    `ipyvizzu`, you can install `pandas` as an extra:

    ```sh
    pip install ipyvizzu[pandas]
    ```

You can use `ipyvizzu` in `Jupyter/IPython`, `Streamlit` or `Panel` (see
[Environments chapter](environments/index.md) for more details).

### Jupyter/IPython

You can install `ipyvizzu` in your notebook without using the command line by
entering the following code into a cell.

```
!pip install ipyvizzu
```

## conda / mamba

Installing `ipyvizzu` from `conda-forge` can be achieved by adding `conda-forge`
to your channels with:

```sh
conda config --add channels conda-forge
conda config --set channel_priority strict
```

Once the `conda-forge` channel has been enabled, run the following command to
install `ipyvizzu` from [conda](https://anaconda.org/conda-forge/ipyvizzu/)

```sh
conda install ipyvizzu

# or with mamba:

mamba install ipyvizzu
```

and this is how to upgrade it.

```sh
conda update ipyvizzu

# or with mamba:

mamba update ipyvizzu
```

community/dark_theme.ipynb METASEP
{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "cf33de94",
   "metadata": {},
   "source": [
    "You can find our default Style and Config settings [here](https://docs.google.com/spreadsheets/d/1KSxFGnU-oaWVUvo-EZIvhKWyeCTwssimSaBYccxGw0c/edit#gid=2051760508) and the style reference table for vizzu-lib on this [link](https://lib.vizzuhq.com/latest/reference/modules/vizzu.Styles.html)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c877d5ba",
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "from ipyvizzu import Chart, Data, Config, Style\n",
    "\n",
    "# Create data object, read csv to data frame and add data frame to data object.\n",
    "data = Data()\n",
    "df = pd.read_csv(\n",
    "    \"https://raw.githubusercontent.com/vizzuhq/ipyvizzu/\"\n",
    "    + \"gh-pages/docs/data/chart_types_eu.csv\",\n",
    "    dtype={\"Year\": str, \"Timeseries\": str},\n",
    ")\n",
    "data.add_df(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6f5fb34c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Set the style of the charts in the story\n",
    "style = Style(\n",
    "    {\n",
    "        \"backgroundColor\": \"#121212\",\n",
    "        \"fontFamily\": \"Roboto, sans-serif\",\n",
    "        \"fontSize\": \"10px\",\n",
    "        \"legend\": {\n",
    "            \"label\": {\n",
    "                \"color\": \"#b9b9b9\",\n",
    "                \"fontSize\": \"1em\",\n",
    "                \"textAlign\": \"left\",\n",
    "            },\n",
    "            \"title\": {\n",
    "                \"color\": \"#b9b9b9\",\n",
    "                \"fontSize\": \"1.166667em\",\n",
    "                \"textAlign\": \"left\",\n",
    "            },\n",
    "        },\n",
    "        \"plot\": {\n",
    "            \"marker\": {\n",
    "                \"colorGradient\": \"#003f5c 0, \"\n",
    "                + \"#58508d 0.25, \"\n",
    "                + \"#bc5090 0.5, \"\n",
    "                + \"#ff6361 0.75, \"\n",
    "                + \"#ffa600 1\",\n",
    "                \"colorPalette\": \"#003f5c \"\n",
    "                + \"#2f4b7c \"\n",
    "                + \"#665191 \"\n",
    "                + \"#a05195 \"\n",
    "                + \"#d45087 \"\n",
    "                + \"#f95d6a \"\n",
    "                + \"#ff7c43 \"\n",
    "                + \"#ffa600 \"\n",
    "                + \"#bea500 \"\n",
    "                + \"#819d10 \"\n",
    "                + \"#488f31 \"\n",
    "                + \"#00795e\",\n",
    "            },\n",
    "            \"yAxis\": {\n",
    "                \"color\": \"#CCCCCCFF\",\n",
    "                \"label\": {\"color\": \"#999999FF\", \"fontSize\": \"1em\"},\n",
    "                \"title\": {\n",
    "                    \"color\": \"#999999FF\",\n",
    "                    \"fontSize\": \"1.166667em\",\n",
    "                },\n",
    "                \"interlacing\": {\"color\": \"#212121\"},\n",
    "            },\n",
    "            \"xAxis\": {\n",
    "                \"label\": {\"color\": \"#999999FF\", \"fontSize\": \"1em\"},\n",
    "                \"title\": {\n",
    "                    \"color\": \"#999999FF\",\n",
    "                    \"fontSize\": \"1.166667em\",\n",
    "                },\n",
    "                \"interlacing\": {\"color\": \"#212121\"},\n",
    "            },\n",
    "        },\n",
    "        \"title\": {\n",
    "            \"color\": \"#f7f7f7\",\n",
    "            \"fontSize\": \"2.166667em\",\n",
    "            \"textAlign\": \"center\",\n",
    "        },\n",
    "        \"tooltip\": {\n",
    "            \"arrowSize\": \"8\",\n",
    "            \"color\": \"#212121\",\n",
    "            \"backgroundColor\": \"#003f5cFF\",\n",
    "            \"borderColor\": \"#D8D8D8FF\",\n",
    "            \"fontSize\": \"12px\",\n",
    "        },\n",
    "        \"logo\": {\n",
    "            \"filter\": \"color(#D8D8D8FF)\",\n",
    "        },\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61a557dc",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart1 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart1.animate(data, style)\n",
    "\n",
    "chart1.animate(\n",
    "    data.filter(\n",
    "        \"\"\"record.Year == '01' || record.Year == '02' || record.Year == '03' || record.Year == '04'|| record.Year == '05'\"\"\"\n",
    "    ),\n",
    "    Config.stackedColumn(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Value 2 (+)\",\n",
    "            \"stackedBy\": \"Joy factors\",\n",
    "            \"title\": \"Stacked Column Chart\",\n",
    "        }\n",
    "    ),\n",
    ")\n",
    "\n",
    "chart1.feature(\"tooltip\", True)\n",
    "\n",
    "chart1.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "38a97ca7",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart2 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart2.animate(data, style)\n",
    "\n",
    "chart2.animate(\n",
    "    Config.splittedColumn(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Value 2 (+)\",\n",
    "            \"splittedBy\": \"Joy factors\",\n",
    "            \"title\": \"Splitted Column Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart2.feature(\"tooltip\", True)\n",
    "\n",
    "chart2.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "6208d735",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart3 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart3.animate(data, style)\n",
    "\n",
    "chart3.animate(\n",
    "    Config.stackedArea(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Value 2 (+)\",\n",
    "            \"stackedBy\": \"Joy factors\",\n",
    "            \"title\": \"Stacked Area Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart3.feature(\"tooltip\", True)\n",
    "\n",
    "chart3.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "dfa6a64b",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart4 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart4.animate(data, style)\n",
    "\n",
    "chart4.animate(\n",
    "    Config.stackedBubble(\n",
    "        {\n",
    "            \"size\": \"Value 2 (+)\",\n",
    "            \"color\": \"Joy factors\",\n",
    "            \"stackedBy\": \"Year\",\n",
    "            \"title\": \"Stacked Bubble Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart4.feature(\"tooltip\", True)\n",
    "\n",
    "chart4.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9a4ce11",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart5 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart5.animate(data, style)\n",
    "\n",
    "chart5.animate(\n",
    "    Config.pie(\n",
    "        {\n",
    "            \"angle\": \"Value 2 (+)\",\n",
    "            \"by\": \"Joy factors\",\n",
    "            \"title\": \"Pie Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart5.feature(\"tooltip\", True)\n",
    "\n",
    "chart5.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "263f2bc1",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart6 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart6.animate(data, style)\n",
    "\n",
    "chart6.animate(\n",
    "    Data.filter(\n",
    "        \"\"\"record.Year == '01' || record.Year == '02' || record.Year == '03' || record.Year == '04'|| record.Year == '05'\"\"\"\n",
    "    ),\n",
    "    Config.stackedTreemap(\n",
    "        {\n",
    "            \"size\": \"Value 2 (+)\",\n",
    "            \"color\": \"Year\",\n",
    "            \"title\": \"Stacked Treemap\",\n",
    "            \"dividedBy\": \"Country_code\",\n",
    "        }\n",
    "    ),\n",
    ")\n",
    "\n",
    "chart6.feature(\"tooltip\", True)\n",
    "\n",
    "chart6.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3c58eb16",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart7 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart7.animate(data, style)\n",
    "\n",
    "chart7.animate(\n",
    "    Data.filter(None),\n",
    "    Config.heatmap(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Country_code\",\n",
    "            \"lightness\": \"Value 3 (+)\",\n",
    "            \"title\": \"Heatmap (lightness)\",\n",
    "        }\n",
    "    ),\n",
    "    Style({\"plot\": {\"marker\": {\"rectangleSpacing\": 0}}}),\n",
    ")\n",
    "\n",
    "chart7.feature(\"tooltip\", True)\n",
    "\n",
    "chart7.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e928bc3b",
   "metadata": {},
   "outputs": [],
   "source": [
    "chart8 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart8.animate(data, style)\n",
    "\n",
    "chart8.animate(\n",
    "    Config(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Country_code\",\n",
    "            \"color\": \"Value 3 (+)\",\n",
    "            \"title\": \"Heatmap (color gradient)\",\n",
    "        }\n",
    "    ),\n",
    "    Style({\"plot\": {\"marker\": {\"rectangleSpacing\": 0}}}),\n",
    ")\n",
    "\n",
    "chart8.feature(\"tooltip\", True)\n",
    "\n",
    "chart8.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.13"
  },
  "title": "ipyvizzu - Example"
 },
 "nbformat": 4,
 "nbformat_minor": 5
}

community/color-blindness_theme.ipynb METASEP
{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This theme uses a palette based on [Bang Wong's colors](https://www.nature.com/articles/nmeth.1618) for color-blind accesibility. Also you can use [this page](https://davidmathlogic.com/colorblind) where you can try diferents colors and simulate how it looks like to viewers with some types of colorblind"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "cell_id": "4444ebffca564899a32e57a48e975dfe",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 7
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 47,
    "execution_start": 1669902493386,
    "source_hash": "61b4be05",
    "tags": []
   },
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "from ipyvizzu import Chart, Data, Config, Style\n",
    "\n",
    "# Create data object, read csv to data frame and add data frame to data object.\n",
    "data = Data()\n",
    "df = pd.read_csv(\n",
    "    \"https://raw.githubusercontent.com/vizzuhq/ipyvizzu/\"\n",
    "    + \"gh-pages/docs/data/chart_types_eu.csv\",\n",
    "    dtype={\"Year\": str, \"Timeseries\": str},\n",
    ")\n",
    "data.add_df(df)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "cell_id": "a04d6ac5a6874233a2534c61a923136e",
    "deepnote_app_coordinates": {
     "h": 52,
     "w": 12,
     "x": 0,
     "y": 73
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 2,
    "execution_start": 1669902497335,
    "source_hash": "d6175ef0",
    "tags": []
   },
   "outputs": [],
   "source": [
    "# Set the style of the charts in the story\n",
    "style = Style(\n",
    "    {\n",
    "        \"backgroundColor\": \"#FFFFFF\",\n",
    "        \"fontFamily\": \"Tahoma\",\n",
    "        \"fontSize\": \"10px\",\n",
    "        \"legend\": {\n",
    "            \"label\": {\n",
    "                \"color\": \"#3E3D3D\",\n",
    "                \"fontSize\": \"1.2em\",\n",
    "                \"textAlign\": \"left\",\n",
    "            },\n",
    "            \"title\": {\n",
    "                \"color\": \"#b9b9b9\",\n",
    "                \"fontSize\": \"1.166667em\",\n",
    "                \"textAlign\": \"left\",\n",
    "            },\n",
    "            \"marker\": {\"size\": \"1em\", \"type\": \"square\"},\n",
    "            \"paddingLeft\": \"0.5em\",\n",
    "        },\n",
    "        \"plot\": {\n",
    "            \"marker\": {\n",
    "                \"colorGradient\": \"#003f5c 0, \"\n",
    "                + \"#58508d 0.25, \"\n",
    "                + \"#bc5090 0.5, \"\n",
    "                + \"#ff6361 0.75, \"\n",
    "                + \"#ffa600 1\",\n",
    "                \"colorPalette\": \"#E69F00 \"\n",
    "                + \"#56B4E9 \"\n",
    "                + \"#009E73 \"\n",
    "                + \"#F0E442 \"\n",
    "                + \"#0072B2 \"\n",
    "                + \"#D55E00 \"\n",
    "                + \"#CC79A7 \"\n",
    "                + \"#DEEF14 \"\n",
    "                + \"#AFA037 \"\n",
    "                + \"#9D3B94 \"\n",
    "                + \"#BEB1FD \"\n",
    "                + \"#20756D \"\n",
    "                + \"#E9C66E \"\n",
    "                + \"#BB76D3 \"\n",
    "                + \"#AC1092 \",\n",
    "                \"label\": {\n",
    "                    \"fontSize\": \"1.2em\",\n",
    "                    \"filter\": \"color(#000000)\",\n",
    "                    \"fontWeight\": \"normal\",\n",
    "                },\n",
    "            },\n",
    "            \"yAxis\": {\n",
    "                \"color\": \"#CCCCCCFF\",\n",
    "                \"label\": {\"color\": \"#999999FF\", \"fontSize\": \"1em\"},\n",
    "                \"title\": {\n",
    "                    \"color\": \"#999999FF\",\n",
    "                    \"fontSize\": \"1.166667em\",\n",
    "                },\n",
    "            },\n",
    "            \"xAxis\": {\n",
    "                \"label\": {\"color\": \"#999999FF\", \"fontSize\": \"1em\"},\n",
    "                \"title\": {\n",
    "                    \"color\": \"#999999FF\",\n",
    "                    \"fontSize\": \"1.166667em\",\n",
    "                },\n",
    "            },\n",
    "        },\n",
    "        \"title\": {\n",
    "            \"color\": \"#000000\",\n",
    "            \"fontSize\": \"2.166667em\",\n",
    "            \"textAlign\": \"center\",\n",
    "        },\n",
    "        \"tooltip\": {\n",
    "            \"arrowSize\": \"8\",\n",
    "            \"color\": \"#191919\",\n",
    "            \"backgroundColor\": \"#FFFFFF\",\n",
    "            \"borderColor\": \"#D8D8D8FF\",\n",
    "            \"fontSize\": \"12px\",\n",
    "        },\n",
    "        \"logo\": {\n",
    "            \"filter\": \"color(#D8D8D8FF)\",\n",
    "        },\n",
    "    }\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cell_id": "5dc406a427384dddad05c65fa1d288fb",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 19
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 16,
    "execution_start": 1669902493482,
    "source_hash": "dd0554a7",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart.animate(data, style)\n",
    "\n",
    "chart.animate(\n",
    "    data.filter(\n",
    "        \"\"\"record.Year == '01' || record.Year == '02' || record.Year == '03' || record.Year == '04'|| record.Year == '05'\"\"\"\n",
    "    ),\n",
    "    Config.stackedColumn(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Value 2 (+)\",\n",
    "            \"stackedBy\": \"Joy factors\",\n",
    "            \"title\": \"Stacked Column Chart\",\n",
    "        }\n",
    "    ),\n",
    ")\n",
    "\n",
    "chart.feature(\"tooltip\", True)\n",
    "\n",
    "chart.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cell_id": "1a5c398e1e5e490785ec4e6225f398ab",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 25
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 14,
    "execution_start": 1669902493492,
    "source_hash": "97fbbb0d",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart2 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart2.animate(data, style)\n",
    "\n",
    "chart2.animate(\n",
    "    Config.splittedColumn(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Value 2 (+)\",\n",
    "            \"splittedBy\": \"Joy factors\",\n",
    "            \"title\": \"Splitted Column Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart2.feature(\"tooltip\", True)\n",
    "\n",
    "chart2.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "allow_embed": false,
    "cell_id": "5e14af3b537d4a49976cd5cbaba01408",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 31
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 19,
    "execution_start": 1669902493501,
    "source_hash": "26f754f7",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart3 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart3.animate(data, style)\n",
    "\n",
    "chart3.animate(\n",
    "    Config.stackedArea(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Value 2 (+)\",\n",
    "            \"stackedBy\": \"Joy factors\",\n",
    "            \"title\": \"Stacked Area Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart3.feature(\"tooltip\", True)\n",
    "\n",
    "chart3.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "allow_embed": false,
    "cell_id": "47b0a167b5fe403fade538f5cca5363e",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 43
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 15,
    "execution_start": 1669902493521,
    "source_hash": "62f63e5e",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart4 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart4.animate(data, style)\n",
    "\n",
    "chart4.animate(\n",
    "    Config.stackedBubble(\n",
    "        {\n",
    "            \"size\": \"Value 2 (+)\",\n",
    "            \"color\": \"Joy factors\",\n",
    "            \"stackedBy\": \"Year\",\n",
    "            \"title\": \"Stacked Bubble Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart4.feature(\"tooltip\", True)\n",
    "\n",
    "chart4.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "cell_id": "e63233c84b3d45fbb64cc3165b1db370",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 37
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 19,
    "execution_start": 1669902493525,
    "source_hash": "92fd46d3",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart5 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart5.animate(data, style)\n",
    "\n",
    "chart5.animate(\n",
    "    Config.pie(\n",
    "        {\n",
    "            \"angle\": \"Value 2 (+)\",\n",
    "            \"by\": \"Joy factors\",\n",
    "            \"title\": \"Pie Chart\",\n",
    "        }\n",
    "    )\n",
    ")\n",
    "\n",
    "chart5.feature(\"tooltip\", True)\n",
    "\n",
    "chart5.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "allow_embed": false,
    "cell_id": "3c85200b95234297a28170c912a5bffd",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 49
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 17,
    "execution_start": 1669902493548,
    "source_hash": "7518318e",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart6 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart6.animate(data, style)\n",
    "\n",
    "chart6.animate(\n",
    "    Data.filter(\n",
    "        \"\"\"record.Year == '01' || record.Year == '02' || record.Year == '03' || record.Year == '04'|| record.Year == '05'\"\"\"\n",
    "    ),\n",
    "    Config.stackedTreemap(\n",
    "        {\n",
    "            \"size\": \"Value 2 (+)\",\n",
    "            \"color\": \"Year\",\n",
    "            \"title\": \"Stacked Treemap\",\n",
    "            \"dividedBy\": \"Country_code\",\n",
    "        }\n",
    "    ),\n",
    ")\n",
    "\n",
    "chart6.feature(\"tooltip\", True)\n",
    "\n",
    "chart6.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "allow_embed": false,
    "cell_id": "86f925ac9fd440dd948eb81d858554a5",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 55
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 15,
    "execution_start": 1669902493567,
    "source_hash": "f63e9b8c",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart7 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart7.animate(data, style)\n",
    "\n",
    "chart7.animate(\n",
    "    Data.filter(None),\n",
    "    Config.heatmap(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Country_code\",\n",
    "            \"lightness\": \"Value 3 (+)\",\n",
    "            \"title\": \"Heatmap (lightness)\",\n",
    "        }\n",
    "    ),\n",
    "    Style({\"plot\": {\"marker\": {\"rectangleSpacing\": 0}}}),\n",
    ")\n",
    "\n",
    "chart7.feature(\"tooltip\", True)\n",
    "\n",
    "chart7.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "allow_embed": false,
    "cell_id": "156a94ec81f04ed19d4914d14a21c37e",
    "deepnote_app_coordinates": {
     "h": 5,
     "w": 12,
     "x": 0,
     "y": 67
    },
    "deepnote_cell_type": "code",
    "deepnote_to_be_reexecuted": false,
    "execution_millis": 21,
    "execution_start": 1669902493574,
    "scrolled": true,
    "source_hash": "a4eba9c5",
    "tags": []
   },
   "outputs": [],
   "source": [
    "chart8 = Chart(width=\"100%\", height=\"480px\", display=\"manual\")\n",
    "\n",
    "chart8.animate(data, style)\n",
    "\n",
    "chart8.animate(\n",
    "    Config(\n",
    "        {\n",
    "            \"x\": \"Year\",\n",
    "            \"y\": \"Country_code\",\n",
    "            \"color\": \"Value 3 (+)\",\n",
    "            \"title\": \"Heatmap (color gradient)\",\n",
    "        }\n",
    "    ),\n",
    "    Style({\"plot\": {\"marker\": {\"rectangleSpacing\": 0}}}),\n",
    ")\n",
    "\n",
    "chart8.feature(\"tooltip\", True)\n",
    "\n",
    "chart8.show()"
   ]
  }
 ],
 "metadata": {
  "deepnote": {},
  "deepnote_app_layout": "article",
  "deepnote_execution_queue": [],
  "deepnote_notebook_id": "c21c8baa37934b03bd33bf02b46c70e2",
  "deepnote_persisted_session": {
   "createdAt": "2022-12-01T14:17:43.579Z"
  },
  "kernelspec": {
   "display_name": "Python 3.10.2 64-bit",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.2"
  },
  "vscode": {
   "interpreter": {
    "hash": "1cf280054921a5f132c2690a7d7165a9692ef17a7daf272aae0ce446c51428bc"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}

pyproject.toml METASEP
[project]
name = "ipyvizzu"
dynamic = ["version"]
description = "Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax."
authors = [
    {name = "Vizzu Inc.", email = "hello@vizzuhq.com"},
]
readme = "README.md"
requires-python = ">=3.6"
dependencies = [
    "IPython",
    "jsonschema",
]
license = {text = "Apache-2.0"}
classifiers = [
    "Environment :: Console",
    "License :: OSI Approved :: Apache Software License",
    "Operating System :: OS Independent",
    "Programming Language :: Python :: 3",
]
keywords = [
    "python",
    "chart",
    "charts",
    "dataviz",
    "jupyter",
    "animation",
    "ipython",
    "graphs",
    "storytelling",
    "jupyter-notebook",
    "data-visualization",
    "graphing",
    "plotting",
    "charting",
    "vizzu"
]

[project.optional-dependencies]
pandas = [
    "pandas",
]
pyspark = [
    "pyspark",
]
numpy = [
    "numpy",
]
fugue = [
    "fugue >= 0.8.1 ; python_version >= '3.7'",
]

[project.urls]
Homepage = "https://ipyvizzu.vizzuhq.com"
Documentation = "https://ipyvizzu.vizzuhq.com"
Source = "https://github.com/vizzuhq/ipyvizzu"
Tracker = "https://github.com/vizzuhq/ipyvizzu/issues"

[tool.pdm.scripts]
init_py = "pdm install"
init_js = "npm install"

init_src_py = {composite = ["pkg_install", "init_py"]}
init_src = {composite = ["init"]}
init_docs = {composite = ["init"]}
init_tools = {composite = ["init"]}

init = {composite = ["pkg_install", "init_py", "init_js"]}


lock_py = "pdm lock --no-default -d"
lock_js = "npm update"

lock = {composite = ["lock_py", "lock_js"]}


fix_format_black = "black"
format_black = "black --diff --check"
fix_format_mdformat = "python ./tools/ci/std_check.py mdformat --wrap 80 --end-of-line keep --line-length 70"
format_mdformat = "python ./tools/ci/std_check.py mdformat --wrap 80 --end-of-line keep --line-length 70 --check"
fix_format_prettier = "npx prettier -w"
format_prettier = "npx prettier -c" 

fix_format_src_py = {composite = ["fix_format_black src tests"]}
format_src_py = {composite = ["format_black src tests"]}
fix_format_src = {composite = ["fix_format_black src tests", "fix_format_prettier src tests"]}
format_src = {composite = ["format_black src tests", "format_prettier src tests"]}
fix_format_docs = {composite = ["fix_format_mdformat docs README.md CONTRIBUTING.md CODE_OF_CONDUCT.md", "fix_format_prettier docs"]}
format_docs = {composite = ["format_mdformat docs README.md CONTRIBUTING.md CODE_OF_CONDUCT.md", "format_prettier docs"]}
fix_format_tools = {composite = ["fix_format_black tools", "fix_format_prettier package.json tools .github"]}
format_tools = {composite = ["format_black tools", "format_prettier package.json tools .github"]}

fix_format = {composite = ["fix_format_src", "fix_format_docs", "fix_format_tools"]}
format = {composite = ["format_src", "format_docs", "format_tools"]}


lint_pylint = "pylint"
fix_lint_eslint = "npx eslint --ext .js,.cjs,.mjs --fix"
lint_eslint = "npx eslint --ext .js,.cjs,.mjs"

lint_src_py = {composite = ["lint_pylint src tests"]}
fix_lint_src = {composite = ["fix_lint_eslint src"]}
lint_src = {composite = ["lint_pylint src tests", "lint_eslint src"]}
fix_lint_docs = {composite = ["fix_lint_eslint docs"]}
lint_docs = {composite = ["lint_eslint docs"]}
fix_lint_tools = {composite = ["fix_lint_eslint tools"]}
lint_tools = {composite = ["lint_pylint tools", "lint_eslint tools"]}

fix_lint = {composite = ["fix_lint_src", "fix_lint_docs", "fix_lint_tools"]}
lint = {composite = ["lint_src", "lint_docs", "lint_tools"]}


type_mypy = "mypy"

type_src = {composite = ["type_mypy src tests"]}
type_tools = {composite = ["type_mypy tools"]}

type = {composite = ["type_src", "type_tools"]}


test = "tox"


ci_src_py = {composite = ["format_src_py ", "lint_src_py ", "type_src_py ", "test"]}
ci_src = {composite = ["format_src", "lint_src", "type_src", "test"]}
ci_docs = {composite = ["format_docs", "lint_docs"]}
ci_tools = {composite = ["format_tools", "lint_tools", "type_tools"]}

ci = {composite = ["ci_src", "ci_docs", "ci_tools"]}


docs_build = "mkdocs build -f ./tools/docs/mkdocs.yml"
docs_deploy = "python ./tools/docs/deploy.py"


pkg_install = "pip install -e ."
pkg_build = {composite = ["python ./tools/ci/version.py False", "pdm build"]}
pkg_check = "twine check dist/*.tar.gz dist/*.whl"
pkg_release = {composite = ["pkg_build", "pkg_check", "python ./tools/ci/version.py True"]}

[tool.tox]
legacy_tox_ini = """
[tox]
envlist = py{36,37,38,39,310,311}

[testenv]
deps =
    coverage
    openpyxl

[testenv:py{36}]
setenv =
    COVERAGE_FILE = .tox/py36/.coverage
extras =
    pandas
    pyspark
    numpy
commands =
    python -m coverage run --branch --source ipyvizzu -m unittest discover tests
    python -m coverage report -m --fail-under=100 --omit .tox/py36/lib/python3.6/site-packages/ipyvizzu/integrations/fugue.py

[testenv:py{37,38,39,311}]
package = editable
extras =
    pandas
    pyspark
    numpy
    fugue
commands =
    python -m coverage run --data-file .tox/{envname}/.coverage --branch --source ipyvizzu -m unittest discover tests
    python -m coverage report --data-file .tox/{envname}/.coverage -m --fail-under=100

[testenv:py{310}]
package = editable
extras =
    pandas
    pyspark
    numpy
    fugue
commands =
    python -m coverage run --data-file .tox/{envname}/.coverage --branch --source ipyvizzu -m unittest discover tests
    python -m coverage html --data-file .tox/{envname}/.coverage -d .tox/{envname}/coverage
    python -m coverage report --data-file .tox/{envname}/.coverage -m --fail-under=100
"""

[tool.pdm.dev-dependencies]
packagetool = [
    "pdm==2.8.0 ; python_version >= '3.10'",
    "twine ; python_version >= '3.10'"
]
packagedeps = [
    "IPython ; python_version >= '3.10'",
    "jsonschema ; python_version >= '3.10'",
    "pandas ; python_version >= '3.10'",
    "pandas-stubs ; python_version >= '3.10'",
    "pyspark ; python_version >= '3.10'",
    "numpy ; python_version >= '3.10'",
    "fugue >= 0.8.1 ; python_version >= '3.10'",
]
codequality = [
    "pre-commit ; python_version >= '3.10'",
    "black ; python_version >= '3.10'",
    "pylint ; python_version >= '3.10'",
    "mypy ; python_version >= '3.10'",
    "tox ; python_version >= '3.10'",
]
env = [
    "notebook ; python_version >= '3.10'",
]
docs = [
    "mdformat ; python_version >= '3.10'",
    "mdformat-beautysh ; python_version >= '3.10'",
    "mdformat-black ; python_version >= '3.10'",
    "mdformat-configurable-black ; python_version >= '3.10'",
    "mdformat-config ; python_version >= '3.10'",
    "mdformat-web ; python_version >= '3.10'",
    "mdformat-admon ; python_version >= '3.10'",
    "mdformat-gfm ; python_version >= '3.10'",
    "mdformat-tables ; python_version >= '3.10'",
    "mdformat-footnote ; python_version >= '3.10'",
    "mdformat-frontmatter ; python_version >= '3.10'",
    "mdx_truly_sane_lists ; python_version >= '3.10'",
    "markdown ; python_version >= '3.10'",
    "types-Markdown ; python_version >= '3.10'",
    "pyyaml ; python_version >= '3.10'",
    "types-pyyaml ; python_version >= '3.10'",
    "requests ; python_version >= '3.10'",
    "types-requests ; python_version >= '3.10'",
    "mkdocs ; python_version >= '3.10'",
    "mkdocs-material ; python_version >= '3.10'",
    "mkdocs-section-index ; python_version >= '3.10'",
    "mkdocs-literate-nav ; python_version >= '3.10'",
    "mkdocs-autorefs ; python_version >= '3.10'",
    "mkdocstrings[python] ; python_version >= '3.10'",
    "mkdocs-gen-files ; python_version >= '3.10'",
    "mkdocs-coverage ; python_version >= '3.10'",
    "mike @ git+https://github.com/jimporter/mike.git@master",
]

[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"

[tool.pdm.package-dir]
ipyvizzu = "src/ipyvizzu"

[tool.pdm.version]
source = "file"
path = "src/ipyvizzu/__version__.py"

[tool.pylint.messages-control]
disable = ["fixme"]
good-names= ["i", "df"]

pdm.lock METASEP
# This file is @generated by PDM.
# It is not intended for manual editing.

[metadata]
groups = ["codequality", "docs", "env", "packagedeps", "packagetool"]
cross_platform = true
static_urls = false
lock_version = "4.3"
content_hash = "sha256:c2706560e8d9cdbd7f8d9bbebe96583a77ebc11aa2245d9c9c4ead82aed8e44b"

[[package]]
name = "adagio"
version = "0.2.4"
requires_python = ">=3.6"
summary = "The Dag IO Framework for Fugue projects"
dependencies = [
    "triad>=0.6.1",
]
files = [
    {file = "adagio-0.2.4-py3-none-any.whl", hash = "sha256:c6c4d812f629fc3141284a0b3cfe483731b28da3a1b18f3d5498695ff87dcc12"},
    {file = "adagio-0.2.4.tar.gz", hash = "sha256:e58abc4539184a65faf9956957d3787616bedeb1303ac5c9b1a201d8af6b87d7"},
]

[[package]]
name = "antlr4-python3-runtime"
version = "4.11.1"
summary = "ANTLR 4.11.1 runtime for Python 3"
files = [
    {file = "antlr4-python3-runtime-4.11.1.tar.gz", hash = "sha256:a53de701312f9bdacc5258a6872cd6c62b90d3a90ae25e494026f76267333b60"},
    {file = "antlr4_python3_runtime-4.11.1-py3-none-any.whl", hash = "sha256:ff1954eda1ca9072c02bf500387d0c86cb549bef4dbb3b64f39468b547ec5f6b"},
]

[[package]]
name = "anyio"
version = "3.7.1"
requires_python = ">=3.7"
summary = "High level compatibility layer for multiple asynchronous event loop implementations"
dependencies = [
    "exceptiongroup; python_version < \"3.11\"",
    "idna>=2.8",
    "sniffio>=1.1",
]
files = [
    {file = "anyio-3.7.1-py3-none-any.whl", hash = "sha256:91dee416e570e92c64041bd18b900d1d6fa78dff7048769ce5ac5ddad004fbb5"},
    {file = "anyio-3.7.1.tar.gz", hash = "sha256:44a3c9aba0f5defa43261a8b3efb97891f2bd7d804e0e1f56419befa1adfc780"},
]

[[package]]
name = "appdirs"
version = "1.4.4"
summary = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
files = [
    {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
    {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
]

[[package]]
name = "appnope"
version = "0.1.3"
summary = "Disable App Nap on macOS >= 10.9"
files = [
    {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"},
    {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
]

[[package]]
name = "argon2-cffi"
version = "21.3.0"
requires_python = ">=3.6"
summary = "The secure Argon2 password hashing algorithm."
dependencies = [
    "argon2-cffi-bindings",
]
files = [
    {file = "argon2-cffi-21.3.0.tar.gz", hash = "sha256:d384164d944190a7dd7ef22c6aa3ff197da12962bd04b17f64d4e93d934dba5b"},
    {file = "argon2_cffi-21.3.0-py3-none-any.whl", hash = "sha256:8c976986f2c5c0e5000919e6de187906cfd81fb1c72bf9d88c01177e77da7f80"},
]

[[package]]
name = "argon2-cffi-bindings"
version = "21.2.0"
requires_python = ">=3.6"
summary = "Low-level CFFI bindings for Argon2"
dependencies = [
    "cffi>=1.0.1",
]
files = [
    {file = "argon2-cffi-bindings-21.2.0.tar.gz", hash = "sha256:bb89ceffa6c791807d1305ceb77dbfacc5aa499891d2c55661c6459651fc39e3"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:ccb949252cb2ab3a08c02024acb77cfb179492d5701c7cbdbfd776124d4d2367"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9524464572e12979364b7d600abf96181d3541da11e23ddf565a32e70bd4dc0d"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b746dba803a79238e925d9046a63aa26bf86ab2a2fe74ce6b009a1c3f5c8f2ae"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58ed19212051f49a523abb1dbe954337dc82d947fb6e5a0da60f7c8471a8476c"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:bd46088725ef7f58b5a1ef7ca06647ebaf0eb4baff7d1d0d177c6cc8744abd86"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_i686.whl", hash = "sha256:8cd69c07dd875537a824deec19f978e0f2078fdda07fd5c42ac29668dda5f40f"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f1152ac548bd5b8bcecfb0b0371f082037e47128653df2e8ba6e914d384f3c3e"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win32.whl", hash = "sha256:603ca0aba86b1349b147cab91ae970c63118a0f30444d4bc80355937c950c082"},
    {file = "argon2_cffi_bindings-21.2.0-cp36-abi3-win_amd64.whl", hash = "sha256:b2ef1c30440dbbcba7a5dc3e319408b59676e2e039e2ae11a8775ecf482b192f"},
    {file = "argon2_cffi_bindings-21.2.0-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e415e3f62c8d124ee16018e491a009937f8cf7ebf5eb430ffc5de21b900dad93"},
    {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3e385d1c39c520c08b53d63300c3ecc28622f076f4c2b0e6d7e796e9f6502194"},
    {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c3e3cc67fdb7d82c4718f19b4e7a87123caf8a93fde7e23cf66ac0337d3cb3f"},
    {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6a22ad9800121b71099d0fb0a65323810a15f2e292f2ba450810a7316e128ee5"},
    {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9f8b450ed0547e3d473fdc8612083fd08dd2120d6ac8f73828df9b7d45bb351"},
    {file = "argon2_cffi_bindings-21.2.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:93f9bf70084f97245ba10ee36575f0c3f1e7d7724d67d8e5b08e61787c320ed7"},
    {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3b9ef65804859d335dc6b31582cad2c5166f0c3e7975f324d9ffaa34ee7e6583"},
    {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4966ef5848d820776f5f562a7d45fdd70c2f330c961d0d745b784034bd9f48d"},
    {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20ef543a89dee4db46a1a6e206cd015360e5a75822f76df533845c3cbaf72670"},
    {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed2937d286e2ad0cc79a7087d3c272832865f779430e0cc2b4f3718d3159b0cb"},
    {file = "argon2_cffi_bindings-21.2.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5e00316dabdaea0b2dd82d141cc66889ced0cdcbfa599e8b471cf22c620c329a"},
]

[[package]]
name = "arrow"
version = "1.2.3"
requires_python = ">=3.6"
summary = "Better dates & times for Python"
dependencies = [
    "python-dateutil>=2.7.0",
]
files = [
    {file = "arrow-1.2.3-py3-none-any.whl", hash = "sha256:5a49ab92e3b7b71d96cd6bfcc4df14efefc9dfa96ea19045815914a6ab6b1fe2"},
    {file = "arrow-1.2.3.tar.gz", hash = "sha256:3934b30ca1b9f292376d9db15b19446088d12ec58629bc3f0da28fd55fb633a1"},
]

[[package]]
name = "astroid"
version = "2.15.6"
requires_python = ">=3.7.2"
summary = "An abstract syntax tree for Python with inference support."
dependencies = [
    "lazy-object-proxy>=1.4.0",
    "typing-extensions>=4.0.0; python_version < \"3.11\"",
    "wrapt<2,>=1.11; python_version < \"3.11\"",
    "wrapt<2,>=1.14; python_version >= \"3.11\"",
]
files = [
    {file = "astroid-2.15.6-py3-none-any.whl", hash = "sha256:389656ca57b6108f939cf5d2f9a2a825a3be50ba9d589670f393236e0a03b91c"},
    {file = "astroid-2.15.6.tar.gz", hash = "sha256:903f024859b7c7687d7a7f3a3f73b17301f8e42dfd9cc9df9d4418172d3e2dbd"},
]

[[package]]
name = "asttokens"
version = "2.2.1"
summary = "Annotate AST trees with source code positions"
dependencies = [
    "six",
]
files = [
    {file = "asttokens-2.2.1-py2.py3-none-any.whl", hash = "sha256:6b0ac9e93fb0335014d382b8fa9b3afa7df546984258005da0b9e7095b3deb1c"},
    {file = "asttokens-2.2.1.tar.gz", hash = "sha256:4622110b2a6f30b77e1473affaa97e711bc2f07d3f10848420ff1898edbe94f3"},
]

[[package]]
name = "async-lru"
version = "2.0.4"
requires_python = ">=3.8"
summary = "Simple LRU cache for asyncio"
dependencies = [
    "typing-extensions>=4.0.0; python_version < \"3.11\"",
]
files = [
    {file = "async-lru-2.0.4.tar.gz", hash = "sha256:b8a59a5df60805ff63220b2a0c5b5393da5521b113cd5465a44eb037d81a5627"},
    {file = "async_lru-2.0.4-py3-none-any.whl", hash = "sha256:ff02944ce3c288c5be660c42dbcca0742b32c3b279d6dceda655190240b99224"},
]

[[package]]
name = "attrs"
version = "23.1.0"
requires_python = ">=3.7"
summary = "Classes Without Boilerplate"
files = [
    {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"},
    {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
]

[[package]]
name = "babel"
version = "2.12.1"
requires_python = ">=3.7"
summary = "Internationalization utilities"
files = [
    {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"},
    {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"},
]

[[package]]
name = "backcall"
version = "0.2.0"
summary = "Specifications for callback functions passed in to an API"
files = [
    {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
    {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
]

[[package]]
name = "beautifulsoup4"
version = "4.12.2"
requires_python = ">=3.6.0"
summary = "Screen-scraping library"
dependencies = [
    "soupsieve>1.2",
]
files = [
    {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"},
    {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"},
]

[[package]]
name = "beautifulsoup4"
version = "4.12.2"
extras = ["lxml"]
requires_python = ">=3.6.0"
summary = "Screen-scraping library"
dependencies = [
    "beautifulsoup4==4.12.2",
    "lxml",
]
files = [
    {file = "beautifulsoup4-4.12.2-py3-none-any.whl", hash = "sha256:bd2520ca0d9d7d12694a53d44ac482d181b4ec1888909b035a3dbf40d0f57d4a"},
    {file = "beautifulsoup4-4.12.2.tar.gz", hash = "sha256:492bbc69dca35d12daac71c4db1bfff0c876c00ef4a2ffacce226d4638eb72da"},
]

[[package]]
name = "beautysh"
version = "6.2.1"
requires_python = ">=3.6.2,<4.0.0"
summary = "A Bash beautifier for the masses."
dependencies = [
    "colorama<0.5.0,>=0.4.4",
    "types-colorama<0.5.0,>=0.4.3",
    "types-setuptools<58.0.0,>=57.4.0",
]
files = [
    {file = "beautysh-6.2.1-py3-none-any.whl", hash = "sha256:8c7d9c4f2bd02c089194218238b7ecc78879506326b301eba1d5f49471a55bac"},
    {file = "beautysh-6.2.1.tar.gz", hash = "sha256:423e0c87cccf2af21cae9a75e04e0a42bc6ce28469c001ee8730242e10a45acd"},
]

[[package]]
name = "black"
version = "23.7.0"
requires_python = ">=3.8"
summary = "The uncompromising code formatter."
dependencies = [
    "click>=8.0.0",
    "mypy-extensions>=0.4.3",
    "packaging>=22.0",
    "pathspec>=0.9.0",
    "platformdirs>=2",
    "tomli>=1.1.0; python_version < \"3.11\"",
]
files = [
    {file = "black-23.7.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:5c4bc552ab52f6c1c506ccae05681fab58c3f72d59ae6e6639e8885e94fe2587"},
    {file = "black-23.7.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:552513d5cd5694590d7ef6f46e1767a4df9af168d449ff767b13b084c020e63f"},
    {file = "black-23.7.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:86cee259349b4448adb4ef9b204bb4467aae74a386bce85d56ba4f5dc0da27be"},
    {file = "black-23.7.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:501387a9edcb75d7ae8a4412bb8749900386eaef258f1aefab18adddea1936bc"},
    {file = "black-23.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:fb074d8b213749fa1d077d630db0d5f8cc3b2ae63587ad4116e8a436e9bbe995"},
    {file = "black-23.7.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:b5b0ee6d96b345a8b420100b7d71ebfdd19fab5e8301aff48ec270042cd40ac2"},
    {file = "black-23.7.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:893695a76b140881531062d48476ebe4a48f5d1e9388177e175d76234ca247cd"},
    {file = "black-23.7.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:c333286dc3ddca6fdff74670b911cccedacb4ef0a60b34e491b8a67c833b343a"},
    {file = "black-23.7.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:831d8f54c3a8c8cf55f64d0422ee875eecac26f5f649fb6c1df65316b67c8926"},
    {file = "black-23.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:7f3bf2dec7d541b4619b8ce526bda74a6b0bffc480a163fed32eb8b3c9aed8ad"},
    {file = "black-23.7.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:f9062af71c59c004cd519e2fb8f5d25d39e46d3af011b41ab43b9c74e27e236f"},
    {file = "black-23.7.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:01ede61aac8c154b55f35301fac3e730baf0c9cf8120f65a9cd61a81cfb4a0c3"},
    {file = "black-23.7.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:327a8c2550ddc573b51e2c352adb88143464bb9d92c10416feb86b0f5aee5ff6"},
    {file = "black-23.7.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1c6022b86f83b632d06f2b02774134def5d4d4f1dac8bef16d90cda18ba28a"},
    {file = "black-23.7.0-cp38-cp38-win_amd64.whl", hash = "sha256:27eb7a0c71604d5de083757fbdb245b1a4fae60e9596514c6ec497eb63f95320"},
    {file = "black-23.7.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:8417dbd2f57b5701492cd46edcecc4f9208dc75529bcf76c514864e48da867d9"},
    {file = "black-23.7.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:47e56d83aad53ca140da0af87678fb38e44fd6bc0af71eebab2d1f59b1acf1d3"},
    {file = "black-23.7.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:25cc308838fe71f7065df53aedd20327969d05671bac95b38fdf37ebe70ac087"},
    {file = "black-23.7.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:642496b675095d423f9b8448243336f8ec71c9d4d57ec17bf795b67f08132a91"},
    {file = "black-23.7.0-cp39-cp39-win_amd64.whl", hash = "sha256:ad0014efc7acf0bd745792bd0d8857413652979200ab924fbf239062adc12491"},
    {file = "black-23.7.0-py3-none-any.whl", hash = "sha256:9fd59d418c60c0348505f2ddf9609c1e1de8e7493eab96198fc89d9f865e7a96"},
    {file = "black-23.7.0.tar.gz", hash = "sha256:022a582720b0d9480ed82576c920a8c1dde97cc38ff11d8d8859b3bd6ca9eedb"},
]

[[package]]
name = "bleach"
version = "6.0.0"
requires_python = ">=3.7"
summary = "An easy safelist-based HTML-sanitizing tool."
dependencies = [
    "six>=1.9.0",
    "webencodings",
]
files = [
    {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"},
    {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"},
]

[[package]]
name = "blinker"
version = "1.6.2"
requires_python = ">=3.7"
summary = "Fast, simple object-to-object and broadcast signaling"
files = [
    {file = "blinker-1.6.2-py3-none-any.whl", hash = "sha256:c3d739772abb7bc2860abf5f2ec284223d9ad5c76da018234f6f50d6f31ab1f0"},
    {file = "blinker-1.6.2.tar.gz", hash = "sha256:4afd3de66ef3a9f8067559fb7a1cbe555c17dcbe15971b05d1b625c3e7abe213"},
]

[[package]]
name = "cachecontrol"
version = "0.13.1"
requires_python = ">=3.7"
summary = "httplib2 caching for requests"
dependencies = [
    "msgpack>=0.5.2",
    "requests>=2.16.0",
]
files = [
    {file = "cachecontrol-0.13.1-py3-none-any.whl", hash = "sha256:95dedbec849f46dda3137866dc28b9d133fc9af55f5b805ab1291833e4457aa4"},
    {file = "cachecontrol-0.13.1.tar.gz", hash = "sha256:f012366b79d2243a6118309ce73151bf52a38d4a5dac8ea57f09bd29087e506b"},
]

[[package]]
name = "cachecontrol"
version = "0.13.1"
extras = ["filecache"]
requires_python = ">=3.7"
summary = "httplib2 caching for requests"
dependencies = [
    "cachecontrol==0.13.1",
    "filelock>=3.8.0",
]
files = [
    {file = "cachecontrol-0.13.1-py3-none-any.whl", hash = "sha256:95dedbec849f46dda3137866dc28b9d133fc9af55f5b805ab1291833e4457aa4"},
    {file = "cachecontrol-0.13.1.tar.gz", hash = "sha256:f012366b79d2243a6118309ce73151bf52a38d4a5dac8ea57f09bd29087e506b"},
]

[[package]]
name = "cachetools"
version = "5.3.1"
requires_python = ">=3.7"
summary = "Extensible memoizing collections and decorators"
files = [
    {file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"},
    {file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"},
]

[[package]]
name = "certifi"
version = "2023.7.22"
requires_python = ">=3.6"
summary = "Python package for providing Mozilla's CA Bundle."
files = [
    {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"},
    {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"},
]

[[package]]
name = "cffi"
version = "1.15.1"
summary = "Foreign Function Interface for Python calling C code."
dependencies = [
    "pycparser",
]
files = [
    {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"},
    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"},
    {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"},
    {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"},
    {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"},
    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"},
    {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"},
    {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"},
    {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"},
    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"},
    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"},
    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"},
    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"},
    {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"},
    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"},
    {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"},
    {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"},
    {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"},
    {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"},
    {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"},
    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"},
    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"},
    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"},
    {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"},
    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"},
    {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"},
    {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"},
    {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"},
    {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"},
    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"},
    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"},
    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"},
    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"},
    {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"},
    {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"},
    {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"},
    {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"},
    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"},
    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"},
    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"},
    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"},
    {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"},
    {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"},
    {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"},
    {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"},
    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"},
    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"},
    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"},
    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"},
    {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"},
    {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"},
    {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"},
    {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"},
    {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"},
    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"},
    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"},
    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"},
    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"},
    {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"},
    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"},
    {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"},
    {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"},
    {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"},
    {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"},
]

[[package]]
name = "cfgv"
version = "3.3.1"
requires_python = ">=3.6.1"
summary = "Validate configuration and produce human readable error messages."
files = [
    {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
    {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
]

[[package]]
name = "chardet"
version = "5.2.0"
requires_python = ">=3.7"
summary = "Universal encoding detector for Python 3"
files = [
    {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"},
    {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"},
]

[[package]]
name = "charset-normalizer"
version = "3.2.0"
requires_python = ">=3.7.0"
summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
files = [
    {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"},
    {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"},
    {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"},
    {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"},
    {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"},
    {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"},
    {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"},
]

[[package]]
name = "click"
version = "8.0.4"
requires_python = ">=3.6"
summary = "Composable command line interface toolkit"
dependencies = [
    "colorama; platform_system == \"Windows\"",
    "importlib-metadata; python_version < \"3.8\"",
]
files = [
    {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"},
    {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"},
]

[[package]]
name = "colorama"
version = "0.4.6"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
summary = "Cross-platform colored terminal text."
files = [
    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]

[[package]]
name = "comm"
version = "0.1.4"
requires_python = ">=3.6"
summary = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc."
dependencies = [
    "traitlets>=4",
]
files = [
    {file = "comm-0.1.4-py3-none-any.whl", hash = "sha256:6d52794cba11b36ed9860999cd10fd02d6b2eac177068fdd585e1e2f8a96e67a"},
    {file = "comm-0.1.4.tar.gz", hash = "sha256:354e40a59c9dd6db50c5cc6b4acc887d82e9603787f83b68c01a80a923984d15"},
]

[[package]]
name = "cryptography"
version = "41.0.3"
requires_python = ">=3.7"
summary = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
dependencies = [
    "cffi>=1.12",
]
files = [
    {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507"},
    {file = "cryptography-41.0.3-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922"},
    {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81"},
    {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd"},
    {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47"},
    {file = "cryptography-41.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116"},
    {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c"},
    {file = "cryptography-41.0.3-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae"},
    {file = "cryptography-41.0.3-cp37-abi3-win32.whl", hash = "sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306"},
    {file = "cryptography-41.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574"},
    {file = "cryptography-41.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087"},
    {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858"},
    {file = "cryptography-41.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906"},
    {file = "cryptography-41.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e"},
    {file = "cryptography-41.0.3-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd"},
    {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207"},
    {file = "cryptography-41.0.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84"},
    {file = "cryptography-41.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7"},
    {file = "cryptography-41.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d"},
    {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de"},
    {file = "cryptography-41.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1"},
    {file = "cryptography-41.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4"},
    {file = "cryptography-41.0.3.tar.gz", hash = "sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34"},
]

[[package]]
name = "cssbeautifier"
version = "1.14.9"
summary = "CSS unobfuscator and beautifier."
dependencies = [
    "editorconfig>=0.12.2",
    "jsbeautifier",
    "six>=1.13.0",
]
files = [
    {file = "cssbeautifier-1.14.9.tar.gz", hash = "sha256:2da432472f68170eb854aff97b16a24721f5090ee36af2e31199590a89e7f71f"},
]

[[package]]
name = "debugpy"
version = "1.6.7"
requires_python = ">=3.7"
summary = "An implementation of the Debug Adapter Protocol for Python"
files = [
    {file = "debugpy-1.6.7-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b3e7ac809b991006ad7f857f016fa92014445085711ef111fdc3f74f66144096"},
    {file = "debugpy-1.6.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e3876611d114a18aafef6383695dfc3f1217c98a9168c1aaf1a02b01ec7d8d1e"},
    {file = "debugpy-1.6.7-cp310-cp310-win32.whl", hash = "sha256:33edb4afa85c098c24cc361d72ba7c21bb92f501104514d4ffec1fb36e09c01a"},
    {file = "debugpy-1.6.7-cp310-cp310-win_amd64.whl", hash = "sha256:ed6d5413474e209ba50b1a75b2d9eecf64d41e6e4501977991cdc755dc83ab0f"},
    {file = "debugpy-1.6.7-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:38ed626353e7c63f4b11efad659be04c23de2b0d15efff77b60e4740ea685d07"},
    {file = "debugpy-1.6.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:279d64c408c60431c8ee832dfd9ace7c396984fd7341fa3116aee414e7dcd88d"},
    {file = "debugpy-1.6.7-cp37-cp37m-win32.whl", hash = "sha256:dbe04e7568aa69361a5b4c47b4493d5680bfa3a911d1e105fbea1b1f23f3eb45"},
    {file = "debugpy-1.6.7-cp37-cp37m-win_amd64.whl", hash = "sha256:f90a2d4ad9a035cee7331c06a4cf2245e38bd7c89554fe3b616d90ab8aab89cc"},
    {file = "debugpy-1.6.7-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:5224eabbbeddcf1943d4e2821876f3e5d7d383f27390b82da5d9558fd4eb30a9"},
    {file = "debugpy-1.6.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bae1123dff5bfe548ba1683eb972329ba6d646c3a80e6b4c06cd1b1dd0205e9b"},
    {file = "debugpy-1.6.7-cp38-cp38-win32.whl", hash = "sha256:9cd10cf338e0907fdcf9eac9087faa30f150ef5445af5a545d307055141dd7a4"},
    {file = "debugpy-1.6.7-cp38-cp38-win_amd64.whl", hash = "sha256:aaf6da50377ff4056c8ed470da24632b42e4087bc826845daad7af211e00faad"},
    {file = "debugpy-1.6.7-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:0679b7e1e3523bd7d7869447ec67b59728675aadfc038550a63a362b63029d2c"},
    {file = "debugpy-1.6.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de86029696e1b3b4d0d49076b9eba606c226e33ae312a57a46dca14ff370894d"},
    {file = "debugpy-1.6.7-cp39-cp39-win32.whl", hash = "sha256:d71b31117779d9a90b745720c0eab54ae1da76d5b38c8026c654f4a066b0130a"},
    {file = "debugpy-1.6.7-cp39-cp39-win_amd64.whl", hash = "sha256:c0ff93ae90a03b06d85b2c529eca51ab15457868a377c4cc40a23ab0e4e552a3"},
    {file = "debugpy-1.6.7-py2.py3-none-any.whl", hash = "sha256:53f7a456bc50706a0eaabecf2d3ce44c4d5010e46dfc65b6b81a518b42866267"},
    {file = "debugpy-1.6.7.zip", hash = "sha256:c4c2f0810fa25323abfdfa36cbbbb24e5c3b1a42cb762782de64439c575d67f2"},
]

[[package]]
name = "decorator"
version = "5.1.1"
requires_python = ">=3.5"
summary = "Decorators for Humans"
files = [
    {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
    {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
]

[[package]]
name = "defusedxml"
version = "0.7.1"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "XML bomb protection for Python stdlib modules"
files = [
    {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"},
    {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"},
]

[[package]]
name = "dill"
version = "0.3.7"
requires_python = ">=3.7"
summary = "serialize all of Python"
files = [
    {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"},
    {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"},
]

[[package]]
name = "distlib"
version = "0.3.7"
summary = "Distribution utilities"
files = [
    {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"},
    {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"},
]

[[package]]
name = "docutils"
version = "0.20.1"
requires_python = ">=3.7"
summary = "Docutils -- Python Documentation Utilities"
files = [
    {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"},
    {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"},
]

[[package]]
name = "editorconfig"
version = "0.12.3"
summary = "EditorConfig File Locator and Interpreter for Python"
files = [
    {file = "EditorConfig-0.12.3-py3-none-any.whl", hash = "sha256:6b0851425aa875b08b16789ee0eeadbd4ab59666e9ebe728e526314c4a2e52c1"},
    {file = "EditorConfig-0.12.3.tar.gz", hash = "sha256:57f8ce78afcba15c8b18d46b5170848c88d56fd38f05c2ec60dbbfcb8996e89e"},
]

[[package]]
name = "exceptiongroup"
version = "1.1.2"
requires_python = ">=3.7"
summary = "Backport of PEP 654 (exception groups)"
files = [
    {file = "exceptiongroup-1.1.2-py3-none-any.whl", hash = "sha256:e346e69d186172ca7cf029c8c1d16235aa0e04035e5750b4b95039e65204328f"},
    {file = "exceptiongroup-1.1.2.tar.gz", hash = "sha256:12c3e887d6485d16943a309616de20ae5582633e0a2eda17f4e10fd61c1e8af5"},
]

[[package]]
name = "executing"
version = "1.2.0"
summary = "Get the currently executing AST node of a frame, and other information"
files = [
    {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"},
    {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"},
]

[[package]]
name = "fastjsonschema"
version = "2.18.0"
summary = "Fastest Python implementation of JSON schema"
files = [
    {file = "fastjsonschema-2.18.0-py3-none-any.whl", hash = "sha256:128039912a11a807068a7c87d0da36660afbfd7202780db26c4aa7153cfdc799"},
    {file = "fastjsonschema-2.18.0.tar.gz", hash = "sha256:e820349dd16f806e4bd1467a138dced9def4bc7d6213a34295272a6cac95b5bd"},
]

[[package]]
name = "filelock"
version = "3.12.2"
requires_python = ">=3.7"
summary = "A platform independent file lock."
files = [
    {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"},
    {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"},
]

[[package]]
name = "findpython"
version = "0.3.1"
requires_python = ">=3.7"
summary = "A utility to find python versions on your system"
dependencies = [
    "packaging>=20",
]
files = [
    {file = "findpython-0.3.1-py3-none-any.whl", hash = "sha256:b57a67fc95cc687bfcfa4944c730a5e368b8cbe20f84ad4cdbc9d6bfe128f50b"},
    {file = "findpython-0.3.1.tar.gz", hash = "sha256:7621f8a9c199a70d219831cddaeb84ca7e83e20b8358172bff47871a18a5eda4"},
]

[[package]]
name = "fqdn"
version = "1.5.1"
requires_python = ">=2.7, !=3.0, !=3.1, !=3.2, !=3.3, !=3.4, <4"
summary = "Validates fully-qualified domain names against RFC 1123, so that they are acceptable to modern bowsers"
files = [
    {file = "fqdn-1.5.1-py3-none-any.whl", hash = "sha256:3a179af3761e4df6eb2e026ff9e1a3033d3587bf980a0b1b2e1e5d08d7358014"},
    {file = "fqdn-1.5.1.tar.gz", hash = "sha256:105ed3677e767fb5ca086a0c1f4bb66ebc3c100be518f0e0d755d9eae164d89f"},
]

[[package]]
name = "fs"
version = "2.4.16"
summary = "Python's filesystem abstraction layer"
dependencies = [
    "appdirs~=1.4.3",
    "setuptools",
    "six~=1.10",
]
files = [
    {file = "fs-2.4.16-py2.py3-none-any.whl", hash = "sha256:660064febbccda264ae0b6bace80a8d1be9e089e0a5eb2427b7d517f9a91545c"},
    {file = "fs-2.4.16.tar.gz", hash = "sha256:ae97c7d51213f4b70b6a958292530289090de3a7e15841e108fbe144f069d313"},
]

[[package]]
name = "fsspec"
version = "2023.6.0"
requires_python = ">=3.8"
summary = "File-system specification"
files = [
    {file = "fsspec-2023.6.0-py3-none-any.whl", hash = "sha256:1cbad1faef3e391fba6dc005ae9b5bdcbf43005c9167ce78c915549c352c869a"},
    {file = "fsspec-2023.6.0.tar.gz", hash = "sha256:d0b2f935446169753e7a5c5c55681c54ea91996cc67be93c39a154fb3a2742af"},
]

[[package]]
name = "fugue"
version = "0.8.6"
requires_python = ">=3.7"
summary = "An abstraction layer for distributed computation"
dependencies = [
    "adagio>=0.2.4",
    "fugue-sql-antlr>=0.1.6",
    "jinja2",
    "pandas>=1.2.0",
    "pyarrow>=0.15.1",
    "qpd>=0.4.4",
    "sqlglot",
    "triad>=0.9.1",
]
files = [
    {file = "fugue-0.8.6-py3-none-any.whl", hash = "sha256:e92742b309a0283ccd021f3ab7a6d8ecd32980179ee3539bcf679173dceac5d4"},
    {file = "fugue-0.8.6.tar.gz", hash = "sha256:4e30c4edbaee31a768b9a097e60d29b39d736a0302d3b611075de3fa73162d09"},
]

[[package]]
name = "fugue-sql-antlr"
version = "0.1.6"
requires_python = ">=3.6"
summary = "Fugue SQL Antlr Parser"
dependencies = [
    "antlr4-python3-runtime<4.12,>=4.11.1",
    "jinja2",
    "triad>=0.6.8",
]
files = [
    {file = "fugue-sql-antlr-0.1.6.tar.gz", hash = "sha256:7787bb0e8fa9e1333cd09a6fee913cae1e02ec26f91cabae9e821adf4cca4f5e"},
]

[[package]]
name = "ghp-import"
version = "2.1.0"
summary = "Copy your docs directly to the gh-pages branch."
dependencies = [
    "python-dateutil>=2.8.1",
]
files = [
    {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
    {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
]

[[package]]
name = "griffe"
version = "0.32.3"
requires_python = ">=3.8"
summary = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API."
dependencies = [
    "colorama>=0.4",
]
files = [
    {file = "griffe-0.32.3-py3-none-any.whl", hash = "sha256:d9471934225818bf8f309822f70451cc6abb4b24e59e0bb27402a45f9412510f"},
    {file = "griffe-0.32.3.tar.gz", hash = "sha256:14983896ad581f59d5ad7b6c9261ff12bdaa905acccc1129341d13e545da8521"},
]

[[package]]
name = "identify"
version = "2.5.26"
requires_python = ">=3.8"
summary = "File identification library for Python"
files = [
    {file = "identify-2.5.26-py2.py3-none-any.whl", hash = "sha256:c22a8ead0d4ca11f1edd6c9418c3220669b3b7533ada0a0ffa6cc0ef85cf9b54"},
    {file = "identify-2.5.26.tar.gz", hash = "sha256:7243800bce2f58404ed41b7c002e53d4d22bcf3ae1b7900c2d7aefd95394bf7f"},
]

[[package]]
name = "idna"
version = "3.4"
requires_python = ">=3.5"
summary = "Internationalized Domain Names in Applications (IDNA)"
files = [
    {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
    {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]

[[package]]
name = "importlib-metadata"
version = "4.8.3"
requires_python = ">=3.6"
summary = "Read metadata from Python packages"
dependencies = [
    "typing-extensions>=3.6.4; python_version < \"3.8\"",
    "zipp>=0.5",
]
files = [
    {file = "importlib_metadata-4.8.3-py3-none-any.whl", hash = "sha256:65a9576a5b2d58ca44d133c42a241905cc45e34d2c06fd5ba2bafa221e5d7b5e"},
    {file = "importlib_metadata-4.8.3.tar.gz", hash = "sha256:766abffff765960fcc18003801f7044eb6755ffae4521c8e8ce8e83b9c9b0668"},
]

[[package]]
name = "importlib-resources"
version = "5.4.0"
requires_python = ">=3.6"
summary = "Read resources from Python packages"
dependencies = [
    "zipp>=3.1.0; python_version < \"3.10\"",
]
files = [
    {file = "importlib_resources-5.4.0-py3-none-any.whl", hash = "sha256:33a95faed5fc19b4bc16b29a6eeae248a3fe69dd55d4d229d2b480e23eeaad45"},
    {file = "importlib_resources-5.4.0.tar.gz", hash = "sha256:d756e2f85dd4de2ba89be0b21dba2a3bbec2e871a42a3a16719258a11f87506b"},
]

[[package]]
name = "installer"
version = "0.7.0"
requires_python = ">=3.7"
summary = "A library for installing Python wheels."
files = [
    {file = "installer-0.7.0-py3-none-any.whl", hash = "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53"},
    {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"},
]

[[package]]
name = "ipykernel"
version = "6.25.1"
requires_python = ">=3.8"
summary = "IPython Kernel for Jupyter"
dependencies = [
    "appnope; platform_system == \"Darwin\"",
    "comm>=0.1.1",
    "debugpy>=1.6.5",
    "ipython>=7.23.1",
    "jupyter-client>=6.1.12",
    "jupyter-core!=5.0.*,>=4.12",
    "matplotlib-inline>=0.1",
    "nest-asyncio",
    "packaging",
    "psutil",
    "pyzmq>=20",
    "tornado>=6.1",
    "traitlets>=5.4.0",
]
files = [
    {file = "ipykernel-6.25.1-py3-none-any.whl", hash = "sha256:c8a2430b357073b37c76c21c52184db42f6b4b0e438e1eb7df3c4440d120497c"},
    {file = "ipykernel-6.25.1.tar.gz", hash = "sha256:050391364c0977e768e354bdb60cbbfbee7cbb943b1af1618382021136ffd42f"},
]

[[package]]
name = "ipython"
version = "8.14.0"
requires_python = ">=3.9"
summary = "IPython: Productive Interactive Computing"
dependencies = [
    "appnope; sys_platform == \"darwin\"",
    "backcall",
    "colorama; sys_platform == \"win32\"",
    "decorator",
    "jedi>=0.16",
    "matplotlib-inline",
    "pexpect>4.3; sys_platform != \"win32\"",
    "pickleshare",
    "prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30",
    "pygments>=2.4.0",
    "stack-data",
    "traitlets>=5",
]
files = [
    {file = "ipython-8.14.0-py3-none-any.whl", hash = "sha256:248aca623f5c99a6635bc3857677b7320b9b8039f99f070ee0d20a5ca5a8e6bf"},
    {file = "ipython-8.14.0.tar.gz", hash = "sha256:1d197b907b6ba441b692c48cf2a3a2de280dc0ac91a3405b39349a50272ca0a1"},
]

[[package]]
name = "isoduration"
version = "20.11.0"
requires_python = ">=3.7"
summary = "Operations with ISO 8601 durations"
dependencies = [
    "arrow>=0.15.0",
]
files = [
    {file = "isoduration-20.11.0-py3-none-any.whl", hash = "sha256:b2904c2a4228c3d44f409c8ae8e2370eb21a26f7ac2ec5446df141dde3452042"},
    {file = "isoduration-20.11.0.tar.gz", hash = "sha256:ac2f9015137935279eac671f94f89eb00584f940f5dc49462a0c4ee692ba1bd9"},
]

[[package]]
name = "isort"
version = "5.12.0"
requires_python = ">=3.8.0"
summary = "A Python utility / library to sort Python imports."
files = [
    {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"},
    {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"},
]

[[package]]
name = "jaraco-classes"
version = "3.3.0"
requires_python = ">=3.8"
summary = "Utility functions for Python class constructs"
dependencies = [
    "more-itertools",
]
files = [
    {file = "jaraco.classes-3.3.0-py3-none-any.whl", hash = "sha256:10afa92b6743f25c0cf5f37c6bb6e18e2c5bb84a16527ccfc0040ea377e7aaeb"},
    {file = "jaraco.classes-3.3.0.tar.gz", hash = "sha256:c063dd08e89217cee02c8d5e5ec560f2c8ce6cdc2fcdc2e68f7b2e5547ed3621"},
]

[[package]]
name = "jedi"
version = "0.19.0"
requires_python = ">=3.6"
summary = "An autocompletion tool for Python that can be used for text editors."
dependencies = [
    "parso<0.9.0,>=0.8.3",
]
files = [
    {file = "jedi-0.19.0-py2.py3-none-any.whl", hash = "sha256:cb8ce23fbccff0025e9386b5cf85e892f94c9b822378f8da49970471335ac64e"},
    {file = "jedi-0.19.0.tar.gz", hash = "sha256:bcf9894f1753969cbac8022a8c2eaee06bfa3724e4192470aaffe7eb6272b0c4"},
]

[[package]]
name = "jeepney"
version = "0.8.0"
requires_python = ">=3.7"
summary = "Low-level, pure Python DBus protocol wrapper."
files = [
    {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"},
    {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"},
]

[[package]]
name = "jinja2"
version = "3.0.3"
requires_python = ">=3.6"
summary = "A very fast and expressive template engine."
dependencies = [
    "MarkupSafe>=2.0",
]
files = [
    {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
    {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
]

[[package]]
name = "jsbeautifier"
version = "1.14.9"
summary = "JavaScript unobfuscator and beautifier."
dependencies = [
    "editorconfig>=0.12.2",
    "six>=1.13.0",
]
files = [
    {file = "jsbeautifier-1.14.9.tar.gz", hash = "sha256:c738ebc36b47bd94e4ca6dd17a9004c3cc74edad582ca1d60e0e5d5945a63cb9"},
]

[[package]]
name = "json5"
version = "0.9.14"
summary = "A Python implementation of the JSON5 data format."
files = [
    {file = "json5-0.9.14-py2.py3-none-any.whl", hash = "sha256:740c7f1b9e584a468dbb2939d8d458db3427f2c93ae2139d05f47e453eae964f"},
    {file = "json5-0.9.14.tar.gz", hash = "sha256:9ed66c3a6ca3510a976a9ef9b8c0787de24802724ab1860bc0153c7fdd589b02"},
]

[[package]]
name = "jsonpointer"
version = "2.4"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
summary = "Identify specific nodes in a JSON document (RFC 6901) "
files = [
    {file = "jsonpointer-2.4-py2.py3-none-any.whl", hash = "sha256:15d51bba20eea3165644553647711d150376234112651b4f1811022aecad7d7a"},
    {file = "jsonpointer-2.4.tar.gz", hash = "sha256:585cee82b70211fa9e6043b7bb89db6e1aa49524340dde8ad6b63206ea689d88"},
]

[[package]]
name = "jsonschema"
version = "4.19.0"
requires_python = ">=3.8"
summary = "An implementation of JSON Schema validation for Python"
dependencies = [
    "attrs>=22.2.0",
    "jsonschema-specifications>=2023.03.6",
    "referencing>=0.28.4",
    "rpds-py>=0.7.1",
]
files = [
    {file = "jsonschema-4.19.0-py3-none-any.whl", hash = "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb"},
    {file = "jsonschema-4.19.0.tar.gz", hash = "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f"},
]

[[package]]
name = "jsonschema-specifications"
version = "2023.7.1"
requires_python = ">=3.8"
summary = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry"
dependencies = [
    "referencing>=0.28.0",
]
files = [
    {file = "jsonschema_specifications-2023.7.1-py3-none-any.whl", hash = "sha256:05adf340b659828a004220a9613be00fa3f223f2b82002e273dee62fd50524b1"},
    {file = "jsonschema_specifications-2023.7.1.tar.gz", hash = "sha256:c91a50404e88a1f6ba40636778e2ee08f6e24c5613fe4c53ac24578a5a7f72bb"},
]

[[package]]
name = "jsonschema"
version = "4.19.0"
extras = ["format-nongpl"]
requires_python = ">=3.8"
summary = "An implementation of JSON Schema validation for Python"
dependencies = [
    "fqdn",
    "idna",
    "isoduration",
    "jsonpointer>1.13",
    "jsonschema==4.19.0",
    "rfc3339-validator",
    "rfc3986-validator>0.1.0",
    "uri-template",
    "webcolors>=1.11",
]
files = [
    {file = "jsonschema-4.19.0-py3-none-any.whl", hash = "sha256:043dc26a3845ff09d20e4420d6012a9c91c9aa8999fa184e7efcfeccb41e32cb"},
    {file = "jsonschema-4.19.0.tar.gz", hash = "sha256:6e1e7569ac13be8139b2dd2c21a55d350066ee3f80df06c608b398cdc6f30e8f"},
]

[[package]]
name = "jupyter-client"
version = "8.3.0"
requires_python = ">=3.8"
summary = "Jupyter protocol implementation and client libraries"
dependencies = [
    "jupyter-core!=5.0.*,>=4.12",
    "python-dateutil>=2.8.2",
    "pyzmq>=23.0",
    "tornado>=6.2",
    "traitlets>=5.3",
]
files = [
    {file = "jupyter_client-8.3.0-py3-none-any.whl", hash = "sha256:7441af0c0672edc5d28035e92ba5e32fadcfa8a4e608a434c228836a89df6158"},
    {file = "jupyter_client-8.3.0.tar.gz", hash = "sha256:3af69921fe99617be1670399a0b857ad67275eefcfa291e2c81a160b7b650f5f"},
]

[[package]]
name = "jupyter-core"
version = "5.3.1"
requires_python = ">=3.8"
summary = "Jupyter core package. A base package on which Jupyter projects rely."
dependencies = [
    "platformdirs>=2.5",
    "pywin32>=300; sys_platform == \"win32\" and platform_python_implementation != \"PyPy\"",
    "traitlets>=5.3",
]
files = [
    {file = "jupyter_core-5.3.1-py3-none-any.whl", hash = "sha256:ae9036db959a71ec1cac33081eeb040a79e681f08ab68b0883e9a676c7a90dce"},
    {file = "jupyter_core-5.3.1.tar.gz", hash = "sha256:5ba5c7938a7f97a6b0481463f7ff0dbac7c15ba48cf46fa4035ca6e838aa1aba"},
]

[[package]]
name = "jupyter-events"
version = "0.7.0"
requires_python = ">=3.8"
summary = "Jupyter Event System library"
dependencies = [
    "jsonschema[format-nongpl]>=4.18.0",
    "python-json-logger>=2.0.4",
    "pyyaml>=5.3",
    "referencing",
    "rfc3339-validator",
    "rfc3986-validator>=0.1.1",
    "traitlets>=5.3",
]
files = [
    {file = "jupyter_events-0.7.0-py3-none-any.whl", hash = "sha256:4753da434c13a37c3f3c89b500afa0c0a6241633441421f6adafe2fb2e2b924e"},
    {file = "jupyter_events-0.7.0.tar.gz", hash = "sha256:7be27f54b8388c03eefea123a4f79247c5b9381c49fb1cd48615ee191eb12615"},
]

[[package]]
name = "jupyter-lsp"
version = "2.2.0"
requires_python = ">=3.8"
summary = "Multi-Language Server WebSocket proxy for Jupyter Notebook/Lab server"
dependencies = [
    "jupyter-server>=1.1.2",
]
files = [
    {file = "jupyter-lsp-2.2.0.tar.gz", hash = "sha256:8ebbcb533adb41e5d635eb8fe82956b0aafbf0fd443b6c4bfa906edeeb8635a1"},
    {file = "jupyter_lsp-2.2.0-py3-none-any.whl", hash = "sha256:9e06b8b4f7dd50300b70dd1a78c0c3b0c3d8fa68e0f2d8a5d1fbab62072aca3f"},
]

[[package]]
name = "jupyter-server"
version = "2.7.0"
requires_python = ">=3.8"
summary = "The backend—i.e. core services, APIs, and REST endpoints—to Jupyter web applications."
dependencies = [
    "anyio>=3.1.0",
    "argon2-cffi",
    "jinja2",
    "jupyter-client>=7.4.4",
    "jupyter-core!=5.0.*,>=4.12",
    "jupyter-events>=0.6.0",
    "jupyter-server-terminals",
    "nbconvert>=6.4.4",
    "nbformat>=5.3.0",
    "overrides",
    "packaging",
    "prometheus-client",
    "pywinpty; os_name == \"nt\"",
    "pyzmq>=24",
    "send2trash",
    "terminado>=0.8.3",
    "tornado>=6.2.0",
    "traitlets>=5.6.0",
    "websocket-client",
]
files = [
    {file = "jupyter_server-2.7.0-py3-none-any.whl", hash = "sha256:6a77912aff643e53fa14bdb2634884b52b784a4be77ce8e93f7283faed0f0849"},
    {file = "jupyter_server-2.7.0.tar.gz", hash = "sha256:36da0a266d31a41ac335a366c88933c17dfa5bb817a48f5c02c16d303bc9477f"},
]

[[package]]
name = "jupyter-server-terminals"
version = "0.4.4"
requires_python = ">=3.8"
summary = "A Jupyter Server Extension Providing Terminals."
dependencies = [
    "pywinpty>=2.0.3; os_name == \"nt\"",
    "terminado>=0.8.3",
]
files = [
    {file = "jupyter_server_terminals-0.4.4-py3-none-any.whl", hash = "sha256:75779164661cec02a8758a5311e18bb8eb70c4e86c6b699403100f1585a12a36"},
    {file = "jupyter_server_terminals-0.4.4.tar.gz", hash = "sha256:57ab779797c25a7ba68e97bcfb5d7740f2b5e8a83b5e8102b10438041a7eac5d"},
]

[[package]]
name = "jupyterlab"
version = "4.0.4"
requires_python = ">=3.8"
summary = "JupyterLab computational environment"
dependencies = [
    "async-lru>=1.0.0",
    "ipykernel",
    "jinja2>=3.0.3",
    "jupyter-core",
    "jupyter-lsp>=2.0.0",
    "jupyter-server<3,>=2.4.0",
    "jupyterlab-server<3,>=2.19.0",
    "notebook-shim>=0.2",
    "packaging",
    "tomli; python_version < \"3.11\"",
    "tornado>=6.2.0",
    "traitlets",
]
files = [
    {file = "jupyterlab-4.0.4-py3-none-any.whl", hash = "sha256:23eef35d22be8f2ad9b873ec41ceb2e8c3b0dc8ae740c0f973e2de09e587530f"},
    {file = "jupyterlab-4.0.4.tar.gz", hash = "sha256:049449a56d93202ed204e0e86f96f5a3447a08cfc09fb012fd239e178651cb34"},
]

[[package]]
name = "jupyterlab-pygments"
version = "0.2.2"
requires_python = ">=3.7"
summary = "Pygments theme using JupyterLab CSS variables"
files = [
    {file = "jupyterlab_pygments-0.2.2-py2.py3-none-any.whl", hash = "sha256:2405800db07c9f770863bcf8049a529c3dd4d3e28536638bd7c1c01d2748309f"},
    {file = "jupyterlab_pygments-0.2.2.tar.gz", hash = "sha256:7405d7fde60819d905a9fa8ce89e4cd830e318cdad22a0030f7a901da705585d"},
]

[[package]]
name = "jupyterlab-server"
version = "2.24.0"
requires_python = ">=3.7"
summary = "A set of server components for JupyterLab and JupyterLab like applications."
dependencies = [
    "babel>=2.10",
    "jinja2>=3.0.3",
    "json5>=0.9.0",
    "jsonschema>=4.17.3",
    "jupyter-server<3,>=1.21",
    "packaging>=21.3",
    "requests>=2.28",
]
files = [
    {file = "jupyterlab_server-2.24.0-py3-none-any.whl", hash = "sha256:5f077e142bb8dc9b843d960f940c513581bceca3793a0d80f9c67d9522c4e876"},
    {file = "jupyterlab_server-2.24.0.tar.gz", hash = "sha256:4e6f99e0a5579bbbc32e449c4dbb039561d4f1a7827d5733273ed56738f21f07"},
]

[[package]]
name = "keyring"
version = "23.9.3"
requires_python = ">=3.7"
summary = "Store and access your passwords safely."
dependencies = [
    "SecretStorage>=3.2; sys_platform == \"linux\"",
    "jaraco-classes",
    "jeepney>=0.4.2; sys_platform == \"linux\"",
    "pywin32-ctypes!=0.1.0,!=0.1.1; sys_platform == \"win32\"",
]
files = [
    {file = "keyring-23.9.3-py3-none-any.whl", hash = "sha256:69732a15cb1433bdfbc3b980a8a36a04878a6cfd7cb99f497b573f31618001c0"},
    {file = "keyring-23.9.3.tar.gz", hash = "sha256:69b01dd83c42f590250fe7a1f503fc229b14de83857314b1933a3ddbf595c4a5"},
]

[[package]]
name = "lazy-object-proxy"
version = "1.9.0"
requires_python = ">=3.7"
summary = "A fast and thorough lazy object proxy."
files = [
    {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"},
    {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"},
    {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"},
    {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"},
    {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"},
    {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"},
]

[[package]]
name = "lxml"
version = "4.9.3"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*"
summary = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API."
files = [
    {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"},
    {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"},
    {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"},
    {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"},
    {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"},
    {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"},
    {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"},
    {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"},
    {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"},
    {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"},
    {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"},
    {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"},
    {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"},
    {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"},
    {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"},
    {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"},
    {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"},
    {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"},
    {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"},
    {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"},
    {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"},
    {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"},
    {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"},
    {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"},
    {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"},
    {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"},
    {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"},
    {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"},
    {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"},
    {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"},
    {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"},
    {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"},
    {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"},
    {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"},
    {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"},
    {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"},
    {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"},
    {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"},
    {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"},
    {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"},
    {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"},
    {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"},
    {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"},
    {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"},
    {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"},
    {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"},
    {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"},
    {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"},
    {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"},
    {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"},
    {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"},
    {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"},
    {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"},
    {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"},
    {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"},
    {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"},
    {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"},
    {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"},
    {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"},
    {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"},
    {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"},
    {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"},
    {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"},
    {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"},
    {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"},
    {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"},
    {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"},
    {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"},
    {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"},
    {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"},
    {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"},
    {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"},
    {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"},
    {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"},
    {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"},
    {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"},
    {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"},
    {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"},
    {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"},
    {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"},
    {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"},
    {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"},
    {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"},
    {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"},
    {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"},
    {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"},
    {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"},
    {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"},
    {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"},
    {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"},
    {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"},
    {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"},
]

[[package]]
name = "markdown"
version = "3.3.7"
requires_python = ">=3.6"
summary = "Python implementation of Markdown."
dependencies = [
    "importlib-metadata>=4.4; python_version < \"3.10\"",
]
files = [
    {file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"},
    {file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"},
]

[[package]]
name = "markdown-it-py"
version = "2.2.0"
requires_python = ">=3.7"
summary = "Python port of markdown-it. Markdown parsing, done right!"
dependencies = [
    "mdurl~=0.1",
]
files = [
    {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"},
    {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"},
]

[[package]]
name = "markupsafe"
version = "2.1.3"
requires_python = ">=3.7"
summary = "Safely add untrusted strings to HTML/XML markup."
files = [
    {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"},
    {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"},
    {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"},
    {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"},
    {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"},
    {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"},
    {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"},
]

[[package]]
name = "matplotlib-inline"
version = "0.1.6"
requires_python = ">=3.5"
summary = "Inline Matplotlib backend for Jupyter"
dependencies = [
    "traitlets",
]
files = [
    {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"},
    {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"},
]

[[package]]
name = "mccabe"
version = "0.7.0"
requires_python = ">=3.6"
summary = "McCabe checker, plugin for flake8"
files = [
    {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
    {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
]

[[package]]
name = "mdformat"
version = "0.7.16"
requires_python = ">=3.7"
summary = "CommonMark compliant Markdown formatter"
dependencies = [
    "markdown-it-py<3.0.0,>=1.0.0",
    "tomli>=1.1.0; python_version < \"3.11\"",
]
files = [
    {file = "mdformat-0.7.16-py3-none-any.whl", hash = "sha256:76398d03baa394f331fb560fd0aed8257cf77b65b1c8146b92d395af16253662"},
    {file = "mdformat-0.7.16.tar.gz", hash = "sha256:99b105033207d2ab70ba1ced8e07327ed4ef1e0a6bc1c7c00207ea73ab502782"},
]

[[package]]
name = "mdformat-admon"
version = "1.0.2"
requires_python = ">=3.8.0"
summary = "An mdformat plugin for admonitions."
dependencies = [
    "mdformat>=0.7.16",
    "mdit-py-plugins>=0.4.0",
]
files = [
    {file = "mdformat_admon-1.0.2-py3-none-any.whl", hash = "sha256:1ab208bd1bc95122b4eca16aa65f42b4c1cf9ea579201dd946dfc40a4cb005b8"},
    {file = "mdformat_admon-1.0.2.tar.gz", hash = "sha256:95b9397d88d1cb7935f976107a93993c2d029f044a0a8794dfaa379abd815c56"},
]

[[package]]
name = "mdformat-beautysh"
version = "0.1.1"
requires_python = ">=3.6,<4.0"
summary = "Mdformat plugin to beautify Bash scripts"
dependencies = [
    "beautysh>=6.0.0",
    "mdformat>=0.3.0",
]
files = [
    {file = "mdformat-beautysh-0.1.1.tar.gz", hash = "sha256:b63a0e3adfc29238917b5d163483952f9326f7737cbe3137d3c6c512daf70789"},
    {file = "mdformat_beautysh-0.1.1-py3-none-any.whl", hash = "sha256:23e52dc93ce4cdee12033766a6146f656c72095f74bc80a2bdfde1974a50ee72"},
]

[[package]]
name = "mdformat-black"
version = "0.1.1"
requires_python = ">=3.6,<4.0"
summary = "Mdformat plugin to Blacken Python code blocks"
dependencies = [
    "black",
    "mdformat>=0.3.0",
]
files = [
    {file = "mdformat-black-0.1.1.tar.gz", hash = "sha256:57cad92aee314b87dee52a795cdb52469ab166589d2771e3ad3dd19db907ab62"},
    {file = "mdformat_black-0.1.1-py3-none-any.whl", hash = "sha256:92a7f83779428ca04e939fcbd196ef6340bf9c83f33b2c50d4d3bb734a63d7b2"},
]

[[package]]
name = "mdformat-config"
version = "0.1.3"
requires_python = ">=3.6,<4.0"
summary = "Mdformat plugin to beautify configuration and data-serialization formats"
dependencies = [
    "mdformat>=0.3.0",
    "ruamel-yaml>=0.16.0",
    "toml>=0.10.0",
]
files = [
    {file = "mdformat-config-0.1.3.tar.gz", hash = "sha256:0af65deef832886e9a47df126d1a083f278e47ca631fc5f5750adfd7b84239c4"},
    {file = "mdformat_config-0.1.3-py3-none-any.whl", hash = "sha256:a3f99eaf9970ee473be8cb459e323545781183327cae9bf070d2d3fb421dfd13"},
]

[[package]]
name = "mdformat-configurable-black"
version = "0.0.1"
requires_python = ">=3.7"
summary = "mdformat-configurable-black plugin"
dependencies = [
    "black",
    "markdown-it-py",
    "mdformat",
]
files = [
    {file = "mdformat-configurable-black-0.0.1.tar.gz", hash = "sha256:30c9c5cbe8b0971d49473856580b1c40e261f6cef2c0db3d1d4344c6581110fd"},
    {file = "mdformat_configurable_black-0.0.1-py3-none-any.whl", hash = "sha256:040d383efd3572e22eb769d219e966615ef514d6a4b014f43a78ad2782f5cae2"},
]

[[package]]
name = "mdformat-footnote"
version = "0.1.1"
requires_python = ">=3.7"
summary = "An mdformat plugin for parsing/validating footnotes"
dependencies = [
    "mdformat<0.8.0,>=0.7.8",
    "mdit-py-plugins",
]
files = [
    {file = "mdformat_footnote-0.1.1-py3-none-any.whl", hash = "sha256:30063aaa0f74c36257c2e80fa0cf00d7c71a5277f27e98109e8765ae8678a95b"},
    {file = "mdformat_footnote-0.1.1.tar.gz", hash = "sha256:3b85c4c84119f15f0b651df89c99a4f6f119fc46dca6b33f7edf4f09655d1126"},
]

[[package]]
name = "mdformat-frontmatter"
version = "2.0.1"
requires_python = ">=3.7"
summary = "An mdformat plugin for parsing / ignoring frontmatter."
dependencies = [
    "mdformat<0.8.0,>=0.7.0",
    "mdit-py-plugins",
    "ruamel-yaml",
]
files = [
    {file = "mdformat_frontmatter-2.0.1-py3-none-any.whl", hash = "sha256:354143935a103d6049239f5c2df288c80d0fbea8f7dd9e535ccc180e8c5aa235"},
    {file = "mdformat_frontmatter-2.0.1.tar.gz", hash = "sha256:a05c188ba2f483ab434b4e46e312c1a2ccf145e9ab95e3f493f8967c182ffd5c"},
]

[[package]]
name = "mdformat-gfm"
version = "0.3.0"
requires_python = ">=3.6.1,<4.0.0"
summary = "Mdformat plugin for GitHub Flavored Markdown compatibility"
dependencies = [
    "markdown-it-py>=0.5.8",
    "mdformat-tables>=0.4.0",
    "mdformat<0.8.0,>=0.7.0",
    "mdit-py-plugins>=0.2.0",
]
files = [
    {file = "mdformat-gfm-0.3.0.tar.gz", hash = "sha256:bceb7b320607fdf245b439c23097ce55574a0bfe1199a9e1a1cc868dcfecdd6b"},
    {file = "mdformat_gfm-0.3.0-py3-none-any.whl", hash = "sha256:29cb6c37655245285ac4ddc00f3225a5ba4b6c550223d81c0b4f14269c4956fd"},
]

[[package]]
name = "mdformat-tables"
version = "0.4.1"
requires_python = ">=3.6.1"
summary = "An mdformat plugin for rendering tables."
dependencies = [
    "mdformat<0.8.0,>=0.7.5",
]
files = [
    {file = "mdformat_tables-0.4.1-py3-none-any.whl", hash = "sha256:981f3dc7350027f78e3fd6a5fe8a16e123eec423af2d140e588d855751501019"},
    {file = "mdformat_tables-0.4.1.tar.gz", hash = "sha256:3024e88e9d29d7b8bb07fd6b59c9d5dcf14d2060122be29e30e72d27b65d7da9"},
]

[[package]]
name = "mdformat-web"
version = "0.1.0"
requires_python = ">=3.6,<4.0"
summary = "Mdformat plugin to format JS, CSS, HTML and XML code blocks"
dependencies = [
    "beautifulsoup4[lxml]<5.0.0,>=4.9.3",
    "cssbeautifier<2.0.0,>=1.13.0",
    "jsbeautifier<2.0.0,>=1.13.0",
    "mdformat>=0.3.5",
]
files = [
    {file = "mdformat-web-0.1.0.tar.gz", hash = "sha256:1a18d9d06e44cc476bdf73b83e5333862f5f5c2de5f979ebd8c86ff7989dbabd"},
    {file = "mdformat_web-0.1.0-py3-none-any.whl", hash = "sha256:a6586e01ada50f5e798022a1b88ec6c9d7fc3e5bb782c4f445446172dfb1e762"},
]

[[package]]
name = "mdit-py-plugins"
version = "0.4.0"
requires_python = ">=3.8"
summary = "Collection of plugins for markdown-it-py"
dependencies = [
    "markdown-it-py<4.0.0,>=1.0.0",
]
files = [
    {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"},
    {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"},
]

[[package]]
name = "mdurl"
version = "0.1.2"
requires_python = ">=3.7"
summary = "Markdown URL utilities"
files = [
    {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
    {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
]

[[package]]
name = "mdx-truly-sane-lists"
version = "1.3"
summary = "Extension for Python-Markdown that makes lists truly sane. Custom indents for nested lists and fix for messy linebreaks."
dependencies = [
    "Markdown>=2.6",
]
files = [
    {file = "mdx_truly_sane_lists-1.3-py3-none-any.whl", hash = "sha256:b9546a4c40ff8f1ab692f77cee4b6bfe8ddf9cccf23f0a24e71f3716fe290a37"},
    {file = "mdx_truly_sane_lists-1.3.tar.gz", hash = "sha256:b661022df7520a1e113af7c355c62216b384c867e4f59fb8ee7ad511e6e77f45"},
]

[[package]]
name = "mergedeep"
version = "1.3.4"
requires_python = ">=3.6"
summary = "A deep merge function for 🐍."
files = [
    {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"},
    {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"},
]

[[package]]
name = "mike"
version = "1.2.0.dev0"
git = "https://github.com/jimporter/mike.git"
ref = "master"
revision = "be1aafe244bc86172fbce52a903c9ab83e2e4a26"
summary = "Manage multiple versions of your MkDocs-powered documentation"
dependencies = [
    "importlib-metadata",
    "importlib-resources",
    "jinja2>=2.7",
    "mkdocs>=1.0",
    "pyyaml>=5.1",
    "verspec",
]

[[package]]
name = "mistune"
version = "3.0.1"
requires_python = ">=3.7"
summary = "A sane and fast Markdown parser with useful plugins and renderers"
files = [
    {file = "mistune-3.0.1-py3-none-any.whl", hash = "sha256:b9b3e438efbb57c62b5beb5e134dab664800bdf1284a7ee09e8b12b13eb1aac6"},
    {file = "mistune-3.0.1.tar.gz", hash = "sha256:e912116c13aa0944f9dc530db38eb88f6a77087ab128f49f84a48f4c05ea163c"},
]

[[package]]
name = "mkdocs"
version = "1.3.1"
requires_python = ">=3.6"
summary = "Project documentation with Markdown."
dependencies = [
    "Jinja2>=2.10.2",
    "Markdown<3.4,>=3.2.1",
    "PyYAML>=3.10",
    "click>=3.3",
    "ghp-import>=1.0",
    "importlib-metadata>=4.3",
    "mergedeep>=1.3.4",
    "packaging>=20.5",
    "pyyaml-env-tag>=0.1",
    "watchdog>=2.0",
]
files = [
    {file = "mkdocs-1.3.1-py3-none-any.whl", hash = "sha256:fda92466393127d2da830bc6edc3a625a14b436316d1caf347690648e774c4f0"},
    {file = "mkdocs-1.3.1.tar.gz", hash = "sha256:a41a2ff25ce3bbacc953f9844ba07d106233cd76c88bac1f59cb1564ac0d87ed"},
]

[[package]]
name = "mkdocs-autorefs"
version = "0.5.0"
requires_python = ">=3.8"
summary = "Automatically link across pages in MkDocs."
dependencies = [
    "Markdown>=3.3",
    "mkdocs>=1.1",
]
files = [
    {file = "mkdocs_autorefs-0.5.0-py3-none-any.whl", hash = "sha256:7930fcb8ac1249f10e683967aeaddc0af49d90702af111a5e390e8b20b3d97ff"},
    {file = "mkdocs_autorefs-0.5.0.tar.gz", hash = "sha256:9a5054a94c08d28855cfab967ada10ed5be76e2bfad642302a610b252c3274c0"},
]

[[package]]
name = "mkdocs-coverage"
version = "1.0.0"
requires_python = ">=3.8"
summary = "MkDocs plugin to integrate your coverage HTML report into your site."
dependencies = [
    "mkdocs>=1.2",
]
files = [
    {file = "mkdocs_coverage-1.0.0-py3-none-any.whl", hash = "sha256:29e3c0fc89d1107ee22a0fbe1a9aa927550f97cf2e2682fcad5672ca3f2e14dd"},
    {file = "mkdocs_coverage-1.0.0.tar.gz", hash = "sha256:3ebe0837c29458f64843c45cbb6618859634326867056d030621ab164649904c"},
]

[[package]]
name = "mkdocs-gen-files"
version = "0.5.0"
requires_python = ">=3.7"
summary = "MkDocs plugin to programmatically generate documentation pages during the build"
dependencies = [
    "mkdocs>=1.0.3",
]
files = [
    {file = "mkdocs_gen_files-0.5.0-py3-none-any.whl", hash = "sha256:7ac060096f3f40bd19039e7277dd3050be9a453c8ac578645844d4d91d7978ea"},
    {file = "mkdocs_gen_files-0.5.0.tar.gz", hash = "sha256:4c7cf256b5d67062a788f6b1d035e157fc1a9498c2399be9af5257d4ff4d19bc"},
]

[[package]]
name = "mkdocs-literate-nav"
version = "0.6.0"
requires_python = ">=3.7"
summary = "MkDocs plugin to specify the navigation in Markdown instead of YAML"
dependencies = [
    "mkdocs>=1.0.3",
]
files = [
    {file = "mkdocs_literate_nav-0.6.0-py3-none-any.whl", hash = "sha256:8c1b84714e5974da5e44e011ec0069275ae7647270c13a679662cf6ffce675a4"},
    {file = "mkdocs_literate_nav-0.6.0.tar.gz", hash = "sha256:81ccbea18163ae8e10bd0bd39237fe70c32a1f2dff6c170779f5d52dd98a0470"},
]

[[package]]
name = "mkdocs-material"
version = "8.5.4"
requires_python = ">=3.7"
summary = "Documentation that simply works"
dependencies = [
    "jinja2>=3.0.2",
    "markdown>=3.2",
    "mkdocs-material-extensions>=1.0.3",
    "mkdocs>=1.3.0",
    "pygments>=2.12",
    "pymdown-extensions>=9.4",
    "requests>=2.26",
]
files = [
    {file = "mkdocs_material-8.5.4-py3-none-any.whl", hash = "sha256:aec2f0f2143109f8388aadf76e6fff749a2b74ebe730d0f674c65b53da89d19d"},
    {file = "mkdocs_material-8.5.4.tar.gz", hash = "sha256:70dc47820d4765b77968b9119f2957d09b4d8d328d950bee4544ff224d5c7b36"},
]

[[package]]
name = "mkdocs-material-extensions"
version = "1.1.1"
requires_python = ">=3.7"
summary = "Extension pack for Python Markdown and MkDocs Material."
files = [
    {file = "mkdocs_material_extensions-1.1.1-py3-none-any.whl", hash = "sha256:e41d9f38e4798b6617ad98ca8f7f1157b1e4385ac1459ca1e4ea219b556df945"},
    {file = "mkdocs_material_extensions-1.1.1.tar.gz", hash = "sha256:9c003da71e2cc2493d910237448c672e00cefc800d3d6ae93d2fc69979e3bd93"},
]

[[package]]
name = "mkdocs-section-index"
version = "0.3.5"
requires_python = ">=3.7"
summary = "MkDocs plugin to allow clickable sections that lead to an index page"
dependencies = [
    "mkdocs>=1.0.3",
]
files = [
    {file = "mkdocs_section_index-0.3.5-py3-none-any.whl", hash = "sha256:1f6359287b0a823d6297cf1cb6c0a49ed75851d0d1cea8b425b207a45ce10141"},
    {file = "mkdocs_section_index-0.3.5.tar.gz", hash = "sha256:fa8b1ce0649326b1873c6460c1df2bb0c4825fd21e3dd416f13ec212d31edf12"},
]

[[package]]
name = "mkdocstrings"
version = "0.22.0"
requires_python = ">=3.7"
summary = "Automatic documentation from sources, for MkDocs."
dependencies = [
    "Jinja2>=2.11.1",
    "Markdown>=3.3",
    "MarkupSafe>=1.1",
    "mkdocs-autorefs>=0.3.1",
    "mkdocs>=1.2",
    "pymdown-extensions>=6.3",
]
files = [
    {file = "mkdocstrings-0.22.0-py3-none-any.whl", hash = "sha256:2d4095d461554ff6a778fdabdca3c00c468c2f1459d469f7a7f622a2b23212ba"},
    {file = "mkdocstrings-0.22.0.tar.gz", hash = "sha256:82a33b94150ebb3d4b5c73bab4598c3e21468c79ec072eff6931c8f3bfc38256"},
]

[[package]]
name = "mkdocstrings-python"
version = "1.3.0"
requires_python = ">=3.8"
summary = "A Python handler for mkdocstrings."
dependencies = [
    "griffe<0.33,>=0.30",
    "mkdocstrings>=0.20",
]
files = [
    {file = "mkdocstrings_python-1.3.0-py3-none-any.whl", hash = "sha256:36c224c86ab77e90e0edfc9fea3307f7d0d245dd7c28f48bbb2203cf6e125530"},
    {file = "mkdocstrings_python-1.3.0.tar.gz", hash = "sha256:f967f84bab530fcc13cc9c02eccf0c18bdb2c3bab5c55fa2045938681eec4fc4"},
]

[[package]]
name = "mkdocstrings"
version = "0.22.0"
extras = ["python"]
requires_python = ">=3.7"
summary = "Automatic documentation from sources, for MkDocs."
dependencies = [
    "mkdocstrings-python>=0.5.2",
    "mkdocstrings==0.22.0",
]
files = [
    {file = "mkdocstrings-0.22.0-py3-none-any.whl", hash = "sha256:2d4095d461554ff6a778fdabdca3c00c468c2f1459d469f7a7f622a2b23212ba"},
    {file = "mkdocstrings-0.22.0.tar.gz", hash = "sha256:82a33b94150ebb3d4b5c73bab4598c3e21468c79ec072eff6931c8f3bfc38256"},
]

[[package]]
name = "more-itertools"
version = "10.1.0"
requires_python = ">=3.8"
summary = "More routines for operating on iterables, beyond itertools"
files = [
    {file = "more-itertools-10.1.0.tar.gz", hash = "sha256:626c369fa0eb37bac0291bce8259b332fd59ac792fa5497b59837309cd5b114a"},
    {file = "more_itertools-10.1.0-py3-none-any.whl", hash = "sha256:64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6"},
]

[[package]]
name = "msgpack"
version = "1.0.5"
summary = "MessagePack serializer"
files = [
    {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:525228efd79bb831cf6830a732e2e80bc1b05436b086d4264814b4b2955b2fa9"},
    {file = "msgpack-1.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4f8d8b3bf1ff2672567d6b5c725a1b347fe838b912772aa8ae2bf70338d5a198"},
    {file = "msgpack-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdc793c50be3f01106245a61b739328f7dccc2c648b501e237f0699fe1395b81"},
    {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5cb47c21a8a65b165ce29f2bec852790cbc04936f502966768e4aae9fa763cb7"},
    {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e42b9594cc3bf4d838d67d6ed62b9e59e201862a25e9a157019e171fbe672dd3"},
    {file = "msgpack-1.0.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:55b56a24893105dc52c1253649b60f475f36b3aa0fc66115bffafb624d7cb30b"},
    {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1967f6129fc50a43bfe0951c35acbb729be89a55d849fab7686004da85103f1c"},
    {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20a97bf595a232c3ee6d57ddaadd5453d174a52594bf9c21d10407e2a2d9b3bd"},
    {file = "msgpack-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d25dd59bbbbb996eacf7be6b4ad082ed7eacc4e8f3d2df1ba43822da9bfa122a"},
    {file = "msgpack-1.0.5-cp310-cp310-win32.whl", hash = "sha256:382b2c77589331f2cb80b67cc058c00f225e19827dbc818d700f61513ab47bea"},
    {file = "msgpack-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:4867aa2df9e2a5fa5f76d7d5565d25ec76e84c106b55509e78c1ede0f152659a"},
    {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9f5ae84c5c8a857ec44dc180a8b0cc08238e021f57abdf51a8182e915e6299f0"},
    {file = "msgpack-1.0.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e6ca5d5699bcd89ae605c150aee83b5321f2115695e741b99618f4856c50898"},
    {file = "msgpack-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5494ea30d517a3576749cad32fa27f7585c65f5f38309c88c6d137877fa28a5a"},
    {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ab2f3331cb1b54165976a9d976cb251a83183631c88076613c6c780f0d6e45a"},
    {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28592e20bbb1620848256ebc105fc420436af59515793ed27d5c77a217477705"},
    {file = "msgpack-1.0.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe5c63197c55bce6385d9aee16c4d0641684628f63ace85f73571e65ad1c1e8d"},
    {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed40e926fa2f297e8a653c954b732f125ef97bdd4c889f243182299de27e2aa9"},
    {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:b2de4c1c0538dcb7010902a2b97f4e00fc4ddf2c8cda9749af0e594d3b7fa3d7"},
    {file = "msgpack-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bf22a83f973b50f9d38e55c6aade04c41ddda19b00c4ebc558930d78eecc64ed"},
    {file = "msgpack-1.0.5-cp311-cp311-win32.whl", hash = "sha256:c396e2cc213d12ce017b686e0f53497f94f8ba2b24799c25d913d46c08ec422c"},
    {file = "msgpack-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c4c68d87497f66f96d50142a2b73b97972130d93677ce930718f68828b382e2"},
    {file = "msgpack-1.0.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a2b031c2e9b9af485d5e3c4520f4220d74f4d222a5b8dc8c1a3ab9448ca79c57"},
    {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f837b93669ce4336e24d08286c38761132bc7ab29782727f8557e1eb21b2080"},
    {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1d46dfe3832660f53b13b925d4e0fa1432b00f5f7210eb3ad3bb9a13c6204a6"},
    {file = "msgpack-1.0.5-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:366c9a7b9057e1547f4ad51d8facad8b406bab69c7d72c0eb6f529cf76d4b85f"},
    {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4c075728a1095efd0634a7dccb06204919a2f67d1893b6aa8e00497258bf926c"},
    {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:f933bbda5a3ee63b8834179096923b094b76f0c7a73c1cfe8f07ad608c58844b"},
    {file = "msgpack-1.0.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:36961b0568c36027c76e2ae3ca1132e35123dcec0706c4b7992683cc26c1320c"},
    {file = "msgpack-1.0.5-cp36-cp36m-win32.whl", hash = "sha256:b5ef2f015b95f912c2fcab19c36814963b5463f1fb9049846994b007962743e9"},
    {file = "msgpack-1.0.5-cp36-cp36m-win_amd64.whl", hash = "sha256:288e32b47e67f7b171f86b030e527e302c91bd3f40fd9033483f2cacc37f327a"},
    {file = "msgpack-1.0.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:137850656634abddfb88236008339fdaba3178f4751b28f270d2ebe77a563b6c"},
    {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c05a4a96585525916b109bb85f8cb6511db1c6f5b9d9cbcbc940dc6b4be944b"},
    {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56a62ec00b636583e5cb6ad313bbed36bb7ead5fa3a3e38938503142c72cba4f"},
    {file = "msgpack-1.0.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef8108f8dedf204bb7b42994abf93882da1159728a2d4c5e82012edd92c9da9f"},
    {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1835c84d65f46900920b3708f5ba829fb19b1096c1800ad60bae8418652a951d"},
    {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:e57916ef1bd0fee4f21c4600e9d1da352d8816b52a599c46460e93a6e9f17086"},
    {file = "msgpack-1.0.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:17358523b85973e5f242ad74aa4712b7ee560715562554aa2134d96e7aa4cbbf"},
    {file = "msgpack-1.0.5-cp37-cp37m-win32.whl", hash = "sha256:cb5aaa8c17760909ec6cb15e744c3ebc2ca8918e727216e79607b7bbce9c8f77"},
    {file = "msgpack-1.0.5-cp37-cp37m-win_amd64.whl", hash = "sha256:ab31e908d8424d55601ad7075e471b7d0140d4d3dd3272daf39c5c19d936bd82"},
    {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:b72d0698f86e8d9ddf9442bdedec15b71df3598199ba33322d9711a19f08145c"},
    {file = "msgpack-1.0.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:379026812e49258016dd84ad79ac8446922234d498058ae1d415f04b522d5b2d"},
    {file = "msgpack-1.0.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:332360ff25469c346a1c5e47cbe2a725517919892eda5cfaffe6046656f0b7bb"},
    {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:476a8fe8fae289fdf273d6d2a6cb6e35b5a58541693e8f9f019bfe990a51e4ba"},
    {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9985b214f33311df47e274eb788a5893a761d025e2b92c723ba4c63936b69b1"},
    {file = "msgpack-1.0.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:48296af57cdb1d885843afd73c4656be5c76c0c6328db3440c9601a98f303d87"},
    {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:addab7e2e1fcc04bd08e4eb631c2a90960c340e40dfc4a5e24d2ff0d5a3b3edb"},
    {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:916723458c25dfb77ff07f4c66aed34e47503b2eb3188b3adbec8d8aa6e00f48"},
    {file = "msgpack-1.0.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:821c7e677cc6acf0fd3f7ac664c98803827ae6de594a9f99563e48c5a2f27eb0"},
    {file = "msgpack-1.0.5-cp38-cp38-win32.whl", hash = "sha256:1c0f7c47f0087ffda62961d425e4407961a7ffd2aa004c81b9c07d9269512f6e"},
    {file = "msgpack-1.0.5-cp38-cp38-win_amd64.whl", hash = "sha256:bae7de2026cbfe3782c8b78b0db9cbfc5455e079f1937cb0ab8d133496ac55e1"},
    {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:20c784e66b613c7f16f632e7b5e8a1651aa5702463d61394671ba07b2fc9e025"},
    {file = "msgpack-1.0.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:266fa4202c0eb94d26822d9bfd7af25d1e2c088927fe8de9033d929dd5ba24c5"},
    {file = "msgpack-1.0.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:18334484eafc2b1aa47a6d42427da7fa8f2ab3d60b674120bce7a895a0a85bdd"},
    {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57e1f3528bd95cc44684beda696f74d3aaa8a5e58c816214b9046512240ef437"},
    {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:586d0d636f9a628ddc6a17bfd45aa5b5efaf1606d2b60fa5d87b8986326e933f"},
    {file = "msgpack-1.0.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a740fa0e4087a734455f0fc3abf5e746004c9da72fbd541e9b113013c8dc3282"},
    {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:3055b0455e45810820db1f29d900bf39466df96ddca11dfa6d074fa47054376d"},
    {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a61215eac016f391129a013c9e46f3ab308db5f5ec9f25811e811f96962599a8"},
    {file = "msgpack-1.0.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:362d9655cd369b08fda06b6657a303eb7172d5279997abe094512e919cf74b11"},
    {file = "msgpack-1.0.5-cp39-cp39-win32.whl", hash = "sha256:ac9dd47af78cae935901a9a500104e2dea2e253207c924cc95de149606dc43cc"},
    {file = "msgpack-1.0.5-cp39-cp39-win_amd64.whl", hash = "sha256:06f5174b5f8ed0ed919da0e62cbd4ffde676a374aba4020034da05fab67b9164"},
    {file = "msgpack-1.0.5.tar.gz", hash = "sha256:c075544284eadc5cddc70f4757331d99dcbc16b2bbd4849d15f8aae4cf36d31c"},
]

[[package]]
name = "mypy"
version = "1.4.1"
requires_python = ">=3.7"
summary = "Optional static typing for Python"
dependencies = [
    "mypy-extensions>=1.0.0",
    "tomli>=1.1.0; python_version < \"3.11\"",
    "typing-extensions>=4.1.0",
]
files = [
    {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"},
    {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"},
    {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"},
    {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"},
    {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"},
    {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"},
    {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"},
    {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"},
    {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"},
    {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"},
    {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"},
    {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"},
    {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"},
    {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"},
    {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"},
    {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"},
    {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"},
    {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"},
    {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"},
    {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"},
    {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"},
    {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"},
    {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"},
    {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"},
    {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"},
    {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"},
]

[[package]]
name = "mypy-extensions"
version = "1.0.0"
requires_python = ">=3.5"
summary = "Type system extensions for programs checked with the mypy type checker."
files = [
    {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
    {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]

[[package]]
name = "nbclient"
version = "0.8.0"
requires_python = ">=3.8.0"
summary = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor."
dependencies = [
    "jupyter-client>=6.1.12",
    "jupyter-core!=5.0.*,>=4.12",
    "nbformat>=5.1",
    "traitlets>=5.4",
]
files = [
    {file = "nbclient-0.8.0-py3-none-any.whl", hash = "sha256:25e861299e5303a0477568557c4045eccc7a34c17fc08e7959558707b9ebe548"},
    {file = "nbclient-0.8.0.tar.gz", hash = "sha256:f9b179cd4b2d7bca965f900a2ebf0db4a12ebff2f36a711cb66861e4ae158e55"},
]

[[package]]
name = "nbconvert"
version = "7.7.3"
requires_python = ">=3.8"
summary = "Converting Jupyter Notebooks"
dependencies = [
    "beautifulsoup4",
    "bleach!=5.0.0",
    "defusedxml",
    "jinja2>=3.0",
    "jupyter-core>=4.7",
    "jupyterlab-pygments",
    "markupsafe>=2.0",
    "mistune<4,>=2.0.3",
    "nbclient>=0.5.0",
    "nbformat>=5.7",
    "packaging",
    "pandocfilters>=1.4.1",
    "pygments>=2.4.1",
    "tinycss2",
    "traitlets>=5.1",
]
files = [
    {file = "nbconvert-7.7.3-py3-none-any.whl", hash = "sha256:3022adadff3f86578a47fab7c2228bb3ca9c56a24345642a22f917f6168b48fc"},
    {file = "nbconvert-7.7.3.tar.gz", hash = "sha256:4a5996bf5f3cd16aa0431897ba1aa4c64842c2079f434b3dc6b8c4b252ef3355"},
]

[[package]]
name = "nbformat"
version = "5.9.2"
requires_python = ">=3.8"
summary = "The Jupyter Notebook format"
dependencies = [
    "fastjsonschema",
    "jsonschema>=2.6",
    "jupyter-core",
    "traitlets>=5.1",
]
files = [
    {file = "nbformat-5.9.2-py3-none-any.whl", hash = "sha256:1c5172d786a41b82bcfd0c23f9e6b6f072e8fb49c39250219e4acfff1efe89e9"},
    {file = "nbformat-5.9.2.tar.gz", hash = "sha256:5f98b5ba1997dff175e77e0c17d5c10a96eaed2cbd1de3533d1fc35d5e111192"},
]

[[package]]
name = "nest-asyncio"
version = "1.5.7"
requires_python = ">=3.5"
summary = "Patch asyncio to allow nested event loops"
files = [
    {file = "nest_asyncio-1.5.7-py3-none-any.whl", hash = "sha256:5301c82941b550b3123a1ea772ba9a1c80bad3a182be8c1a5ae6ad3be57a9657"},
    {file = "nest_asyncio-1.5.7.tar.gz", hash = "sha256:6a80f7b98f24d9083ed24608977c09dd608d83f91cccc24c9d2cba6d10e01c10"},
]

[[package]]
name = "nodeenv"
version = "1.8.0"
requires_python = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
summary = "Node.js virtual environment builder"
dependencies = [
    "setuptools",
]
files = [
    {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"},
    {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"},
]

[[package]]
name = "notebook"
version = "7.0.2"
requires_python = ">=3.8"
summary = "Jupyter Notebook - A web-based notebook environment for interactive computing"
dependencies = [
    "jupyter-server<3,>=2.4.0",
    "jupyterlab-server<3,>=2.22.1",
    "jupyterlab<5,>=4.0.2",
    "notebook-shim<0.3,>=0.2",
    "tornado>=6.2.0",
]
files = [
    {file = "notebook-7.0.2-py3-none-any.whl", hash = "sha256:c77b1499dc9b07ce4f4f26990dcb25b2107b434f2536766b51a72a4228d9a4b6"},
    {file = "notebook-7.0.2.tar.gz", hash = "sha256:d70d6a07418c829bd5f54337ce993b7105261d9026f9d3fe68e9b8aa1a20da9a"},
]

[[package]]
name = "notebook-shim"
version = "0.2.3"
requires_python = ">=3.7"
summary = "A shim layer for notebook traits and config"
dependencies = [
    "jupyter-server<3,>=1.8",
]
files = [
    {file = "notebook_shim-0.2.3-py3-none-any.whl", hash = "sha256:a83496a43341c1674b093bfcebf0fe8e74cbe7eda5fd2bbc56f8e39e1486c0c7"},
    {file = "notebook_shim-0.2.3.tar.gz", hash = "sha256:f69388ac283ae008cd506dda10d0288b09a017d822d5e8c7129a152cbd3ce7e9"},
]

[[package]]
name = "numpy"
version = "1.25.2"
requires_python = ">=3.9"
summary = "Fundamental package for array computing in Python"
files = [
    {file = "numpy-1.25.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:db3ccc4e37a6873045580d413fe79b68e47a681af8db2e046f1dacfa11f86eb3"},
    {file = "numpy-1.25.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:90319e4f002795ccfc9050110bbbaa16c944b1c37c0baeea43c5fb881693ae1f"},
    {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dfe4a913e29b418d096e696ddd422d8a5d13ffba4ea91f9f60440a3b759b0187"},
    {file = "numpy-1.25.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f08f2e037bba04e707eebf4bc934f1972a315c883a9e0ebfa8a7756eabf9e357"},
    {file = "numpy-1.25.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bec1e7213c7cb00d67093247f8c4db156fd03075f49876957dca4711306d39c9"},
    {file = "numpy-1.25.2-cp310-cp310-win32.whl", hash = "sha256:7dc869c0c75988e1c693d0e2d5b26034644399dd929bc049db55395b1379e044"},
    {file = "numpy-1.25.2-cp310-cp310-win_amd64.whl", hash = "sha256:834b386f2b8210dca38c71a6e0f4fd6922f7d3fcff935dbe3a570945acb1b545"},
    {file = "numpy-1.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c5462d19336db4560041517dbb7759c21d181a67cb01b36ca109b2ae37d32418"},
    {file = "numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c5652ea24d33585ea39eb6a6a15dac87a1206a692719ff45d53c5282e66d4a8f"},
    {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d60fbae8e0019865fc4784745814cff1c421df5afee233db6d88ab4f14655a2"},
    {file = "numpy-1.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60e7f0f7f6d0eee8364b9a6304c2845b9c491ac706048c7e8cf47b83123b8dbf"},
    {file = "numpy-1.25.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bb33d5a1cf360304754913a350edda36d5b8c5331a8237268c48f91253c3a364"},
    {file = "numpy-1.25.2-cp311-cp311-win32.whl", hash = "sha256:5883c06bb92f2e6c8181df7b39971a5fb436288db58b5a1c3967702d4278691d"},
    {file = "numpy-1.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:5c97325a0ba6f9d041feb9390924614b60b99209a71a69c876f71052521d42a4"},
    {file = "numpy-1.25.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b79e513d7aac42ae918db3ad1341a015488530d0bb2a6abcbdd10a3a829ccfd3"},
    {file = "numpy-1.25.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb942bfb6f84df5ce05dbf4b46673ffed0d3da59f13635ea9b926af3deb76926"},
    {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e0746410e73384e70d286f93abf2520035250aad8c5714240b0492a7302fdca"},
    {file = "numpy-1.25.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7806500e4f5bdd04095e849265e55de20d8cc4b661b038957354327f6d9b295"},
    {file = "numpy-1.25.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8b77775f4b7df768967a7c8b3567e309f617dd5e99aeb886fa14dc1a0791141f"},
    {file = "numpy-1.25.2-cp39-cp39-win32.whl", hash = "sha256:2792d23d62ec51e50ce4d4b7d73de8f67a2fd3ea710dcbc8563a51a03fb07b01"},
    {file = "numpy-1.25.2-cp39-cp39-win_amd64.whl", hash = "sha256:76b4115d42a7dfc5d485d358728cdd8719be33cc5ec6ec08632a5d6fca2ed380"},
    {file = "numpy-1.25.2-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:1a1329e26f46230bf77b02cc19e900db9b52f398d6722ca853349a782d4cff55"},
    {file = "numpy-1.25.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c3abc71e8b6edba80a01a52e66d83c5d14433cbcd26a40c329ec7ed09f37901"},
    {file = "numpy-1.25.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1b9735c27cea5d995496f46a8b1cd7b408b3f34b6d50459d9ac8fe3a20cc17bf"},
    {file = "numpy-1.25.2.tar.gz", hash = "sha256:fd608e19c8d7c55021dffd43bfe5492fab8cc105cc8986f813f8c3c048b38760"},
]

[[package]]
name = "overrides"
version = "7.4.0"
requires_python = ">=3.6"
summary = "A decorator to automatically detect mismatch when overriding a method."
files = [
    {file = "overrides-7.4.0-py3-none-any.whl", hash = "sha256:3ad24583f86d6d7a49049695efe9933e67ba62f0c7625d53c59fa832ce4b8b7d"},
    {file = "overrides-7.4.0.tar.gz", hash = "sha256:9502a3cca51f4fac40b5feca985b6703a5c1f6ad815588a7ca9e285b9dca6757"},
]

[[package]]
name = "packaging"
version = "23.1"
requires_python = ">=3.7"
summary = "Core utilities for Python packages"
files = [
    {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"},
    {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"},
]

[[package]]
name = "pandas"
version = "2.0.3"
requires_python = ">=3.8"
summary = "Powerful data structures for data analysis, time series, and statistics"
dependencies = [
    "numpy>=1.21.0; python_version >= \"3.10\"",
    "numpy>=1.23.2; python_version >= \"3.11\"",
    "python-dateutil>=2.8.2",
    "pytz>=2020.1",
    "tzdata>=2022.1",
]
files = [
    {file = "pandas-2.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e4c7c9f27a4185304c7caf96dc7d91bc60bc162221152de697c98eb0b2648dd8"},
    {file = "pandas-2.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f167beed68918d62bffb6ec64f2e1d8a7d297a038f86d4aed056b9493fca407f"},
    {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce0c6f76a0f1ba361551f3e6dceaff06bde7514a374aa43e33b588ec10420183"},
    {file = "pandas-2.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba619e410a21d8c387a1ea6e8a0e49bb42216474436245718d7f2e88a2f8d7c0"},
    {file = "pandas-2.0.3-cp310-cp310-win32.whl", hash = "sha256:3ef285093b4fe5058eefd756100a367f27029913760773c8bf1d2d8bebe5d210"},
    {file = "pandas-2.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:9ee1a69328d5c36c98d8e74db06f4ad518a1840e8ccb94a4ba86920986bb617e"},
    {file = "pandas-2.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b084b91d8d66ab19f5bb3256cbd5ea661848338301940e17f4492b2ce0801fe8"},
    {file = "pandas-2.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:37673e3bdf1551b95bf5d4ce372b37770f9529743d2498032439371fc7b7eb26"},
    {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9cb1e14fdb546396b7e1b923ffaeeac24e4cedd14266c3497216dd4448e4f2d"},
    {file = "pandas-2.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9cd88488cceb7635aebb84809d087468eb33551097d600c6dad13602029c2df"},
    {file = "pandas-2.0.3-cp311-cp311-win32.whl", hash = "sha256:694888a81198786f0e164ee3a581df7d505024fbb1f15202fc7db88a71d84ebd"},
    {file = "pandas-2.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:6a21ab5c89dcbd57f78d0ae16630b090eec626360085a4148693def5452d8a6b"},
    {file = "pandas-2.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9e4da0d45e7f34c069fe4d522359df7d23badf83abc1d1cef398895822d11061"},
    {file = "pandas-2.0.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:32fca2ee1b0d93dd71d979726b12b61faa06aeb93cf77468776287f41ff8fdc5"},
    {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:258d3624b3ae734490e4d63c430256e716f488c4fcb7c8e9bde2d3aa46c29089"},
    {file = "pandas-2.0.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eae3dc34fa1aa7772dd3fc60270d13ced7346fcbcfee017d3132ec625e23bb0"},
    {file = "pandas-2.0.3-cp38-cp38-win32.whl", hash = "sha256:f3421a7afb1a43f7e38e82e844e2bca9a6d793d66c1a7f9f0ff39a795bbc5e02"},
    {file = "pandas-2.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:69d7f3884c95da3a31ef82b7618af5710dba95bb885ffab339aad925c3e8ce78"},
    {file = "pandas-2.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5247fb1ba347c1261cbbf0fcfba4a3121fbb4029d95d9ef4dc45406620b25c8b"},
    {file = "pandas-2.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:81af086f4543c9d8bb128328b5d32e9986e0c84d3ee673a2ac6fb57fd14f755e"},
    {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1994c789bf12a7c5098277fb43836ce090f1073858c10f9220998ac74f37c69b"},
    {file = "pandas-2.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ec591c48e29226bcbb316e0c1e9423622bc7a4eaf1ef7c3c9fa1a3981f89641"},
    {file = "pandas-2.0.3-cp39-cp39-win32.whl", hash = "sha256:04dbdbaf2e4d46ca8da896e1805bc04eb85caa9a82e259e8eed00254d5e0c682"},
    {file = "pandas-2.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:1168574b036cd8b93abc746171c9b4f1b83467438a5e45909fed645cf8692dbc"},
    {file = "pandas-2.0.3.tar.gz", hash = "sha256:c02f372a88e0d17f36d3093a644c73cfc1788e876a7c4bcb4020a77512e2043c"},
]

[[package]]
name = "pandas-stubs"
version = "2.0.2.230605"
requires_python = ">=3.8"
summary = "Type annotations for pandas"
dependencies = [
    "numpy>=1.24.3",
    "types-pytz>=2022.1.1",
]
files = [
    {file = "pandas_stubs-2.0.2.230605-py3-none-any.whl", hash = "sha256:39106b602f3cb6dc5f728b84e1b32bde6ecf41ee34ee714c66228009609fbada"},
    {file = "pandas_stubs-2.0.2.230605.tar.gz", hash = "sha256:624c7bb06d38145a44b61be459ccd19b038e0bf20364a025ecaab78fea65e858"},
]

[[package]]
name = "pandocfilters"
version = "1.5.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
summary = "Utilities for writing pandoc filters in python"
files = [
    {file = "pandocfilters-1.5.0-py2.py3-none-any.whl", hash = "sha256:33aae3f25fd1a026079f5d27bdd52496f0e0803b3469282162bafdcbdf6ef14f"},
    {file = "pandocfilters-1.5.0.tar.gz", hash = "sha256:0b679503337d233b4339a817bfc8c50064e2eff681314376a47cb582305a7a38"},
]

[[package]]
name = "parso"
version = "0.8.3"
requires_python = ">=3.6"
summary = "A Python Parser"
files = [
    {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
    {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
]

[[package]]
name = "pathspec"
version = "0.11.2"
requires_python = ">=3.7"
summary = "Utility library for gitignore style pattern matching of file paths."
files = [
    {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"},
    {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"},
]

[[package]]
name = "pdm"
version = "2.8.0"
requires_python = ">=3.7"
summary = "A modern Python package and dependency manager supporting the latest PEP standards"
dependencies = [
    "blinker",
    "cachecontrol[filecache]>=0.13.0",
    "certifi",
    "findpython>=0.3.0",
    "installer<0.8,>=0.7",
    "packaging!=22.0,>=20.9",
    "platformdirs",
    "pyproject-hooks",
    "python-dotenv>=0.15",
    "requests-toolbelt",
    "resolvelib>=1.0.1",
    "rich>=12.3.0",
    "shellingham>=1.3.2",
    "tomli>=1.1.0; python_version < \"3.11\"",
    "tomlkit<1,>=0.11.1",
    "unearth>=0.9.0",
    "virtualenv>=20",
]
files = [
    {file = "pdm-2.8.0-py3-none-any.whl", hash = "sha256:5ddd0921de8054abaeb70149b63a0c29dfa5d12c561b3a774cf04c43a85f6f08"},
    {file = "pdm-2.8.0.tar.gz", hash = "sha256:060b1628fda465f2c41e064d212ca9eba630c346a3305e115ae23a4c2cf024da"},
]

[[package]]
name = "pexpect"
version = "4.8.0"
summary = "Pexpect allows easy control of interactive console applications."
dependencies = [
    "ptyprocess>=0.5",
]
files = [
    {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
    {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
]

[[package]]
name = "pickleshare"
version = "0.7.5"
summary = "Tiny 'shelve'-like database with concurrency support"
files = [
    {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
    {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
]

[[package]]
name = "pkginfo"
version = "1.9.6"
requires_python = ">=3.6"
summary = "Query metadata from sdists / bdists / installed packages."
files = [
    {file = "pkginfo-1.9.6-py3-none-any.whl", hash = "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546"},
    {file = "pkginfo-1.9.6.tar.gz", hash = "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"},
]

[[package]]
name = "platformdirs"
version = "3.10.0"
requires_python = ">=3.7"
summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
files = [
    {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"},
    {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"},
]

[[package]]
name = "pluggy"
version = "1.2.0"
requires_python = ">=3.7"
summary = "plugin and hook calling mechanisms for python"
files = [
    {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"},
    {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"},
]

[[package]]
name = "pre-commit"
version = "3.3.3"
requires_python = ">=3.8"
summary = "A framework for managing and maintaining multi-language pre-commit hooks."
dependencies = [
    "cfgv>=2.0.0",
    "identify>=1.0.0",
    "nodeenv>=0.11.1",
    "pyyaml>=5.1",
    "virtualenv>=20.10.0",
]
files = [
    {file = "pre_commit-3.3.3-py2.py3-none-any.whl", hash = "sha256:10badb65d6a38caff29703362271d7dca483d01da88f9d7e05d0b97171c136cb"},
    {file = "pre_commit-3.3.3.tar.gz", hash = "sha256:a2256f489cd913d575c145132ae196fe335da32d91a8294b7afe6622335dd023"},
]

[[package]]
name = "prometheus-client"
version = "0.17.1"
requires_python = ">=3.6"
summary = "Python client for the Prometheus monitoring system."
files = [
    {file = "prometheus_client-0.17.1-py3-none-any.whl", hash = "sha256:e537f37160f6807b8202a6fc4764cdd19bac5480ddd3e0d463c3002b34462101"},
    {file = "prometheus_client-0.17.1.tar.gz", hash = "sha256:21e674f39831ae3f8acde238afd9a27a37d0d2fb5a28ea094f0ce25d2cbf2091"},
]

[[package]]
name = "prompt-toolkit"
version = "3.0.39"
requires_python = ">=3.7.0"
summary = "Library for building powerful interactive command lines in Python"
dependencies = [
    "wcwidth",
]
files = [
    {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"},
    {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"},
]

[[package]]
name = "psutil"
version = "5.9.5"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
summary = "Cross-platform lib for process and system monitoring in Python."
files = [
    {file = "psutil-5.9.5-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:be8929ce4313f9f8146caad4272f6abb8bf99fc6cf59344a3167ecd74f4f203f"},
    {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:ab8ed1a1d77c95453db1ae00a3f9c50227ebd955437bcf2a574ba8adbf6a74d5"},
    {file = "psutil-5.9.5-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:4aef137f3345082a3d3232187aeb4ac4ef959ba3d7c10c33dd73763fbc063da4"},
    {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:ea8518d152174e1249c4f2a1c89e3e6065941df2fa13a1ab45327716a23c2b48"},
    {file = "psutil-5.9.5-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:acf2aef9391710afded549ff602b5887d7a2349831ae4c26be7c807c0a39fac4"},
    {file = "psutil-5.9.5-cp27-none-win32.whl", hash = "sha256:5b9b8cb93f507e8dbaf22af6a2fd0ccbe8244bf30b1baad6b3954e935157ae3f"},
    {file = "psutil-5.9.5-cp27-none-win_amd64.whl", hash = "sha256:8c5f7c5a052d1d567db4ddd231a9d27a74e8e4a9c3f44b1032762bd7b9fdcd42"},
    {file = "psutil-5.9.5-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:3c6f686f4225553615612f6d9bc21f1c0e305f75d7d8454f9b46e901778e7217"},
    {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a7dd9997128a0d928ed4fb2c2d57e5102bb6089027939f3b722f3a210f9a8da"},
    {file = "psutil-5.9.5-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89518112647f1276b03ca97b65cc7f64ca587b1eb0278383017c2a0dcc26cbe4"},
    {file = "psutil-5.9.5-cp36-abi3-win32.whl", hash = "sha256:104a5cc0e31baa2bcf67900be36acde157756b9c44017b86b2c049f11957887d"},
    {file = "psutil-5.9.5-cp36-abi3-win_amd64.whl", hash = "sha256:b258c0c1c9d145a1d5ceffab1134441c4c5113b2417fafff7315a917a026c3c9"},
    {file = "psutil-5.9.5-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:c607bb3b57dc779d55e1554846352b4e358c10fff3abf3514a7a6601beebdb30"},
    {file = "psutil-5.9.5.tar.gz", hash = "sha256:5410638e4df39c54d957fc51ce03048acd8e6d60abc0f5107af51e5fb566eb3c"},
]

[[package]]
name = "ptyprocess"
version = "0.7.0"
summary = "Run a subprocess in a pseudo terminal"
files = [
    {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
    {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
]

[[package]]
name = "pure-eval"
version = "0.2.2"
summary = "Safely evaluate AST nodes without side effects"
files = [
    {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"},
    {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"},
]

[[package]]
name = "py4j"
version = "0.10.9.7"
summary = "Enables Python programs to dynamically access arbitrary Java objects"
files = [
    {file = "py4j-0.10.9.7-py2.py3-none-any.whl", hash = "sha256:85defdfd2b2376eb3abf5ca6474b51ab7e0de341c75a02f46dc9b5976f5a5c1b"},
    {file = "py4j-0.10.9.7.tar.gz", hash = "sha256:0b6e5315bb3ada5cf62ac651d107bb2ebc02def3dee9d9548e3baac644ea8dbb"},
]

[[package]]
name = "pyarrow"
version = "12.0.1"
requires_python = ">=3.7"
summary = "Python library for Apache Arrow"
dependencies = [
    "numpy>=1.16.6",
]
files = [
    {file = "pyarrow-12.0.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:6d288029a94a9bb5407ceebdd7110ba398a00412c5b0155ee9813a40d246c5df"},
    {file = "pyarrow-12.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345e1828efdbd9aa4d4de7d5676778aba384a2c3add896d995b23d368e60e5af"},
    {file = "pyarrow-12.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d6009fdf8986332b2169314da482baed47ac053311c8934ac6651e614deacd6"},
    {file = "pyarrow-12.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d3c4cbbf81e6dd23fe921bc91dc4619ea3b79bc58ef10bce0f49bdafb103daf"},
    {file = "pyarrow-12.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:cdacf515ec276709ac8042c7d9bd5be83b4f5f39c6c037a17a60d7ebfd92c890"},
    {file = "pyarrow-12.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:749be7fd2ff260683f9cc739cb862fb11be376de965a2a8ccbf2693b098db6c7"},
    {file = "pyarrow-12.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6895b5fb74289d055c43db3af0de6e16b07586c45763cb5e558d38b86a91e3a7"},
    {file = "pyarrow-12.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1887bdae17ec3b4c046fcf19951e71b6a619f39fa674f9881216173566c8f718"},
    {file = "pyarrow-12.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2c9cb8eeabbadf5fcfc3d1ddea616c7ce893db2ce4dcef0ac13b099ad7ca082"},
    {file = "pyarrow-12.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:ce4aebdf412bd0eeb800d8e47db854f9f9f7e2f5a0220440acf219ddfddd4f63"},
    {file = "pyarrow-12.0.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:e0d8730c7f6e893f6db5d5b86eda42c0a130842d101992b581e2138e4d5663d3"},
    {file = "pyarrow-12.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43364daec02f69fec89d2315f7fbfbeec956e0d991cbbef471681bd77875c40f"},
    {file = "pyarrow-12.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:051f9f5ccf585f12d7de836e50965b3c235542cc896959320d9776ab93f3b33d"},
    {file = "pyarrow-12.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:be2757e9275875d2a9c6e6052ac7957fbbfc7bc7370e4a036a9b893e96fedaba"},
    {file = "pyarrow-12.0.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:cf812306d66f40f69e684300f7af5111c11f6e0d89d6b733e05a3de44961529d"},
    {file = "pyarrow-12.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:459a1c0ed2d68671188b2118c63bac91eaef6fc150c77ddd8a583e3c795737bf"},
    {file = "pyarrow-12.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85e705e33eaf666bbe508a16fd5ba27ca061e177916b7a317ba5a51bee43384c"},
    {file = "pyarrow-12.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9120c3eb2b1f6f516a3b7a9714ed860882d9ef98c4b17edcdc91d95b7528db60"},
    {file = "pyarrow-12.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:c780f4dc40460015d80fcd6a6140de80b615349ed68ef9adb653fe351778c9b3"},
    {file = "pyarrow-12.0.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:a3c63124fc26bf5f95f508f5d04e1ece8cc23a8b0af2a1e6ab2b1ec3fdc91b24"},
    {file = "pyarrow-12.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b13329f79fa4472324f8d32dc1b1216616d09bd1e77cfb13104dec5463632c36"},
    {file = "pyarrow-12.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb656150d3d12ec1396f6dde542db1675a95c0cc8366d507347b0beed96e87ca"},
    {file = "pyarrow-12.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6251e38470da97a5b2e00de5c6a049149f7b2bd62f12fa5dbb9ac674119ba71a"},
    {file = "pyarrow-12.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:3de26da901216149ce086920547dfff5cd22818c9eab67ebc41e863a5883bac7"},
    {file = "pyarrow-12.0.1.tar.gz", hash = "sha256:cce317fc96e5b71107bf1f9f184d5e54e2bd14bbf3f9a3d62819961f0af86fec"},
]

[[package]]
name = "pycparser"
version = "2.21"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
summary = "C parser in Python"
files = [
    {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
    {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
]

[[package]]
name = "pygments"
version = "2.16.1"
requires_python = ">=3.7"
summary = "Pygments is a syntax highlighting package written in Python."
files = [
    {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"},
    {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"},
]

[[package]]
name = "pylint"
version = "2.17.5"
requires_python = ">=3.7.2"
summary = "python code static checker"
dependencies = [
    "astroid<=2.17.0-dev0,>=2.15.6",
    "colorama>=0.4.5; sys_platform == \"win32\"",
    "dill>=0.2; python_version < \"3.11\"",
    "dill>=0.3.6; python_version >= \"3.11\"",
    "isort<6,>=4.2.5",
    "mccabe<0.8,>=0.6",
    "platformdirs>=2.2.0",
    "tomli>=1.1.0; python_version < \"3.11\"",
    "tomlkit>=0.10.1",
]
files = [
    {file = "pylint-2.17.5-py3-none-any.whl", hash = "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413"},
    {file = "pylint-2.17.5.tar.gz", hash = "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"},
]

[[package]]
name = "pymdown-extensions"
version = "10.1"
requires_python = ">=3.7"
summary = "Extension pack for Python Markdown."
dependencies = [
    "markdown>=3.2",
    "pyyaml",
]
files = [
    {file = "pymdown_extensions-10.1-py3-none-any.whl", hash = "sha256:ef25dbbae530e8f67575d222b75ff0649b1e841e22c2ae9a20bad9472c2207dc"},
    {file = "pymdown_extensions-10.1.tar.gz", hash = "sha256:508009b211373058debb8247e168de4cbcb91b1bff7b5e961b2c3e864e00b195"},
]

[[package]]
name = "pyproject-api"
version = "1.5.3"
requires_python = ">=3.7"
summary = "API to interact with the python pyproject.toml based projects"
dependencies = [
    "packaging>=23.1",
    "tomli>=2.0.1; python_version < \"3.11\"",
]
files = [
    {file = "pyproject_api-1.5.3-py3-none-any.whl", hash = "sha256:14cf09828670c7b08842249c1f28c8ee6581b872e893f81b62d5465bec41502f"},
    {file = "pyproject_api-1.5.3.tar.gz", hash = "sha256:ffb5b2d7cad43f5b2688ab490de7c4d3f6f15e0b819cb588c4b771567c9729eb"},
]

[[package]]
name = "pyproject-hooks"
version = "1.0.0"
requires_python = ">=3.7"
summary = "Wrappers to call pyproject.toml-based build backend hooks."
dependencies = [
    "tomli>=1.1.0; python_version < \"3.11\"",
]
files = [
    {file = "pyproject_hooks-1.0.0-py3-none-any.whl", hash = "sha256:283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8"},
    {file = "pyproject_hooks-1.0.0.tar.gz", hash = "sha256:f271b298b97f5955d53fb12b72c1fb1948c22c1a6b70b315c54cedaca0264ef5"},
]

[[package]]
name = "pyspark"
version = "3.4.1"
requires_python = ">=3.7"
summary = "Apache Spark Python API"
dependencies = [
    "py4j==0.10.9.7",
]
files = [
    {file = "pyspark-3.4.1.tar.gz", hash = "sha256:72cd66ab8cf61a75854e5a753f75bea35ee075c3a96f9de4e2a66d02ec7fc652"},
]

[[package]]
name = "python-dateutil"
version = "2.8.2"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
summary = "Extensions to the standard Python datetime module"
dependencies = [
    "six>=1.5",
]
files = [
    {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"},
    {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"},
]

[[package]]
name = "python-dotenv"
version = "1.0.0"
requires_python = ">=3.8"
summary = "Read key-value pairs from a .env file and set them as environment variables"
files = [
    {file = "python-dotenv-1.0.0.tar.gz", hash = "sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba"},
    {file = "python_dotenv-1.0.0-py3-none-any.whl", hash = "sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"},
]

[[package]]
name = "python-json-logger"
version = "2.0.7"
requires_python = ">=3.6"
summary = "A python library adding a json log formatter"
files = [
    {file = "python-json-logger-2.0.7.tar.gz", hash = "sha256:23e7ec02d34237c5aa1e29a070193a4ea87583bb4e7f8fd06d3de8264c4b2e1c"},
    {file = "python_json_logger-2.0.7-py3-none-any.whl", hash = "sha256:f380b826a991ebbe3de4d897aeec42760035ac760345e57b812938dc8b35e2bd"},
]

[[package]]
name = "pytz"
version = "2023.3"
summary = "World timezone definitions, modern and historical"
files = [
    {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"},
    {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"},
]

[[package]]
name = "pywin32"
version = "306"
summary = "Python for Window Extensions"
files = [
    {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"},
    {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"},
    {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"},
    {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"},
    {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"},
    {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"},
    {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"},
    {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"},
    {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"},
    {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"},
    {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"},
    {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"},
    {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"},
    {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"},
]

[[package]]
name = "pywin32-ctypes"
version = "0.2.2"
requires_python = ">=3.6"
summary = "A (partial) reimplementation of pywin32 using ctypes/cffi"
files = [
    {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"},
    {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"},
]

[[package]]
name = "pywinpty"
version = "2.0.11"
requires_python = ">=3.8"
summary = "Pseudo terminal support for Windows from Python."
files = [
    {file = "pywinpty-2.0.11-cp310-none-win_amd64.whl", hash = "sha256:452f10ac9ff8ab9151aa8cea9e491a9612a12250b1899278c6a56bc184afb47f"},
    {file = "pywinpty-2.0.11-cp311-none-win_amd64.whl", hash = "sha256:6701867d42aec1239bc0fedf49a336570eb60eb886e81763db77ea2b6c533cc3"},
    {file = "pywinpty-2.0.11-cp38-none-win_amd64.whl", hash = "sha256:0ffd287751ad871141dc9724de70ea21f7fc2ff1af50861e0d232cf70739d8c4"},
    {file = "pywinpty-2.0.11-cp39-none-win_amd64.whl", hash = "sha256:e4e7f023c28ca7aa8e1313e53ba80a4d10171fe27857b7e02f99882dfe3e8638"},
    {file = "pywinpty-2.0.11.tar.gz", hash = "sha256:e244cffe29a894876e2cd251306efd0d8d64abd5ada0a46150a4a71c0b9ad5c5"},
]

[[package]]
name = "pyyaml"
version = "6.0.1"
requires_python = ">=3.6"
summary = "YAML parser and emitter for Python"
files = [
    {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
    {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
    {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
    {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
    {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
    {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
    {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
    {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
    {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
    {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
    {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
    {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
    {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
    {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
    {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
    {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
    {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
    {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
    {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
    {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
    {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
    {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
    {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
    {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
    {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
    {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
    {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
    {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
    {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
    {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
    {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
    {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
    {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
    {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
    {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
    {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
    {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
    {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
    {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
    {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
]

[[package]]
name = "pyyaml-env-tag"
version = "0.1"
requires_python = ">=3.6"
summary = "A custom YAML tag for referencing environment variables in YAML files. "
dependencies = [
    "pyyaml",
]
files = [
    {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
    {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
]

[[package]]
name = "pyzmq"
version = "25.1.0"
requires_python = ">=3.6"
summary = "Python bindings for 0MQ"
dependencies = [
    "cffi; implementation_name == \"pypy\"",
]
files = [
    {file = "pyzmq-25.1.0-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:1a6169e69034eaa06823da6a93a7739ff38716142b3596c180363dee729d713d"},
    {file = "pyzmq-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:19d0383b1f18411d137d891cab567de9afa609b214de68b86e20173dc624c101"},
    {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1e931d9a92f628858a50f5bdffdfcf839aebe388b82f9d2ccd5d22a38a789dc"},
    {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:97d984b1b2f574bc1bb58296d3c0b64b10e95e7026f8716ed6c0b86d4679843f"},
    {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:154bddda2a351161474b36dba03bf1463377ec226a13458725183e508840df89"},
    {file = "pyzmq-25.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cb6d161ae94fb35bb518b74bb06b7293299c15ba3bc099dccd6a5b7ae589aee3"},
    {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:90146ab578931e0e2826ee39d0c948d0ea72734378f1898939d18bc9c823fcf9"},
    {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:831ba20b660b39e39e5ac8603e8193f8fce1ee03a42c84ade89c36a251449d80"},
    {file = "pyzmq-25.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3a522510e3434e12aff80187144c6df556bb06fe6b9d01b2ecfbd2b5bfa5c60c"},
    {file = "pyzmq-25.1.0-cp310-cp310-win32.whl", hash = "sha256:be24a5867b8e3b9dd5c241de359a9a5217698ff616ac2daa47713ba2ebe30ad1"},
    {file = "pyzmq-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:5693dcc4f163481cf79e98cf2d7995c60e43809e325b77a7748d8024b1b7bcba"},
    {file = "pyzmq-25.1.0-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:13bbe36da3f8aaf2b7ec12696253c0bf6ffe05f4507985a8844a1081db6ec22d"},
    {file = "pyzmq-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:69511d604368f3dc58d4be1b0bad99b61ee92b44afe1cd9b7bd8c5e34ea8248a"},
    {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a983c8694667fd76d793ada77fd36c8317e76aa66eec75be2653cef2ea72883"},
    {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:332616f95eb400492103ab9d542b69d5f0ff628b23129a4bc0a2fd48da6e4e0b"},
    {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58416db767787aedbfd57116714aad6c9ce57215ffa1c3758a52403f7c68cff5"},
    {file = "pyzmq-25.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:cad9545f5801a125f162d09ec9b724b7ad9b6440151b89645241d0120e119dcc"},
    {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d6128d431b8dfa888bf51c22a04d48bcb3d64431caf02b3cb943269f17fd2994"},
    {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:2b15247c49d8cbea695b321ae5478d47cffd496a2ec5ef47131a9e79ddd7e46c"},
    {file = "pyzmq-25.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:442d3efc77ca4d35bee3547a8e08e8d4bb88dadb54a8377014938ba98d2e074a"},
    {file = "pyzmq-25.1.0-cp311-cp311-win32.whl", hash = "sha256:65346f507a815a731092421d0d7d60ed551a80d9b75e8b684307d435a5597425"},
    {file = "pyzmq-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:8b45d722046fea5a5694cba5d86f21f78f0052b40a4bbbbf60128ac55bfcc7b6"},
    {file = "pyzmq-25.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f45808eda8b1d71308c5416ef3abe958f033fdbb356984fabbfc7887bed76b3f"},
    {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b697774ea8273e3c0460cf0bba16cd85ca6c46dfe8b303211816d68c492e132"},
    {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b324fa769577fc2c8f5efcd429cef5acbc17d63fe15ed16d6dcbac2c5eb00849"},
    {file = "pyzmq-25.1.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:5873d6a60b778848ce23b6c0ac26c39e48969823882f607516b91fb323ce80e5"},
    {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f0d9e7ba6a815a12c8575ba7887da4b72483e4cfc57179af10c9b937f3f9308f"},
    {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:414b8beec76521358b49170db7b9967d6974bdfc3297f47f7d23edec37329b00"},
    {file = "pyzmq-25.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:01f06f33e12497dca86353c354461f75275a5ad9eaea181ac0dc1662da8074fa"},
    {file = "pyzmq-25.1.0-cp36-cp36m-win32.whl", hash = "sha256:b5a07c4f29bf7cb0164664ef87e4aa25435dcc1f818d29842118b0ac1eb8e2b5"},
    {file = "pyzmq-25.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:968b0c737797c1809ec602e082cb63e9824ff2329275336bb88bd71591e94a90"},
    {file = "pyzmq-25.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:47b915ba666c51391836d7ed9a745926b22c434efa76c119f77bcffa64d2c50c"},
    {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5af31493663cf76dd36b00dafbc839e83bbca8a0662931e11816d75f36155897"},
    {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5489738a692bc7ee9a0a7765979c8a572520d616d12d949eaffc6e061b82b4d1"},
    {file = "pyzmq-25.1.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1fc56a0221bdf67cfa94ef2d6ce5513a3d209c3dfd21fed4d4e87eca1822e3a3"},
    {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:75217e83faea9edbc29516fc90c817bc40c6b21a5771ecb53e868e45594826b0"},
    {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3830be8826639d801de9053cf86350ed6742c4321ba4236e4b5568528d7bfed7"},
    {file = "pyzmq-25.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:3575699d7fd7c9b2108bc1c6128641a9a825a58577775ada26c02eb29e09c517"},
    {file = "pyzmq-25.1.0-cp37-cp37m-win32.whl", hash = "sha256:95bd3a998d8c68b76679f6b18f520904af5204f089beebb7b0301d97704634dd"},
    {file = "pyzmq-25.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:dbc466744a2db4b7ca05589f21ae1a35066afada2f803f92369f5877c100ef62"},
    {file = "pyzmq-25.1.0-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:3bed53f7218490c68f0e82a29c92335daa9606216e51c64f37b48eb78f1281f4"},
    {file = "pyzmq-25.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eb52e826d16c09ef87132c6e360e1879c984f19a4f62d8a935345deac43f3c12"},
    {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ddbef8b53cd16467fdbfa92a712eae46dd066aa19780681a2ce266e88fbc7165"},
    {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9301cf1d7fc1ddf668d0abbe3e227fc9ab15bc036a31c247276012abb921b5ff"},
    {file = "pyzmq-25.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e23a8c3b6c06de40bdb9e06288180d630b562db8ac199e8cc535af81f90e64b"},
    {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4a82faae00d1eed4809c2f18b37f15ce39a10a1c58fe48b60ad02875d6e13d80"},
    {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:c8398a1b1951aaa330269c35335ae69744be166e67e0ebd9869bdc09426f3871"},
    {file = "pyzmq-25.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d40682ac60b2a613d36d8d3a0cd14fbdf8e7e0618fbb40aa9fa7b796c9081584"},
    {file = "pyzmq-25.1.0-cp38-cp38-win32.whl", hash = "sha256:33d5c8391a34d56224bccf74f458d82fc6e24b3213fc68165c98b708c7a69325"},
    {file = "pyzmq-25.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:c66b7ff2527e18554030319b1376d81560ca0742c6e0b17ff1ee96624a5f1afd"},
    {file = "pyzmq-25.1.0-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:af56229ea6527a849ac9fb154a059d7e32e77a8cba27e3e62a1e38d8808cb1a5"},
    {file = "pyzmq-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bdca18b94c404af6ae5533cd1bc310c4931f7ac97c148bbfd2cd4bdd62b96253"},
    {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0b6b42f7055bbc562f63f3df3b63e3dd1ebe9727ff0f124c3aa7bcea7b3a00f9"},
    {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c2fc7aad520a97d64ffc98190fce6b64152bde57a10c704b337082679e74f67"},
    {file = "pyzmq-25.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be86a26415a8b6af02cd8d782e3a9ae3872140a057f1cadf0133de685185c02b"},
    {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:851fb2fe14036cfc1960d806628b80276af5424db09fe5c91c726890c8e6d943"},
    {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2a21fec5c3cea45421a19ccbe6250c82f97af4175bc09de4d6dd78fb0cb4c200"},
    {file = "pyzmq-25.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bad172aba822444b32eae54c2d5ab18cd7dee9814fd5c7ed026603b8cae2d05f"},
    {file = "pyzmq-25.1.0-cp39-cp39-win32.whl", hash = "sha256:4d67609b37204acad3d566bb7391e0ecc25ef8bae22ff72ebe2ad7ffb7847158"},
    {file = "pyzmq-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:71c7b5896e40720d30cd77a81e62b433b981005bbff0cb2f739e0f8d059b5d99"},
    {file = "pyzmq-25.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cb27ef9d3bdc0c195b2dc54fcb8720e18b741624686a81942e14c8b67cc61a6"},
    {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0c4fc2741e0513b5d5a12fe200d6785bbcc621f6f2278893a9ca7bed7f2efb7d"},
    {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fc34fdd458ff77a2a00e3c86f899911f6f269d393ca5675842a6e92eea565bae"},
    {file = "pyzmq-25.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8751f9c1442624da391bbd92bd4b072def6d7702a9390e4479f45c182392ff78"},
    {file = "pyzmq-25.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:6581e886aec3135964a302a0f5eb68f964869b9efd1dbafdebceaaf2934f8a68"},
    {file = "pyzmq-25.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5482f08d2c3c42b920e8771ae8932fbaa0a67dff925fc476996ddd8155a170f3"},
    {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7fbcafa3ea16d1de1f213c226005fea21ee16ed56134b75b2dede5a2129e62"},
    {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:adecf6d02b1beab8d7c04bc36f22bb0e4c65a35eb0b4750b91693631d4081c70"},
    {file = "pyzmq-25.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6d39e42a0aa888122d1beb8ec0d4ddfb6c6b45aecb5ba4013c27e2f28657765"},
    {file = "pyzmq-25.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7018289b402ebf2b2c06992813523de61d4ce17bd514c4339d8f27a6f6809492"},
    {file = "pyzmq-25.1.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9e68ae9864d260b18f311b68d29134d8776d82e7f5d75ce898b40a88df9db30f"},
    {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e21cc00e4debe8f54c3ed7b9fcca540f46eee12762a9fa56feb8512fd9057161"},
    {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2f666ae327a6899ff560d741681fdcdf4506f990595201ed39b44278c471ad98"},
    {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f5efcc29056dfe95e9c9db0dfbb12b62db9c4ad302f812931b6d21dd04a9119"},
    {file = "pyzmq-25.1.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:48e5e59e77c1a83162ab3c163fc01cd2eebc5b34560341a67421b09be0891287"},
    {file = "pyzmq-25.1.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:108c96ebbd573d929740d66e4c3d1bdf31d5cde003b8dc7811a3c8c5b0fc173b"},
    {file = "pyzmq-25.1.0.tar.gz", hash = "sha256:80c41023465d36280e801564a69cbfce8ae85ff79b080e1913f6e90481fb8957"},
]

[[package]]
name = "qpd"
version = "0.4.4"
requires_python = ">=3.7"
summary = "Query Pandas Using SQL"
dependencies = [
    "adagio",
    "antlr4-python3-runtime<4.12,>=4.11.1",
    "pandas>=1.2.0",
    "triad>=0.9.0",
]
files = [
    {file = "qpd-0.4.4-py3-none-any.whl", hash = "sha256:fc02b53d990f505353ec495682fbc107dfc06c59e66d2206b5d2db2b5700b629"},
    {file = "qpd-0.4.4.tar.gz", hash = "sha256:e0ed05b88e321ea9935874377bda11339c90f1469f34344e9b41d16b8088e136"},
]

[[package]]
name = "readme-renderer"
version = "40.0"
requires_python = ">=3.8"
summary = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse"
dependencies = [
    "Pygments>=2.5.1",
    "bleach>=2.1.0",
    "docutils>=0.13.1",
]
files = [
    {file = "readme_renderer-40.0-py3-none-any.whl", hash = "sha256:e18feb2a1e7706f2865b81ebb460056d93fb29d69daa10b223c00faa7bd9a00a"},
    {file = "readme_renderer-40.0.tar.gz", hash = "sha256:9f77b519d96d03d7d7dce44977ba543090a14397c4f60de5b6eb5b8048110aa4"},
]

[[package]]
name = "referencing"
version = "0.30.2"
requires_python = ">=3.8"
summary = "JSON Referencing + Python"
dependencies = [
    "attrs>=22.2.0",
    "rpds-py>=0.7.0",
]
files = [
    {file = "referencing-0.30.2-py3-none-any.whl", hash = "sha256:449b6669b6121a9e96a7f9e410b245d471e8d48964c67113ce9afe50c8dd7bdf"},
    {file = "referencing-0.30.2.tar.gz", hash = "sha256:794ad8003c65938edcdbc027f1933215e0d0ccc0291e3ce20a4d87432b59efc0"},
]

[[package]]
name = "requests"
version = "2.31.0"
requires_python = ">=3.7"
summary = "Python HTTP for Humans."
dependencies = [
    "certifi>=2017.4.17",
    "charset-normalizer<4,>=2",
    "idna<4,>=2.5",
    "urllib3<3,>=1.21.1",
]
files = [
    {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
    {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
]

[[package]]
name = "requests-toolbelt"
version = "1.0.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
summary = "A utility belt for advanced users of python-requests"
dependencies = [
    "requests<3.0.0,>=2.0.1",
]
files = [
    {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"},
    {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"},
]

[[package]]
name = "resolvelib"
version = "1.0.1"
summary = "Resolve abstract dependencies into concrete ones"
files = [
    {file = "resolvelib-1.0.1-py2.py3-none-any.whl", hash = "sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf"},
    {file = "resolvelib-1.0.1.tar.gz", hash = "sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309"},
]

[[package]]
name = "rfc3339-validator"
version = "0.1.4"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "A pure python RFC3339 validator"
dependencies = [
    "six",
]
files = [
    {file = "rfc3339_validator-0.1.4-py2.py3-none-any.whl", hash = "sha256:24f6ec1eda14ef823da9e36ec7113124b39c04d50a4d3d3a3c2859577e7791fa"},
    {file = "rfc3339_validator-0.1.4.tar.gz", hash = "sha256:138a2abdf93304ad60530167e51d2dfb9549521a836871b88d7f4695d0022f6b"},
]

[[package]]
name = "rfc3986"
version = "2.0.0"
requires_python = ">=3.7"
summary = "Validating URI References per RFC 3986"
files = [
    {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"},
    {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"},
]

[[package]]
name = "rfc3986-validator"
version = "0.1.1"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "Pure python rfc3986 validator"
files = [
    {file = "rfc3986_validator-0.1.1-py2.py3-none-any.whl", hash = "sha256:2f235c432ef459970b4306369336b9d5dbdda31b510ca1e327636e01f528bfa9"},
    {file = "rfc3986_validator-0.1.1.tar.gz", hash = "sha256:3d44bde7921b3b9ec3ae4e3adca370438eccebc676456449b145d533b240d055"},
]

[[package]]
name = "rich"
version = "13.5.2"
requires_python = ">=3.7.0"
summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
dependencies = [
    "markdown-it-py>=2.2.0",
    "pygments<3.0.0,>=2.13.0",
]
files = [
    {file = "rich-13.5.2-py3-none-any.whl", hash = "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808"},
    {file = "rich-13.5.2.tar.gz", hash = "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39"},
]

[[package]]
name = "rpds-py"
version = "0.9.2"
requires_python = ">=3.8"
summary = "Python bindings to Rust's persistent data structures (rpds)"
files = [
    {file = "rpds_py-0.9.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:ab6919a09c055c9b092798ce18c6c4adf49d24d4d9e43a92b257e3f2548231e7"},
    {file = "rpds_py-0.9.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d55777a80f78dd09410bd84ff8c95ee05519f41113b2df90a69622f5540c4f8b"},
    {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a216b26e5af0a8e265d4efd65d3bcec5fba6b26909014effe20cd302fd1138fa"},
    {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:29cd8bfb2d716366a035913ced99188a79b623a3512292963d84d3e06e63b496"},
    {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:44659b1f326214950a8204a248ca6199535e73a694be8d3e0e869f820767f12f"},
    {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:745f5a43fdd7d6d25a53ab1a99979e7f8ea419dfefebcab0a5a1e9095490ee5e"},
    {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a987578ac5214f18b99d1f2a3851cba5b09f4a689818a106c23dbad0dfeb760f"},
    {file = "rpds_py-0.9.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf4151acb541b6e895354f6ff9ac06995ad9e4175cbc6d30aaed08856558201f"},
    {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:03421628f0dc10a4119d714a17f646e2837126a25ac7a256bdf7c3943400f67f"},
    {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:13b602dc3e8dff3063734f02dcf05111e887f301fdda74151a93dbbc249930fe"},
    {file = "rpds_py-0.9.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fae5cb554b604b3f9e2c608241b5d8d303e410d7dfb6d397c335f983495ce7f6"},
    {file = "rpds_py-0.9.2-cp310-none-win32.whl", hash = "sha256:47c5f58a8e0c2c920cc7783113df2fc4ff12bf3a411d985012f145e9242a2764"},
    {file = "rpds_py-0.9.2-cp310-none-win_amd64.whl", hash = "sha256:4ea6b73c22d8182dff91155af018b11aac9ff7eca085750455c5990cb1cfae6e"},
    {file = "rpds_py-0.9.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:e564d2238512c5ef5e9d79338ab77f1cbbda6c2d541ad41b2af445fb200385e3"},
    {file = "rpds_py-0.9.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f411330a6376fb50e5b7a3e66894e4a39e60ca2e17dce258d53768fea06a37bd"},
    {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e7521f5af0233e89939ad626b15278c71b69dc1dfccaa7b97bd4cdf96536bb7"},
    {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8d3335c03100a073883857e91db9f2e0ef8a1cf42dc0369cbb9151c149dbbc1b"},
    {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d25b1c1096ef0447355f7293fbe9ad740f7c47ae032c2884113f8e87660d8f6e"},
    {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a5d3fbd02efd9cf6a8ffc2f17b53a33542f6b154e88dd7b42ef4a4c0700fdad"},
    {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5934e2833afeaf36bd1eadb57256239785f5af0220ed8d21c2896ec4d3a765f"},
    {file = "rpds_py-0.9.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:095b460e117685867d45548fbd8598a8d9999227e9061ee7f012d9d264e6048d"},
    {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:91378d9f4151adc223d584489591dbb79f78814c0734a7c3bfa9c9e09978121c"},
    {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:24a81c177379300220e907e9b864107614b144f6c2a15ed5c3450e19cf536fae"},
    {file = "rpds_py-0.9.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:de0b6eceb46141984671802d412568d22c6bacc9b230174f9e55fc72ef4f57de"},
    {file = "rpds_py-0.9.2-cp311-none-win32.whl", hash = "sha256:700375326ed641f3d9d32060a91513ad668bcb7e2cffb18415c399acb25de2ab"},
    {file = "rpds_py-0.9.2-cp311-none-win_amd64.whl", hash = "sha256:0766babfcf941db8607bdaf82569ec38107dbb03c7f0b72604a0b346b6eb3298"},
    {file = "rpds_py-0.9.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:b1440c291db3f98a914e1afd9d6541e8fc60b4c3aab1a9008d03da4651e67386"},
    {file = "rpds_py-0.9.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0f2996fbac8e0b77fd67102becb9229986396e051f33dbceada3debaacc7033f"},
    {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f30d205755566a25f2ae0382944fcae2f350500ae4df4e795efa9e850821d82"},
    {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:159fba751a1e6b1c69244e23ba6c28f879a8758a3e992ed056d86d74a194a0f3"},
    {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1f044792e1adcea82468a72310c66a7f08728d72a244730d14880cd1dabe36b"},
    {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9251eb8aa82e6cf88510530b29eef4fac825a2b709baf5b94a6094894f252387"},
    {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01899794b654e616c8625b194ddd1e5b51ef5b60ed61baa7a2d9c2ad7b2a4238"},
    {file = "rpds_py-0.9.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b0c43f8ae8f6be1d605b0465671124aa8d6a0e40f1fb81dcea28b7e3d87ca1e1"},
    {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:207f57c402d1f8712618f737356e4b6f35253b6d20a324d9a47cb9f38ee43a6b"},
    {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b52e7c5ae35b00566d244ffefba0f46bb6bec749a50412acf42b1c3f402e2c90"},
    {file = "rpds_py-0.9.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:978fa96dbb005d599ec4fd9ed301b1cc45f1a8f7982d4793faf20b404b56677d"},
    {file = "rpds_py-0.9.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:6aa8326a4a608e1c28da191edd7c924dff445251b94653988efb059b16577a4d"},
    {file = "rpds_py-0.9.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aad51239bee6bff6823bbbdc8ad85136c6125542bbc609e035ab98ca1e32a192"},
    {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd4dc3602370679c2dfb818d9c97b1137d4dd412230cfecd3c66a1bf388a196"},
    {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd9da77c6ec1f258387957b754f0df60766ac23ed698b61941ba9acccd3284d1"},
    {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:190ca6f55042ea4649ed19c9093a9be9d63cd8a97880106747d7147f88a49d18"},
    {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:876bf9ed62323bc7dcfc261dbc5572c996ef26fe6406b0ff985cbcf460fc8a4c"},
    {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa2818759aba55df50592ecbc95ebcdc99917fa7b55cc6796235b04193eb3c55"},
    {file = "rpds_py-0.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9ea4d00850ef1e917815e59b078ecb338f6a8efda23369677c54a5825dbebb55"},
    {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:5855c85eb8b8a968a74dc7fb014c9166a05e7e7a8377fb91d78512900aadd13d"},
    {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:14c408e9d1a80dcb45c05a5149e5961aadb912fff42ca1dd9b68c0044904eb32"},
    {file = "rpds_py-0.9.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:65a0583c43d9f22cb2130c7b110e695fff834fd5e832a776a107197e59a1898e"},
    {file = "rpds_py-0.9.2-cp38-none-win32.whl", hash = "sha256:71f2f7715935a61fa3e4ae91d91b67e571aeb5cb5d10331ab681256bda2ad920"},
    {file = "rpds_py-0.9.2-cp38-none-win_amd64.whl", hash = "sha256:674c704605092e3ebbbd13687b09c9f78c362a4bc710343efe37a91457123044"},
    {file = "rpds_py-0.9.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:07e2c54bef6838fa44c48dfbc8234e8e2466d851124b551fc4e07a1cfeb37260"},
    {file = "rpds_py-0.9.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fdf55283ad38c33e35e2855565361f4bf0abd02470b8ab28d499c663bc5d7c"},
    {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:890ba852c16ace6ed9f90e8670f2c1c178d96510a21b06d2fa12d8783a905193"},
    {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50025635ba8b629a86d9d5474e650da304cb46bbb4d18690532dd79341467846"},
    {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:517cbf6e67ae3623c5127206489d69eb2bdb27239a3c3cc559350ef52a3bbf0b"},
    {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0836d71ca19071090d524739420a61580f3f894618d10b666cf3d9a1688355b1"},
    {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c439fd54b2b9053717cca3de9583be6584b384d88d045f97d409f0ca867d80f"},
    {file = "rpds_py-0.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f68996a3b3dc9335037f82754f9cdbe3a95db42bde571d8c3be26cc6245f2324"},
    {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:7d68dc8acded354c972116f59b5eb2e5864432948e098c19fe6994926d8e15c3"},
    {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f963c6b1218b96db85fc37a9f0851eaf8b9040aa46dec112611697a7023da535"},
    {file = "rpds_py-0.9.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a46859d7f947061b4010e554ccd1791467d1b1759f2dc2ec9055fa239f1bc26"},
    {file = "rpds_py-0.9.2-cp39-none-win32.whl", hash = "sha256:e07e5dbf8a83c66783a9fe2d4566968ea8c161199680e8ad38d53e075df5f0d0"},
    {file = "rpds_py-0.9.2-cp39-none-win_amd64.whl", hash = "sha256:682726178138ea45a0766907957b60f3a1bf3acdf212436be9733f28b6c5af3c"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:196cb208825a8b9c8fc360dc0f87993b8b260038615230242bf18ec84447c08d"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c7671d45530fcb6d5e22fd40c97e1e1e01965fc298cbda523bb640f3d923b387"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83b32f0940adec65099f3b1c215ef7f1d025d13ff947975a055989cb7fd019a4"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f67da97f5b9eac838b6980fc6da268622e91f8960e083a34533ca710bec8611"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03975db5f103997904c37e804e5f340c8fdabbb5883f26ee50a255d664eed58c"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:987b06d1cdb28f88a42e4fb8a87f094e43f3c435ed8e486533aea0bf2e53d931"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c861a7e4aef15ff91233751619ce3a3d2b9e5877e0fcd76f9ea4f6847183aa16"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02938432352359805b6da099c9c95c8a0547fe4b274ce8f1a91677401bb9a45f"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:ef1f08f2a924837e112cba2953e15aacfccbbfcd773b4b9b4723f8f2ddded08e"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:35da5cc5cb37c04c4ee03128ad59b8c3941a1e5cd398d78c37f716f32a9b7f67"},
    {file = "rpds_py-0.9.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:141acb9d4ccc04e704e5992d35472f78c35af047fa0cfae2923835d153f091be"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79f594919d2c1a0cc17d1988a6adaf9a2f000d2e1048f71f298b056b1018e872"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a06418fe1155e72e16dddc68bb3780ae44cebb2912fbd8bb6ff9161de56e1798"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b2eb034c94b0b96d5eddb290b7b5198460e2d5d0c421751713953a9c4e47d10"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b08605d248b974eb02f40bdcd1a35d3924c83a2a5e8f5d0fa5af852c4d960af"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0805911caedfe2736935250be5008b261f10a729a303f676d3d5fea6900c96a"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab2299e3f92aa5417d5e16bb45bb4586171c1327568f638e8453c9f8d9e0f020"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c8d7594e38cf98d8a7df25b440f684b510cf4627fe038c297a87496d10a174f"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8b9ec12ad5f0a4625db34db7e0005be2632c1013b253a4a60e8302ad4d462afd"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1fcdee18fea97238ed17ab6478c66b2095e4ae7177e35fb71fbe561a27adf620"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:933a7d5cd4b84f959aedeb84f2030f0a01d63ae6cf256629af3081cf3e3426e8"},
    {file = "rpds_py-0.9.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:686ba516e02db6d6f8c279d1641f7067ebb5dc58b1d0536c4aaebb7bf01cdc5d"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:0173c0444bec0a3d7d848eaeca2d8bd32a1b43f3d3fde6617aac3731fa4be05f"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d576c3ef8c7b2d560e301eb33891d1944d965a4d7a2eacb6332eee8a71827db6"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed89861ee8c8c47d6beb742a602f912b1bb64f598b1e2f3d758948721d44d468"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1054a08e818f8e18910f1bee731583fe8f899b0a0a5044c6e680ceea34f93876"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99e7c4bb27ff1aab90dcc3e9d37ee5af0231ed98d99cb6f5250de28889a3d502"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c545d9d14d47be716495076b659db179206e3fd997769bc01e2d550eeb685596"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9039a11bca3c41be5a58282ed81ae422fa680409022b996032a43badef2a3752"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fb39aca7a64ad0c9490adfa719dbeeb87d13be137ca189d2564e596f8ba32c07"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2d8b3b3a2ce0eaa00c5bbbb60b6713e94e7e0becab7b3db6c5c77f979e8ed1f1"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:99b1c16f732b3a9971406fbfe18468592c5a3529585a45a35adbc1389a529a03"},
    {file = "rpds_py-0.9.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c27ee01a6c3223025f4badd533bea5e87c988cb0ba2811b690395dfe16088cfe"},
    {file = "rpds_py-0.9.2.tar.gz", hash = "sha256:8d70e8f14900f2657c249ea4def963bed86a29b81f81f5b76b5a9215680de945"},
]

[[package]]
name = "ruamel-yaml"
version = "0.17.32"
requires_python = ">=3"
summary = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
dependencies = [
    "ruamel-yaml-clib>=0.2.7; platform_python_implementation == \"CPython\" and python_version < \"3.12\"",
]
files = [
    {file = "ruamel.yaml-0.17.32-py3-none-any.whl", hash = "sha256:23cd2ed620231677564646b0c6a89d138b6822a0d78656df7abda5879ec4f447"},
    {file = "ruamel.yaml-0.17.32.tar.gz", hash = "sha256:ec939063761914e14542972a5cba6d33c23b0859ab6342f61cf070cfc600efc2"},
]

[[package]]
name = "ruamel-yaml-clib"
version = "0.2.7"
requires_python = ">=3.5"
summary = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
files = [
    {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5859983f26d8cd7bb5c287ef452e8aacc86501487634573d260968f753e1d71"},
    {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:debc87a9516b237d0466a711b18b6ebeb17ba9f391eb7f91c649c5c4ec5006c7"},
    {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:df5828871e6648db72d1c19b4bd24819b80a755c4541d3409f0f7acd0f335c80"},
    {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:efa08d63ef03d079dcae1dfe334f6c8847ba8b645d08df286358b1f5293d24ab"},
    {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win32.whl", hash = "sha256:763d65baa3b952479c4e972669f679fe490eee058d5aa85da483ebae2009d231"},
    {file = "ruamel.yaml.clib-0.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:d000f258cf42fec2b1bbf2863c61d7b8918d31ffee905da62dede869254d3b8a"},
    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:045e0626baf1c52e5527bd5db361bc83180faaba2ff586e763d3d5982a876a9e"},
    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:1a6391a7cabb7641c32517539ca42cf84b87b667bad38b78d4d42dd23e957c81"},
    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:9c7617df90c1365638916b98cdd9be833d31d337dbcd722485597b43c4a215bf"},
    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:41d0f1fa4c6830176eef5b276af04c89320ea616655d01327d5ce65e50575c94"},
    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win32.whl", hash = "sha256:f6d3d39611ac2e4f62c3128a9eed45f19a6608670c5a2f4f07f24e8de3441d38"},
    {file = "ruamel.yaml.clib-0.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:da538167284de58a52109a9b89b8f6a53ff8437dd6dc26d33b57bf6699153122"},
    {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4b3a93bb9bc662fc1f99c5c3ea8e623d8b23ad22f861eb6fce9377ac07ad6072"},
    {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-macosx_12_0_arm64.whl", hash = "sha256:a234a20ae07e8469da311e182e70ef6b199d0fbeb6c6cc2901204dd87fb867e8"},
    {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:15910ef4f3e537eea7fe45f8a5d19997479940d9196f357152a09031c5be59f3"},
    {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:370445fd795706fd291ab00c9df38a0caed0f17a6fb46b0f607668ecb16ce763"},
    {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win32.whl", hash = "sha256:ecdf1a604009bd35c674b9225a8fa609e0282d9b896c03dd441a91e5f53b534e"},
    {file = "ruamel.yaml.clib-0.2.7-cp36-cp36m-win_amd64.whl", hash = "sha256:f34019dced51047d6f70cb9383b2ae2853b7fc4dce65129a5acd49f4f9256646"},
    {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2aa261c29a5545adfef9296b7e33941f46aa5bbd21164228e833412af4c9c75f"},
    {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f01da5790e95815eb5a8a138508c01c758e5f5bc0ce4286c4f7028b8dd7ac3d0"},
    {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:40d030e2329ce5286d6b231b8726959ebbe0404c92f0a578c0e2482182e38282"},
    {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c3ca1fbba4ae962521e5eb66d72998b51f0f4d0f608d3c0347a48e1af262efa7"},
    {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win32.whl", hash = "sha256:7bdb4c06b063f6fd55e472e201317a3bb6cdeeee5d5a38512ea5c01e1acbdd93"},
    {file = "ruamel.yaml.clib-0.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:be2a7ad8fd8f7442b24323d24ba0b56c51219513cfa45b9ada3b87b76c374d4b"},
    {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:91a789b4aa0097b78c93e3dc4b40040ba55bef518f84a40d4442f713b4094acb"},
    {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:99e77daab5d13a48a4054803d052ff40780278240a902b880dd37a51ba01a307"},
    {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:3243f48ecd450eddadc2d11b5feb08aca941b5cd98c9b1db14b2fd128be8c697"},
    {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8831a2cedcd0f0927f788c5bdf6567d9dc9cc235646a434986a852af1cb54b4b"},
    {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win32.whl", hash = "sha256:3110a99e0f94a4a3470ff67fc20d3f96c25b13d24c6980ff841e82bafe827cac"},
    {file = "ruamel.yaml.clib-0.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:92460ce908546ab69770b2e576e4f99fbb4ce6ab4b245345a3869a0a0410488f"},
    {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc0667c1eb8f83a3752b71b9c4ba55ef7c7058ae57022dd9b29065186a113d9"},
    {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:4a4d8d417868d68b979076a9be6a38c676eca060785abaa6709c7b31593c35d1"},
    {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:bf9a6bc4a0221538b1a7de3ed7bca4c93c02346853f44e1cd764be0023cd3640"},
    {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:a7b301ff08055d73223058b5c46c55638917f04d21577c95e00e0c4d79201a6b"},
    {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win32.whl", hash = "sha256:d5e51e2901ec2366b79f16c2299a03e74ba4531ddcfacc1416639c557aef0ad8"},
    {file = "ruamel.yaml.clib-0.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:184faeaec61dbaa3cace407cffc5819f7b977e75360e8d5ca19461cd851a5fc5"},
    {file = "ruamel.yaml.clib-0.2.7.tar.gz", hash = "sha256:1f08fd5a2bea9c4180db71678e850b995d2a5f4537be0e94557668cf0f5f9497"},
]

[[package]]
name = "secretstorage"
version = "3.3.3"
requires_python = ">=3.6"
summary = "Python bindings to FreeDesktop.org Secret Service API"
dependencies = [
    "cryptography>=2.0",
    "jeepney>=0.6",
]
files = [
    {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"},
    {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"},
]

[[package]]
name = "send2trash"
version = "1.8.2"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
summary = "Send file to trash natively under Mac OS X, Windows and Linux"
files = [
    {file = "Send2Trash-1.8.2-py3-none-any.whl", hash = "sha256:a384719d99c07ce1eefd6905d2decb6f8b7ed054025bb0e618919f945de4f679"},
    {file = "Send2Trash-1.8.2.tar.gz", hash = "sha256:c132d59fa44b9ca2b1699af5c86f57ce9f4c5eb56629d5d55fbb7a35f84e2312"},
]

[[package]]
name = "setuptools"
version = "68.0.0"
requires_python = ">=3.7"
summary = "Easily download, build, install, upgrade, and uninstall Python packages"
files = [
    {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"},
    {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"},
]

[[package]]
name = "shellingham"
version = "1.5.0.post1"
requires_python = ">=3.7"
summary = "Tool to Detect Surrounding Shell"
files = [
    {file = "shellingham-1.5.0.post1-py2.py3-none-any.whl", hash = "sha256:368bf8c00754fd4f55afb7bbb86e272df77e4dc76ac29dbcbb81a59e9fc15744"},
    {file = "shellingham-1.5.0.post1.tar.gz", hash = "sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28"},
]

[[package]]
name = "six"
version = "1.16.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python 2 and 3 compatibility utilities"
files = [
    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]

[[package]]
name = "sniffio"
version = "1.3.0"
requires_python = ">=3.7"
summary = "Sniff out which async library your code is running under"
files = [
    {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"},
    {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"},
]

[[package]]
name = "soupsieve"
version = "2.4.1"
requires_python = ">=3.7"
summary = "A modern CSS selector implementation for Beautiful Soup."
files = [
    {file = "soupsieve-2.4.1-py3-none-any.whl", hash = "sha256:1c1bfee6819544a3447586c889157365a27e10d88cde3ad3da0cf0ddf646feb8"},
    {file = "soupsieve-2.4.1.tar.gz", hash = "sha256:89d12b2d5dfcd2c9e8c22326da9d9aa9cb3dfab0a83a024f05704076ee8d35ea"},
]

[[package]]
name = "sqlglot"
version = "17.10.0"
summary = "An easily customizable SQL parser and transpiler"
files = [
    {file = "sqlglot-17.10.0-py3-none-any.whl", hash = "sha256:ebfae3f15ac619d097b02d932972c4ff29cd221ecd77ec1f24f3006bd9743238"},
    {file = "sqlglot-17.10.0.tar.gz", hash = "sha256:658029557cc224303c0da57ebd50b05102795b56efe3c8e70ff7674804e5ec49"},
]

[[package]]
name = "stack-data"
version = "0.6.2"
summary = "Extract data from python stack frames and tracebacks for informative displays"
dependencies = [
    "asttokens>=2.1.0",
    "executing>=1.2.0",
    "pure-eval",
]
files = [
    {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"},
    {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"},
]

[[package]]
name = "terminado"
version = "0.17.1"
requires_python = ">=3.7"
summary = "Tornado websocket backend for the Xterm.js Javascript terminal emulator library."
dependencies = [
    "ptyprocess; os_name != \"nt\"",
    "pywinpty>=1.1.0; os_name == \"nt\"",
    "tornado>=6.1.0",
]
files = [
    {file = "terminado-0.17.1-py3-none-any.whl", hash = "sha256:8650d44334eba354dd591129ca3124a6ba42c3d5b70df5051b6921d506fdaeae"},
    {file = "terminado-0.17.1.tar.gz", hash = "sha256:6ccbbcd3a4f8a25a5ec04991f39a0b8db52dfcd487ea0e578d977e6752380333"},
]

[[package]]
name = "tinycss2"
version = "1.2.1"
requires_python = ">=3.7"
summary = "A tiny CSS parser"
dependencies = [
    "webencodings>=0.4",
]
files = [
    {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"},
    {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"},
]

[[package]]
name = "toml"
version = "0.10.2"
requires_python = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python Library for Tom's Obvious, Minimal Language"
files = [
    {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
    {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
]

[[package]]
name = "tomli"
version = "2.0.1"
requires_python = ">=3.7"
summary = "A lil' TOML parser"
files = [
    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
]

[[package]]
name = "tomlkit"
version = "0.12.1"
requires_python = ">=3.7"
summary = "Style preserving TOML library"
files = [
    {file = "tomlkit-0.12.1-py3-none-any.whl", hash = "sha256:712cbd236609acc6a3e2e97253dfc52d4c2082982a88f61b640ecf0817eab899"},
    {file = "tomlkit-0.12.1.tar.gz", hash = "sha256:38e1ff8edb991273ec9f6181244a6a391ac30e9f5098e7535640ea6be97a7c86"},
]

[[package]]
name = "tornado"
version = "6.3.2"
requires_python = ">= 3.8"
summary = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
files = [
    {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:c367ab6c0393d71171123ca5515c61ff62fe09024fa6bf299cd1339dc9456829"},
    {file = "tornado-6.3.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b46a6ab20f5c7c1cb949c72c1994a4585d2eaa0be4853f50a03b5031e964fc7c"},
    {file = "tornado-6.3.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2de14066c4a38b4ecbbcd55c5cc4b5340eb04f1c5e81da7451ef555859c833f"},
    {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05615096845cf50a895026f749195bf0b10b8909f9be672f50b0fe69cba368e4"},
    {file = "tornado-6.3.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5b17b1cf5f8354efa3d37c6e28fdfd9c1c1e5122f2cb56dac121ac61baa47cbe"},
    {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:29e71c847a35f6e10ca3b5c2990a52ce38b233019d8e858b755ea6ce4dcdd19d"},
    {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_i686.whl", hash = "sha256:834ae7540ad3a83199a8da8f9f2d383e3c3d5130a328889e4cc991acc81e87a0"},
    {file = "tornado-6.3.2-cp38-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6a0848f1aea0d196a7c4f6772197cbe2abc4266f836b0aac76947872cd29b411"},
    {file = "tornado-6.3.2-cp38-abi3-win32.whl", hash = "sha256:7efcbcc30b7c654eb6a8c9c9da787a851c18f8ccd4a5a3a95b05c7accfa068d2"},
    {file = "tornado-6.3.2-cp38-abi3-win_amd64.whl", hash = "sha256:0c325e66c8123c606eea33084976c832aa4e766b7dff8aedd7587ea44a604cdf"},
    {file = "tornado-6.3.2.tar.gz", hash = "sha256:4b927c4f19b71e627b13f3db2324e4ae660527143f9e1f2e2fb404f3a187e2ba"},
]

[[package]]
name = "tox"
version = "4.6.4"
requires_python = ">=3.7"
summary = "tox is a generic virtualenv management and test command line tool"
dependencies = [
    "cachetools>=5.3.1",
    "chardet>=5.1",
    "colorama>=0.4.6",
    "filelock>=3.12.2",
    "packaging>=23.1",
    "platformdirs>=3.8",
    "pluggy>=1.2",
    "pyproject-api>=1.5.2",
    "tomli>=2.0.1; python_version < \"3.11\"",
    "virtualenv>=20.23.1",
]
files = [
    {file = "tox-4.6.4-py3-none-any.whl", hash = "sha256:1b8f8ae08d6a5475cad9d508236c51ea060620126fd7c3c513d0f5c7f29cc776"},
    {file = "tox-4.6.4.tar.gz", hash = "sha256:5e2ad8845764706170d3dcaac171704513cc8a725655219acb62fe4380bdadda"},
]

[[package]]
name = "traitlets"
version = "5.9.0"
requires_python = ">=3.7"
summary = "Traitlets Python configuration system"
files = [
    {file = "traitlets-5.9.0-py3-none-any.whl", hash = "sha256:9e6ec080259b9a5940c797d58b613b5e31441c2257b87c2e795c5228ae80d2d8"},
    {file = "traitlets-5.9.0.tar.gz", hash = "sha256:f6cde21a9c68cf756af02035f72d5a723bf607e862e7be33ece505abf4a3bad9"},
]

[[package]]
name = "triad"
version = "0.9.1"
requires_python = ">=3.7"
summary = "A collection of python utils for Fugue projects"
dependencies = [
    "fs",
    "fsspec",
    "numpy",
    "pandas>=1.2.0",
    "pyarrow",
    "six",
]
files = [
    {file = "triad-0.9.1-py3-none-any.whl", hash = "sha256:29084e7e17bfb12c00ca4812af2c9d5876462c1fda326293a12eb0f638829dea"},
    {file = "triad-0.9.1.tar.gz", hash = "sha256:afc3fd9f225247974fd1170f97448d8111ef011d2d8cb17a3503c3fc795cf594"},
]

[[package]]
name = "twine"
version = "4.0.2"
requires_python = ">=3.7"
summary = "Collection of utilities for publishing packages on PyPI"
dependencies = [
    "importlib-metadata>=3.6",
    "keyring>=15.1",
    "pkginfo>=1.8.1",
    "readme-renderer>=35.0",
    "requests-toolbelt!=0.9.0,>=0.8.0",
    "requests>=2.20",
    "rfc3986>=1.4.0",
    "rich>=12.0.0",
    "urllib3>=1.26.0",
]
files = [
    {file = "twine-4.0.2-py3-none-any.whl", hash = "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8"},
    {file = "twine-4.0.2.tar.gz", hash = "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8"},
]

[[package]]
name = "types-colorama"
version = "0.4.15.12"
summary = "Typing stubs for colorama"
files = [
    {file = "types-colorama-0.4.15.12.tar.gz", hash = "sha256:fbdfc5d9d24d85c33bd054fbe33adc6cec44eedb19cfbbabfbbb57dc257ae4b8"},
    {file = "types_colorama-0.4.15.12-py3-none-any.whl", hash = "sha256:23c9d4a00961227f7ef018d5a1c190c4bbc282119c3ee76a17677a793f13bb82"},
]

[[package]]
name = "types-markdown"
version = "3.4.2.10"
summary = "Typing stubs for Markdown"
files = [
    {file = "types-Markdown-3.4.2.10.tar.gz", hash = "sha256:11e3558d50e3bc1e3f52f3fe073788f4ab917a829374fb354476221c700629e8"},
    {file = "types_Markdown-3.4.2.10-py3-none-any.whl", hash = "sha256:543ff3027fda21c3149780bf835a721cd094c5729e9a87725f180569c960bff8"},
]

[[package]]
name = "types-pytz"
version = "2023.3.0.0"
summary = "Typing stubs for pytz"
files = [
    {file = "types-pytz-2023.3.0.0.tar.gz", hash = "sha256:ecdc70d543aaf3616a7e48631543a884f74205f284cefd6649ddf44c6a820aac"},
    {file = "types_pytz-2023.3.0.0-py3-none-any.whl", hash = "sha256:4fc2a7fbbc315f0b6630e0b899fd6c743705abe1094d007b0e612d10da15e0f3"},
]

[[package]]
name = "types-pyyaml"
version = "6.0.12.11"
summary = "Typing stubs for PyYAML"
files = [
    {file = "types-PyYAML-6.0.12.11.tar.gz", hash = "sha256:7d340b19ca28cddfdba438ee638cd4084bde213e501a3978738543e27094775b"},
    {file = "types_PyYAML-6.0.12.11-py3-none-any.whl", hash = "sha256:a461508f3096d1d5810ec5ab95d7eeecb651f3a15b71959999988942063bf01d"},
]

[[package]]
name = "types-requests"
version = "2.31.0.2"
summary = "Typing stubs for requests"
dependencies = [
    "types-urllib3",
]
files = [
    {file = "types-requests-2.31.0.2.tar.gz", hash = "sha256:6aa3f7faf0ea52d728bb18c0a0d1522d9bfd8c72d26ff6f61bfc3d06a411cf40"},
    {file = "types_requests-2.31.0.2-py3-none-any.whl", hash = "sha256:56d181c85b5925cbc59f4489a57e72a8b2166f18273fd8ba7b6fe0c0b986f12a"},
]

[[package]]
name = "types-setuptools"
version = "57.4.18"
summary = "Typing stubs for setuptools"
files = [
    {file = "types-setuptools-57.4.18.tar.gz", hash = "sha256:8ee03d823fe7fda0bd35faeae33d35cb5c25b497263e6a58b34c4cfd05f40bcf"},
    {file = "types_setuptools-57.4.18-py3-none-any.whl", hash = "sha256:9660b8774b12cd61b448e2fd87a667c02e7ec13ce9f15171f1d49a4654c4df6a"},
]

[[package]]
name = "types-urllib3"
version = "1.26.25.14"
summary = "Typing stubs for urllib3"
files = [
    {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"},
    {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"},
]

[[package]]
name = "typing-extensions"
version = "4.7.1"
requires_python = ">=3.7"
summary = "Backported and Experimental Type Hints for Python 3.7+"
files = [
    {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"},
    {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"},
]

[[package]]
name = "tzdata"
version = "2023.3"
requires_python = ">=2"
summary = "Provider of IANA time zone data"
files = [
    {file = "tzdata-2023.3-py2.py3-none-any.whl", hash = "sha256:7e65763eef3120314099b6939b5546db7adce1e7d6f2e179e3df563c70511eda"},
    {file = "tzdata-2023.3.tar.gz", hash = "sha256:11ef1e08e54acb0d4f95bdb1be05da659673de4acbd21bf9c69e94cc5e907a3a"},
]

[[package]]
name = "unearth"
version = "0.10.0"
requires_python = ">=3.7"
summary = "A utility to fetch and download python packages"
dependencies = [
    "packaging>=20",
    "requests>=2.25",
]
files = [
    {file = "unearth-0.10.0-py3-none-any.whl", hash = "sha256:e8b36f6efd6b677a3ff86354675368a79e98ee8ba01aaa601858e2cc043bc51a"},
    {file = "unearth-0.10.0.tar.gz", hash = "sha256:d5b152a5ab2aa3e5149a11cf7b3ba5c5d493176dca38f66ca8969dadd5a8f645"},
]

[[package]]
name = "uri-template"
version = "1.3.0"
requires_python = ">=3.7"
summary = "RFC 6570 URI Template Processor"
files = [
    {file = "uri-template-1.3.0.tar.gz", hash = "sha256:0e00f8eb65e18c7de20d595a14336e9f337ead580c70934141624b6d1ffdacc7"},
    {file = "uri_template-1.3.0-py3-none-any.whl", hash = "sha256:a44a133ea12d44a0c0f06d7d42a52d71282e77e2f937d8abd5655b8d56fc1363"},
]

[[package]]
name = "urllib3"
version = "2.0.4"
requires_python = ">=3.7"
summary = "HTTP library with thread-safe connection pooling, file post, and more."
files = [
    {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"},
    {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"},
]

[[package]]
name = "verspec"
version = "0.1.0"
summary = "Flexible version handling"
files = [
    {file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"},
    {file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"},
]

[[package]]
name = "virtualenv"
version = "20.24.2"
requires_python = ">=3.7"
summary = "Virtual Python Environment builder"
dependencies = [
    "distlib<1,>=0.3.7",
    "filelock<4,>=3.12.2",
    "platformdirs<4,>=3.9.1",
]
files = [
    {file = "virtualenv-20.24.2-py3-none-any.whl", hash = "sha256:43a3052be36080548bdee0b42919c88072037d50d56c28bd3f853cbe92b953ff"},
    {file = "virtualenv-20.24.2.tar.gz", hash = "sha256:fd8a78f46f6b99a67b7ec5cf73f92357891a7b3a40fd97637c27f854aae3b9e0"},
]

[[package]]
name = "watchdog"
version = "2.3.1"
requires_python = ">=3.6"
summary = "Filesystem events monitoring"
files = [
    {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1f1200d4ec53b88bf04ab636f9133cb703eb19768a39351cee649de21a33697"},
    {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:564e7739abd4bd348aeafbf71cc006b6c0ccda3160c7053c4a53b67d14091d42"},
    {file = "watchdog-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95ad708a9454050a46f741ba5e2f3468655ea22da1114e4c40b8cbdaca572565"},
    {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a073c91a6ef0dda488087669586768195c3080c66866144880f03445ca23ef16"},
    {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa8b028750b43e80eea9946d01925168eeadb488dfdef1d82be4b1e28067f375"},
    {file = "watchdog-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:964fd236cd443933268ae49b59706569c8b741073dbfd7ca705492bae9d39aab"},
    {file = "watchdog-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:91fd146d723392b3e6eb1ac21f122fcce149a194a2ba0a82c5e4d0ee29cd954c"},
    {file = "watchdog-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f"},
    {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85bf2263290591b7c5fa01140601b64c831be88084de41efbcba6ea289874f44"},
    {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f2df370cd8e4e18499dd0bfdef476431bcc396108b97195d9448d90924e3131"},
    {file = "watchdog-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b"},
    {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f5d0f7eac86807275eba40b577c671b306f6f335ba63a5c5a348da151aba0fc"},
    {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b848c71ef2b15d0ef02f69da8cc120d335cec0ed82a3fa7779e27a5a8527225"},
    {file = "watchdog-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d9878be36d2b9271e3abaa6f4f051b363ff54dbbe7e7df1af3c920e4311ee43"},
    {file = "watchdog-2.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cd61f98cb37143206818cb1786d2438626aa78d682a8f2ecee239055a9771d5"},
    {file = "watchdog-2.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d2dbcf1acd96e7a9c9aefed201c47c8e311075105d94ce5e899f118155709fd"},
    {file = "watchdog-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03f342a9432fe08107defbe8e405a2cb922c5d00c4c6c168c68b633c64ce6190"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7a596f9415a378d0339681efc08d2249e48975daae391d58f2e22a3673b977cf"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:0e1dd6d449267cc7d6935d7fe27ee0426af6ee16578eed93bacb1be9ff824d2d"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_i686.whl", hash = "sha256:7a1876f660e32027a1a46f8a0fa5747ad4fcf86cb451860eae61a26e102c8c79"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:2caf77ae137935c1466f8cefd4a3aec7017b6969f425d086e6a528241cba7256"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:53f3e95081280898d9e4fc51c5c69017715929e4eea1ab45801d5e903dd518ad"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:9da7acb9af7e4a272089bd2af0171d23e0d6271385c51d4d9bde91fe918c53ed"},
    {file = "watchdog-2.3.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8a4d484e846dcd75e96b96d80d80445302621be40e293bfdf34a631cab3b33dc"},
    {file = "watchdog-2.3.1-py3-none-win32.whl", hash = "sha256:a74155398434937ac2780fd257c045954de5b11b5c52fc844e2199ce3eecf4cf"},
    {file = "watchdog-2.3.1-py3-none-win_amd64.whl", hash = "sha256:5defe4f0918a2a1a4afbe4dbb967f743ac3a93d546ea4674567806375b024adb"},
    {file = "watchdog-2.3.1-py3-none-win_ia64.whl", hash = "sha256:4109cccf214b7e3462e8403ab1e5b17b302ecce6c103eb2fc3afa534a7f27b96"},
    {file = "watchdog-2.3.1.tar.gz", hash = "sha256:d9f9ed26ed22a9d331820a8432c3680707ea8b54121ddcc9dc7d9f2ceeb36906"},
]

[[package]]
name = "wcwidth"
version = "0.2.6"
summary = "Measures the displayed width of unicode strings in a terminal"
files = [
    {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"},
    {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"},
]

[[package]]
name = "webcolors"
version = "1.13"
requires_python = ">=3.7"
summary = "A library for working with the color formats defined by HTML and CSS."
files = [
    {file = "webcolors-1.13-py3-none-any.whl", hash = "sha256:29bc7e8752c0a1bd4a1f03c14d6e6a72e93d82193738fa860cbff59d0fcc11bf"},
    {file = "webcolors-1.13.tar.gz", hash = "sha256:c225b674c83fa923be93d235330ce0300373d02885cef23238813b0d5668304a"},
]

[[package]]
name = "webencodings"
version = "0.5.1"
summary = "Character encoding aliases for legacy web content"
files = [
    {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
    {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
]

[[package]]
name = "websocket-client"
version = "1.6.1"
requires_python = ">=3.7"
summary = "WebSocket client for Python with low level API options"
files = [
    {file = "websocket-client-1.6.1.tar.gz", hash = "sha256:c951af98631d24f8df89ab1019fc365f2227c0892f12fd150e935607c79dd0dd"},
    {file = "websocket_client-1.6.1-py3-none-any.whl", hash = "sha256:f1f9f2ad5291f0225a49efad77abf9e700b6fef553900623060dad6e26503b9d"},
]

[[package]]
name = "wrapt"
version = "1.15.0"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
summary = "Module for decorators, wrappers and monkey patching."
files = [
    {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"},
    {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"},
    {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"},
    {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"},
    {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"},
    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"},
    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"},
    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"},
    {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"},
    {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"},
    {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"},
    {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"},
    {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"},
    {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"},
    {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"},
    {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"},
    {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"},
    {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"},
    {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"},
    {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"},
    {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"},
    {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"},
    {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"},
    {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"},
    {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"},
    {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"},
    {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"},
    {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"},
    {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"},
    {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"},
    {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"},
    {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"},
    {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"},
    {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"},
    {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"},
    {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"},
    {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"},
    {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"},
    {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"},
    {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"},
    {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"},
    {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"},
    {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"},
    {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"},
    {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"},
    {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"},
    {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"},
    {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"},
    {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"},
    {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"},
    {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"},
    {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"},
    {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"},
    {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"},
    {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"},
    {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"},
    {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"},
    {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"},
    {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"},
    {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"},
    {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"},
    {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"},
    {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"},
    {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"},
    {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"},
    {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"},
    {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"},
    {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"},
    {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"},
    {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"},
    {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"},
    {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"},
    {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"},
    {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"},
    {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"},
]

[[package]]
name = "zipp"
version = "3.6.0"
requires_python = ">=3.6"
summary = "Backport of pathlib-compatible object wrapper for zip files"
files = [
    {file = "zipp-3.6.0-py3-none-any.whl", hash = "sha256:9fe5ea21568a0a70e50f273397638d39b03353731e6cbbb3fd8502a33fec40bc"},
    {file = "zipp-3.6.0.tar.gz", hash = "sha256:71c644c5369f4a6e07636f0aa966270449561fcea2e3d6747b8d23efaa9d7832"},
]

package.json METASEP
{
  "name": "ipyvizzu-dev",
  "description": "ipyvizzu development",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/vizzuhq/ipyvizzu.git"
  },
  "homepage": "https://ipyvizzu.vizzuhq.com/",
  "url": "https://github.com/vizzuhq/ipyvizzu/issues",
  "author": "Vizzu Inc.",
  "license": "Apache-2.0",
  "dependencies": {
    "npm-run-all": "*",
    "prettier": "*",
    "eslint": "*",
    "eslint-config-standard": "*",
    "eslint-config-prettier": "*",
    "puppeteer": "^19.7.0"
  },
  "prettier": {
    "printWidth": 80,
    "endOfLine": "auto"
  },
  "eslintConfig": {
    "env": {
      "browser": true,
      "jest": true
    },
    "extends": [
      "standard",
      "prettier"
    ]
  }
}

package-lock.json METASEP
{
  "name": "ipyvizzu-dev",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "ipyvizzu-dev",
      "license": "Apache-2.0",
      "dependencies": {
        "eslint": "*",
        "eslint-config-prettier": "*",
        "eslint-config-standard": "*",
        "npm-run-all": "*",
        "prettier": "*",
        "puppeteer": "^19.7.0"
      }
    },
    "node_modules/@aashutoshrathi/word-wrap": {
      "version": "1.2.6",
      "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
      "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/@babel/code-frame": {
      "version": "7.22.5",
      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz",
      "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==",
      "dependencies": {
        "@babel/highlight": "^7.22.5"
      },
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@babel/helper-validator-identifier": {
      "version": "7.22.5",
      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
      "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@babel/highlight": {
      "version": "7.22.5",
      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz",
      "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==",
      "dependencies": {
        "@babel/helper-validator-identifier": "^7.22.5",
        "chalk": "^2.0.0",
        "js-tokens": "^4.0.0"
      },
      "engines": {
        "node": ">=6.9.0"
      }
    },
    "node_modules/@babel/highlight/node_modules/ansi-styles": {
      "version": "3.2.1",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
      "dependencies": {
        "color-convert": "^1.9.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/@babel/highlight/node_modules/chalk": {
      "version": "2.4.2",
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
      "dependencies": {
        "ansi-styles": "^3.2.1",
        "escape-string-regexp": "^1.0.5",
        "supports-color": "^5.3.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/@babel/highlight/node_modules/color-convert": {
      "version": "1.9.3",
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
      "dependencies": {
        "color-name": "1.1.3"
      }
    },
    "node_modules/@babel/highlight/node_modules/color-name": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
    },
    "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
      "engines": {
        "node": ">=0.8.0"
      }
    },
    "node_modules/@babel/highlight/node_modules/has-flag": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/@babel/highlight/node_modules/supports-color": {
      "version": "5.5.0",
      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
      "dependencies": {
        "has-flag": "^3.0.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/@eslint-community/eslint-utils": {
      "version": "4.4.0",
      "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
      "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
      "dependencies": {
        "eslint-visitor-keys": "^3.3.0"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "peerDependencies": {
        "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
      }
    },
    "node_modules/@eslint-community/regexpp": {
      "version": "4.6.2",
      "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz",
      "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==",
      "engines": {
        "node": "^12.0.0 || ^14.0.0 || >=16.0.0"
      }
    },
    "node_modules/@eslint/eslintrc": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.0.tgz",
      "integrity": "sha512-Lj7DECXqIVCqnqjjHMPna4vn6GJcMgul/wuS0je9OZ9gsL0zzDpKPVtcG1HaDVc+9y+qgXneTeUMbCqXJNpH1A==",
      "dependencies": {
        "ajv": "^6.12.4",
        "debug": "^4.3.2",
        "espree": "^9.6.0",
        "globals": "^13.19.0",
        "ignore": "^5.2.0",
        "import-fresh": "^3.2.1",
        "js-yaml": "^4.1.0",
        "minimatch": "^3.1.2",
        "strip-json-comments": "^3.1.1"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/@eslint/js": {
      "version": "8.44.0",
      "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.44.0.tgz",
      "integrity": "sha512-Ag+9YM4ocKQx9AarydN0KY2j0ErMHNIocPDrVo8zAE44xLTjEtz81OdR68/cydGtk6m6jDb5Za3r2useMzYmSw==",
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      }
    },
    "node_modules/@humanwhocodes/config-array": {
      "version": "0.11.10",
      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz",
      "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==",
      "dependencies": {
        "@humanwhocodes/object-schema": "^1.2.1",
        "debug": "^4.1.1",
        "minimatch": "^3.0.5"
      },
      "engines": {
        "node": ">=10.10.0"
      }
    },
    "node_modules/@humanwhocodes/module-importer": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
      "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
      "engines": {
        "node": ">=12.22"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/nzakas"
      }
    },
    "node_modules/@humanwhocodes/object-schema": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
    },
    "node_modules/@nodelib/fs.scandir": {
      "version": "2.1.5",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
      "dependencies": {
        "@nodelib/fs.stat": "2.0.5",
        "run-parallel": "^1.1.9"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nodelib/fs.stat": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@nodelib/fs.walk": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
      "dependencies": {
        "@nodelib/fs.scandir": "2.1.5",
        "fastq": "^1.6.0"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/@puppeteer/browsers": {
      "version": "0.5.0",
      "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz",
      "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==",
      "dependencies": {
        "debug": "4.3.4",
        "extract-zip": "2.0.1",
        "https-proxy-agent": "5.0.1",
        "progress": "2.0.3",
        "proxy-from-env": "1.1.0",
        "tar-fs": "2.1.1",
        "unbzip2-stream": "1.4.3",
        "yargs": "17.7.1"
      },
      "bin": {
        "browsers": "lib/cjs/main-cli.js"
      },
      "engines": {
        "node": ">=14.1.0"
      },
      "peerDependencies": {
        "typescript": ">= 4.7.4"
      },
      "peerDependenciesMeta": {
        "typescript": {
          "optional": true
        }
      }
    },
    "node_modules/@types/json5": {
      "version": "0.0.29",
      "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
      "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
      "peer": true
    },
    "node_modules/@types/node": {
      "version": "20.4.5",
      "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.5.tgz",
      "integrity": "sha512-rt40Nk13II9JwQBdeYqmbn2Q6IVTA5uPhvSO+JVqdXw/6/4glI6oR9ezty/A9Hg5u7JH4OmYmuQ+XvjKm0Datg==",
      "optional": true
    },
    "node_modules/@types/yauzl": {
      "version": "2.10.0",
      "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz",
      "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==",
      "optional": true,
      "dependencies": {
        "@types/node": "*"
      }
    },
    "node_modules/acorn": {
      "version": "8.10.0",
      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
      "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
      "bin": {
        "acorn": "bin/acorn"
      },
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/acorn-jsx": {
      "version": "5.3.2",
      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
      "peerDependencies": {
        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
      }
    },
    "node_modules/agent-base": {
      "version": "6.0.2",
      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
      "dependencies": {
        "debug": "4"
      },
      "engines": {
        "node": ">= 6.0.0"
      }
    },
    "node_modules/ajv": {
      "version": "6.12.6",
      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
      "dependencies": {
        "fast-deep-equal": "^3.1.1",
        "fast-json-stable-stringify": "^2.0.0",
        "json-schema-traverse": "^0.4.1",
        "uri-js": "^4.2.2"
      },
      "funding": {
        "type": "github",
        "url": "https://github.com/sponsors/epoberezkin"
      }
    },
    "node_modules/ansi-regex": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/ansi-styles": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
      "dependencies": {
        "color-convert": "^2.0.1"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
      }
    },
    "node_modules/argparse": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
    },
    "node_modules/array-buffer-byte-length": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz",
      "integrity": "sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "is-array-buffer": "^3.0.1"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array-includes": {
      "version": "3.1.6",
      "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz",
      "integrity": "sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==",
      "peer": true,
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4",
        "get-intrinsic": "^1.1.3",
        "is-string": "^1.0.7"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.flat": {
      "version": "1.3.1",
      "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz",
      "integrity": "sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==",
      "peer": true,
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4",
        "es-shim-unscopables": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/array.prototype.flatmap": {
      "version": "1.3.1",
      "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz",
      "integrity": "sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==",
      "peer": true,
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4",
        "es-shim-unscopables": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/arraybuffer.prototype.slice": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz",
      "integrity": "sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw==",
      "dependencies": {
        "array-buffer-byte-length": "^1.0.0",
        "call-bind": "^1.0.2",
        "define-properties": "^1.2.0",
        "get-intrinsic": "^1.2.1",
        "is-array-buffer": "^3.0.2",
        "is-shared-array-buffer": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/available-typed-arrays": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
      "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/balanced-match": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
    },
    "node_modules/base64-js": {
      "version": "1.5.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ]
    },
    "node_modules/bl": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
      "dependencies": {
        "buffer": "^5.5.0",
        "inherits": "^2.0.4",
        "readable-stream": "^3.4.0"
      }
    },
    "node_modules/brace-expansion": {
      "version": "1.1.11",
      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
      "dependencies": {
        "balanced-match": "^1.0.0",
        "concat-map": "0.0.1"
      }
    },
    "node_modules/buffer": {
      "version": "5.7.1",
      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "dependencies": {
        "base64-js": "^1.3.1",
        "ieee754": "^1.1.13"
      }
    },
    "node_modules/buffer-crc32": {
      "version": "0.2.13",
      "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
      "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
      "engines": {
        "node": "*"
      }
    },
    "node_modules/builtins": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
      "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
      "peer": true,
      "dependencies": {
        "semver": "^7.0.0"
      }
    },
    "node_modules/builtins/node_modules/semver": {
      "version": "7.5.4",
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
      "peer": true,
      "dependencies": {
        "lru-cache": "^6.0.0"
      },
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/call-bind": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
      "dependencies": {
        "function-bind": "^1.1.1",
        "get-intrinsic": "^1.0.2"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/callsites": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/chalk": {
      "version": "4.1.2",
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
      "dependencies": {
        "ansi-styles": "^4.1.0",
        "supports-color": "^7.1.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/chalk/chalk?sponsor=1"
      }
    },
    "node_modules/chownr": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
      "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
    },
    "node_modules/chromium-bidi": {
      "version": "0.4.7",
      "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.7.tgz",
      "integrity": "sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==",
      "dependencies": {
        "mitt": "3.0.0"
      },
      "peerDependencies": {
        "devtools-protocol": "*"
      }
    },
    "node_modules/cliui": {
      "version": "8.0.1",
      "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
      "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
      "dependencies": {
        "string-width": "^4.2.0",
        "strip-ansi": "^6.0.1",
        "wrap-ansi": "^7.0.0"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/color-convert": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
      "dependencies": {
        "color-name": "~1.1.4"
      },
      "engines": {
        "node": ">=7.0.0"
      }
    },
    "node_modules/color-name": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
    },
    "node_modules/concat-map": {
      "version": "0.0.1",
      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
    },
    "node_modules/cosmiconfig": {
      "version": "8.1.3",
      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz",
      "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==",
      "dependencies": {
        "import-fresh": "^3.2.1",
        "js-yaml": "^4.1.0",
        "parse-json": "^5.0.0",
        "path-type": "^4.0.0"
      },
      "engines": {
        "node": ">=14"
      },
      "funding": {
        "url": "https://github.com/sponsors/d-fischer"
      }
    },
    "node_modules/cross-fetch": {
      "version": "3.1.5",
      "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz",
      "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==",
      "dependencies": {
        "node-fetch": "2.6.7"
      }
    },
    "node_modules/cross-spawn": {
      "version": "7.0.3",
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
      "dependencies": {
        "path-key": "^3.1.0",
        "shebang-command": "^2.0.0",
        "which": "^2.0.1"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/debug": {
      "version": "4.3.4",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
      "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
      "dependencies": {
        "ms": "2.1.2"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/deep-is": {
      "version": "0.1.4",
      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
      "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
    },
    "node_modules/define-properties": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz",
      "integrity": "sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==",
      "dependencies": {
        "has-property-descriptors": "^1.0.0",
        "object-keys": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/devtools-protocol": {
      "version": "0.0.1107588",
      "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz",
      "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg=="
    },
    "node_modules/doctrine": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
      "dependencies": {
        "esutils": "^2.0.2"
      },
      "engines": {
        "node": ">=6.0.0"
      }
    },
    "node_modules/emoji-regex": {
      "version": "8.0.0",
      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
    },
    "node_modules/end-of-stream": {
      "version": "1.4.4",
      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
      "dependencies": {
        "once": "^1.4.0"
      }
    },
    "node_modules/error-ex": {
      "version": "1.3.2",
      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
      "dependencies": {
        "is-arrayish": "^0.2.1"
      }
    },
    "node_modules/es-abstract": {
      "version": "1.22.1",
      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.1.tgz",
      "integrity": "sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw==",
      "dependencies": {
        "array-buffer-byte-length": "^1.0.0",
        "arraybuffer.prototype.slice": "^1.0.1",
        "available-typed-arrays": "^1.0.5",
        "call-bind": "^1.0.2",
        "es-set-tostringtag": "^2.0.1",
        "es-to-primitive": "^1.2.1",
        "function.prototype.name": "^1.1.5",
        "get-intrinsic": "^1.2.1",
        "get-symbol-description": "^1.0.0",
        "globalthis": "^1.0.3",
        "gopd": "^1.0.1",
        "has": "^1.0.3",
        "has-property-descriptors": "^1.0.0",
        "has-proto": "^1.0.1",
        "has-symbols": "^1.0.3",
        "internal-slot": "^1.0.5",
        "is-array-buffer": "^3.0.2",
        "is-callable": "^1.2.7",
        "is-negative-zero": "^2.0.2",
        "is-regex": "^1.1.4",
        "is-shared-array-buffer": "^1.0.2",
        "is-string": "^1.0.7",
        "is-typed-array": "^1.1.10",
        "is-weakref": "^1.0.2",
        "object-inspect": "^1.12.3",
        "object-keys": "^1.1.1",
        "object.assign": "^4.1.4",
        "regexp.prototype.flags": "^1.5.0",
        "safe-array-concat": "^1.0.0",
        "safe-regex-test": "^1.0.0",
        "string.prototype.trim": "^1.2.7",
        "string.prototype.trimend": "^1.0.6",
        "string.prototype.trimstart": "^1.0.6",
        "typed-array-buffer": "^1.0.0",
        "typed-array-byte-length": "^1.0.0",
        "typed-array-byte-offset": "^1.0.0",
        "typed-array-length": "^1.0.4",
        "unbox-primitive": "^1.0.2",
        "which-typed-array": "^1.1.10"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/es-set-tostringtag": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz",
      "integrity": "sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==",
      "dependencies": {
        "get-intrinsic": "^1.1.3",
        "has": "^1.0.3",
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/es-shim-unscopables": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz",
      "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==",
      "peer": true,
      "dependencies": {
        "has": "^1.0.3"
      }
    },
    "node_modules/es-to-primitive": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
      "dependencies": {
        "is-callable": "^1.1.4",
        "is-date-object": "^1.0.1",
        "is-symbol": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/escalade": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/escape-string-regexp": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/eslint": {
      "version": "8.45.0",
      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.45.0.tgz",
      "integrity": "sha512-pd8KSxiQpdYRfYa9Wufvdoct3ZPQQuVuU5O6scNgMuOMYuxvH0IGaYK0wUFjo4UYYQQCUndlXiMbnxopwvvTiw==",
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.2.0",
        "@eslint-community/regexpp": "^4.4.0",
        "@eslint/eslintrc": "^2.1.0",
        "@eslint/js": "8.44.0",
        "@humanwhocodes/config-array": "^0.11.10",
        "@humanwhocodes/module-importer": "^1.0.1",
        "@nodelib/fs.walk": "^1.2.8",
        "ajv": "^6.10.0",
        "chalk": "^4.0.0",
        "cross-spawn": "^7.0.2",
        "debug": "^4.3.2",
        "doctrine": "^3.0.0",
        "escape-string-regexp": "^4.0.0",
        "eslint-scope": "^7.2.0",
        "eslint-visitor-keys": "^3.4.1",
        "espree": "^9.6.0",
        "esquery": "^1.4.2",
        "esutils": "^2.0.2",
        "fast-deep-equal": "^3.1.3",
        "file-entry-cache": "^6.0.1",
        "find-up": "^5.0.0",
        "glob-parent": "^6.0.2",
        "globals": "^13.19.0",
        "graphemer": "^1.4.0",
        "ignore": "^5.2.0",
        "imurmurhash": "^0.1.4",
        "is-glob": "^4.0.0",
        "is-path-inside": "^3.0.3",
        "js-yaml": "^4.1.0",
        "json-stable-stringify-without-jsonify": "^1.0.1",
        "levn": "^0.4.1",
        "lodash.merge": "^4.6.2",
        "minimatch": "^3.1.2",
        "natural-compare": "^1.4.0",
        "optionator": "^0.9.3",
        "strip-ansi": "^6.0.1",
        "text-table": "^0.2.0"
      },
      "bin": {
        "eslint": "bin/eslint.js"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/eslint-config-prettier": {
      "version": "8.8.0",
      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz",
      "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==",
      "bin": {
        "eslint-config-prettier": "bin/cli.js"
      },
      "peerDependencies": {
        "eslint": ">=7.0.0"
      }
    },
    "node_modules/eslint-config-standard": {
      "version": "17.1.0",
      "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz",
      "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "engines": {
        "node": ">=12.0.0"
      },
      "peerDependencies": {
        "eslint": "^8.0.1",
        "eslint-plugin-import": "^2.25.2",
        "eslint-plugin-n": "^15.0.0 || ^16.0.0 ",
        "eslint-plugin-promise": "^6.0.0"
      }
    },
    "node_modules/eslint-import-resolver-node": {
      "version": "0.3.7",
      "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz",
      "integrity": "sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==",
      "peer": true,
      "dependencies": {
        "debug": "^3.2.7",
        "is-core-module": "^2.11.0",
        "resolve": "^1.22.1"
      }
    },
    "node_modules/eslint-import-resolver-node/node_modules/debug": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
      "peer": true,
      "dependencies": {
        "ms": "^2.1.1"
      }
    },
    "node_modules/eslint-module-utils": {
      "version": "2.8.0",
      "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz",
      "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==",
      "peer": true,
      "dependencies": {
        "debug": "^3.2.7"
      },
      "engines": {
        "node": ">=4"
      },
      "peerDependenciesMeta": {
        "eslint": {
          "optional": true
        }
      }
    },
    "node_modules/eslint-module-utils/node_modules/debug": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
      "peer": true,
      "dependencies": {
        "ms": "^2.1.1"
      }
    },
    "node_modules/eslint-plugin-es-x": {
      "version": "7.2.0",
      "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.2.0.tgz",
      "integrity": "sha512-9dvv5CcvNjSJPqnS5uZkqb3xmbeqRLnvXKK7iI5+oK/yTusyc46zbBZKENGsOfojm/mKfszyZb+wNqNPAPeGXA==",
      "peer": true,
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.1.2",
        "@eslint-community/regexpp": "^4.6.0"
      },
      "engines": {
        "node": "^14.18.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/ota-meshi"
      },
      "peerDependencies": {
        "eslint": ">=8"
      }
    },
    "node_modules/eslint-plugin-import": {
      "version": "2.27.5",
      "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.27.5.tgz",
      "integrity": "sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==",
      "peer": true,
      "dependencies": {
        "array-includes": "^3.1.6",
        "array.prototype.flat": "^1.3.1",
        "array.prototype.flatmap": "^1.3.1",
        "debug": "^3.2.7",
        "doctrine": "^2.1.0",
        "eslint-import-resolver-node": "^0.3.7",
        "eslint-module-utils": "^2.7.4",
        "has": "^1.0.3",
        "is-core-module": "^2.11.0",
        "is-glob": "^4.0.3",
        "minimatch": "^3.1.2",
        "object.values": "^1.1.6",
        "resolve": "^1.22.1",
        "semver": "^6.3.0",
        "tsconfig-paths": "^3.14.1"
      },
      "engines": {
        "node": ">=4"
      },
      "peerDependencies": {
        "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
      }
    },
    "node_modules/eslint-plugin-import/node_modules/debug": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
      "peer": true,
      "dependencies": {
        "ms": "^2.1.1"
      }
    },
    "node_modules/eslint-plugin-import/node_modules/doctrine": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
      "peer": true,
      "dependencies": {
        "esutils": "^2.0.2"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/eslint-plugin-n": {
      "version": "16.0.1",
      "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.0.1.tgz",
      "integrity": "sha512-CDmHegJN0OF3L5cz5tATH84RPQm9kG+Yx39wIqIwPR2C0uhBGMWfbbOtetR83PQjjidA5aXMu+LEFw1jaSwvTA==",
      "peer": true,
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.4.0",
        "builtins": "^5.0.1",
        "eslint-plugin-es-x": "^7.1.0",
        "ignore": "^5.2.4",
        "is-core-module": "^2.12.1",
        "minimatch": "^3.1.2",
        "resolve": "^1.22.2",
        "semver": "^7.5.3"
      },
      "engines": {
        "node": ">=16.0.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/mysticatea"
      },
      "peerDependencies": {
        "eslint": ">=7.0.0"
      }
    },
    "node_modules/eslint-plugin-n/node_modules/semver": {
      "version": "7.5.4",
      "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
      "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
      "peer": true,
      "dependencies": {
        "lru-cache": "^6.0.0"
      },
      "bin": {
        "semver": "bin/semver.js"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/eslint-plugin-promise": {
      "version": "6.1.1",
      "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz",
      "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==",
      "peer": true,
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "peerDependencies": {
        "eslint": "^7.0.0 || ^8.0.0"
      }
    },
    "node_modules/eslint-scope": {
      "version": "7.2.1",
      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.1.tgz",
      "integrity": "sha512-CvefSOsDdaYYvxChovdrPo/ZGt8d5lrJWleAc1diXRKhHGiTYEI26cvo8Kle/wGnsizoCJjK73FMg1/IkIwiNA==",
      "dependencies": {
        "esrecurse": "^4.3.0",
        "estraverse": "^5.2.0"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/eslint-visitor-keys": {
      "version": "3.4.1",
      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz",
      "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==",
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/espree": {
      "version": "9.6.1",
      "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
      "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
      "dependencies": {
        "acorn": "^8.9.0",
        "acorn-jsx": "^5.3.2",
        "eslint-visitor-keys": "^3.4.1"
      },
      "engines": {
        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
      },
      "funding": {
        "url": "https://opencollective.com/eslint"
      }
    },
    "node_modules/esquery": {
      "version": "1.5.0",
      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
      "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
      "dependencies": {
        "estraverse": "^5.1.0"
      },
      "engines": {
        "node": ">=0.10"
      }
    },
    "node_modules/esrecurse": {
      "version": "4.3.0",
      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
      "dependencies": {
        "estraverse": "^5.2.0"
      },
      "engines": {
        "node": ">=4.0"
      }
    },
    "node_modules/estraverse": {
      "version": "5.3.0",
      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
      "engines": {
        "node": ">=4.0"
      }
    },
    "node_modules/esutils": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/extract-zip": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
      "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
      "dependencies": {
        "debug": "^4.1.1",
        "get-stream": "^5.1.0",
        "yauzl": "^2.10.0"
      },
      "bin": {
        "extract-zip": "cli.js"
      },
      "engines": {
        "node": ">= 10.17.0"
      },
      "optionalDependencies": {
        "@types/yauzl": "^2.9.1"
      }
    },
    "node_modules/fast-deep-equal": {
      "version": "3.1.3",
      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
    },
    "node_modules/fast-json-stable-stringify": {
      "version": "2.1.0",
      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
    },
    "node_modules/fast-levenshtein": {
      "version": "2.0.6",
      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
      "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="
    },
    "node_modules/fastq": {
      "version": "1.15.0",
      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
      "dependencies": {
        "reusify": "^1.0.4"
      }
    },
    "node_modules/fd-slicer": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
      "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
      "dependencies": {
        "pend": "~1.2.0"
      }
    },
    "node_modules/file-entry-cache": {
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
      "dependencies": {
        "flat-cache": "^3.0.4"
      },
      "engines": {
        "node": "^10.12.0 || >=12.0.0"
      }
    },
    "node_modules/find-up": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
      "dependencies": {
        "locate-path": "^6.0.0",
        "path-exists": "^4.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/flat-cache": {
      "version": "3.0.4",
      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
      "dependencies": {
        "flatted": "^3.1.0",
        "rimraf": "^3.0.2"
      },
      "engines": {
        "node": "^10.12.0 || >=12.0.0"
      }
    },
    "node_modules/flatted": {
      "version": "3.2.7",
      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz",
      "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
    },
    "node_modules/for-each": {
      "version": "0.3.3",
      "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
      "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
      "dependencies": {
        "is-callable": "^1.1.3"
      }
    },
    "node_modules/fs-constants": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
    },
    "node_modules/fs.realpath": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
    },
    "node_modules/function-bind": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
    },
    "node_modules/function.prototype.name": {
      "version": "1.1.5",
      "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz",
      "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.3",
        "es-abstract": "^1.19.0",
        "functions-have-names": "^1.2.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/functions-have-names": {
      "version": "1.2.3",
      "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
      "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-caller-file": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
      "engines": {
        "node": "6.* || 8.* || >= 10.*"
      }
    },
    "node_modules/get-intrinsic": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz",
      "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==",
      "dependencies": {
        "function-bind": "^1.1.1",
        "has": "^1.0.3",
        "has-proto": "^1.0.1",
        "has-symbols": "^1.0.3"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/get-stream": {
      "version": "5.2.0",
      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
      "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
      "dependencies": {
        "pump": "^3.0.0"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/get-symbol-description": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz",
      "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "get-intrinsic": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/glob": {
      "version": "7.2.3",
      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
      "dependencies": {
        "fs.realpath": "^1.0.0",
        "inflight": "^1.0.4",
        "inherits": "2",
        "minimatch": "^3.1.1",
        "once": "^1.3.0",
        "path-is-absolute": "^1.0.0"
      },
      "engines": {
        "node": "*"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/glob-parent": {
      "version": "6.0.2",
      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
      "dependencies": {
        "is-glob": "^4.0.3"
      },
      "engines": {
        "node": ">=10.13.0"
      }
    },
    "node_modules/globals": {
      "version": "13.20.0",
      "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
      "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==",
      "dependencies": {
        "type-fest": "^0.20.2"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/globalthis": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
      "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
      "dependencies": {
        "define-properties": "^1.1.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/gopd": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
      "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
      "dependencies": {
        "get-intrinsic": "^1.1.3"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/graceful-fs": {
      "version": "4.2.11",
      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
    },
    "node_modules/graphemer": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
      "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="
    },
    "node_modules/has": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
      "dependencies": {
        "function-bind": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4.0"
      }
    },
    "node_modules/has-bigints": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
      "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-flag": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/has-property-descriptors": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz",
      "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==",
      "dependencies": {
        "get-intrinsic": "^1.1.1"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-proto": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz",
      "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-symbols": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/has-tostringtag": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz",
      "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==",
      "dependencies": {
        "has-symbols": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/hosted-git-info": {
      "version": "2.8.9",
      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
      "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
    },
    "node_modules/https-proxy-agent": {
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
      "dependencies": {
        "agent-base": "6",
        "debug": "4"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/ieee754": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ]
    },
    "node_modules/ignore": {
      "version": "5.2.4",
      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
      "engines": {
        "node": ">= 4"
      }
    },
    "node_modules/import-fresh": {
      "version": "3.3.0",
      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
      "dependencies": {
        "parent-module": "^1.0.0",
        "resolve-from": "^4.0.0"
      },
      "engines": {
        "node": ">=6"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/imurmurhash": {
      "version": "0.1.4",
      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
      "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==",
      "engines": {
        "node": ">=0.8.19"
      }
    },
    "node_modules/inflight": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
      "dependencies": {
        "once": "^1.3.0",
        "wrappy": "1"
      }
    },
    "node_modules/inherits": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
    },
    "node_modules/internal-slot": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz",
      "integrity": "sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==",
      "dependencies": {
        "get-intrinsic": "^1.2.0",
        "has": "^1.0.3",
        "side-channel": "^1.0.4"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/is-array-buffer": {
      "version": "3.0.2",
      "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz",
      "integrity": "sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "get-intrinsic": "^1.2.0",
        "is-typed-array": "^1.1.10"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-arrayish": {
      "version": "0.2.1",
      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
    },
    "node_modules/is-bigint": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
      "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
      "dependencies": {
        "has-bigints": "^1.0.1"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-boolean-object": {
      "version": "1.1.2",
      "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
      "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-callable": {
      "version": "1.2.7",
      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
      "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-core-module": {
      "version": "2.12.1",
      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz",
      "integrity": "sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==",
      "dependencies": {
        "has": "^1.0.3"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-date-object": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
      "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
      "dependencies": {
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-extglob": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-fullwidth-code-point": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/is-glob": {
      "version": "4.0.3",
      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
      "dependencies": {
        "is-extglob": "^2.1.1"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-negative-zero": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz",
      "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-number-object": {
      "version": "1.0.7",
      "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
      "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
      "dependencies": {
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-path-inside": {
      "version": "3.0.3",
      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
      "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/is-regex": {
      "version": "1.1.4",
      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
      "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-shared-array-buffer": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz",
      "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==",
      "dependencies": {
        "call-bind": "^1.0.2"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-string": {
      "version": "1.0.7",
      "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
      "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
      "dependencies": {
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-symbol": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
      "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
      "dependencies": {
        "has-symbols": "^1.0.2"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-typed-array": {
      "version": "1.1.12",
      "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz",
      "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==",
      "dependencies": {
        "which-typed-array": "^1.1.11"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/is-weakref": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
      "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
      "dependencies": {
        "call-bind": "^1.0.2"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/isarray": {
      "version": "2.0.5",
      "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
      "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
    },
    "node_modules/isexe": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
    },
    "node_modules/js-tokens": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
    },
    "node_modules/js-yaml": {
      "version": "4.1.0",
      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
      "dependencies": {
        "argparse": "^2.0.1"
      },
      "bin": {
        "js-yaml": "bin/js-yaml.js"
      }
    },
    "node_modules/json-parse-better-errors": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
    },
    "node_modules/json-parse-even-better-errors": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
    },
    "node_modules/json-schema-traverse": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
    },
    "node_modules/json-stable-stringify-without-jsonify": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
    },
    "node_modules/json5": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
      "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
      "peer": true,
      "dependencies": {
        "minimist": "^1.2.0"
      },
      "bin": {
        "json5": "lib/cli.js"
      }
    },
    "node_modules/levn": {
      "version": "0.4.1",
      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
      "dependencies": {
        "prelude-ls": "^1.2.1",
        "type-check": "~0.4.0"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/lines-and-columns": {
      "version": "1.2.4",
      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
    },
    "node_modules/load-json-file": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz",
      "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==",
      "dependencies": {
        "graceful-fs": "^4.1.2",
        "parse-json": "^4.0.0",
        "pify": "^3.0.0",
        "strip-bom": "^3.0.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/load-json-file/node_modules/parse-json": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
      "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==",
      "dependencies": {
        "error-ex": "^1.3.1",
        "json-parse-better-errors": "^1.0.1"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/locate-path": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
      "dependencies": {
        "p-locate": "^5.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/lodash.merge": {
      "version": "4.6.2",
      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
    },
    "node_modules/lru-cache": {
      "version": "6.0.0",
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
      "peer": true,
      "dependencies": {
        "yallist": "^4.0.0"
      },
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/memorystream": {
      "version": "0.3.1",
      "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz",
      "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==",
      "engines": {
        "node": ">= 0.10.0"
      }
    },
    "node_modules/minimatch": {
      "version": "3.1.2",
      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
      "dependencies": {
        "brace-expansion": "^1.1.7"
      },
      "engines": {
        "node": "*"
      }
    },
    "node_modules/minimist": {
      "version": "1.2.8",
      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
      "peer": true,
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/mitt": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.0.tgz",
      "integrity": "sha512-7dX2/10ITVyqh4aOSVI9gdape+t9l2/8QxHrFmUXu4EEUpdlxl6RudZUPZoc+zuY2hk1j7XxVroIVIan/pD/SQ=="
    },
    "node_modules/mkdirp-classic": {
      "version": "0.5.3",
      "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz",
      "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A=="
    },
    "node_modules/ms": {
      "version": "2.1.2",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
    },
    "node_modules/natural-compare": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
      "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="
    },
    "node_modules/nice-try": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
    },
    "node_modules/node-fetch": {
      "version": "2.6.7",
      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
      "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
      "dependencies": {
        "whatwg-url": "^5.0.0"
      },
      "engines": {
        "node": "4.x || >=6.0.0"
      },
      "peerDependencies": {
        "encoding": "^0.1.0"
      },
      "peerDependenciesMeta": {
        "encoding": {
          "optional": true
        }
      }
    },
    "node_modules/normalize-package-data": {
      "version": "2.5.0",
      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
      "dependencies": {
        "hosted-git-info": "^2.1.4",
        "resolve": "^1.10.0",
        "semver": "2 || 3 || 4 || 5",
        "validate-npm-package-license": "^3.0.1"
      }
    },
    "node_modules/normalize-package-data/node_modules/semver": {
      "version": "5.7.2",
      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
      "bin": {
        "semver": "bin/semver"
      }
    },
    "node_modules/npm-run-all": {
      "version": "4.1.5",
      "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz",
      "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==",
      "dependencies": {
        "ansi-styles": "^3.2.1",
        "chalk": "^2.4.1",
        "cross-spawn": "^6.0.5",
        "memorystream": "^0.3.1",
        "minimatch": "^3.0.4",
        "pidtree": "^0.3.0",
        "read-pkg": "^3.0.0",
        "shell-quote": "^1.6.1",
        "string.prototype.padend": "^3.0.0"
      },
      "bin": {
        "npm-run-all": "bin/npm-run-all/index.js",
        "run-p": "bin/run-p/index.js",
        "run-s": "bin/run-s/index.js"
      },
      "engines": {
        "node": ">= 4"
      }
    },
    "node_modules/npm-run-all/node_modules/ansi-styles": {
      "version": "3.2.1",
      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
      "dependencies": {
        "color-convert": "^1.9.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/npm-run-all/node_modules/chalk": {
      "version": "2.4.2",
      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
      "dependencies": {
        "ansi-styles": "^3.2.1",
        "escape-string-regexp": "^1.0.5",
        "supports-color": "^5.3.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/npm-run-all/node_modules/color-convert": {
      "version": "1.9.3",
      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
      "dependencies": {
        "color-name": "1.1.3"
      }
    },
    "node_modules/npm-run-all/node_modules/color-name": {
      "version": "1.1.3",
      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
    },
    "node_modules/npm-run-all/node_modules/cross-spawn": {
      "version": "6.0.5",
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
      "dependencies": {
        "nice-try": "^1.0.4",
        "path-key": "^2.0.1",
        "semver": "^5.5.0",
        "shebang-command": "^1.2.0",
        "which": "^1.2.9"
      },
      "engines": {
        "node": ">=4.8"
      }
    },
    "node_modules/npm-run-all/node_modules/escape-string-regexp": {
      "version": "1.0.5",
      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
      "engines": {
        "node": ">=0.8.0"
      }
    },
    "node_modules/npm-run-all/node_modules/has-flag": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/npm-run-all/node_modules/path-key": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
      "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/npm-run-all/node_modules/semver": {
      "version": "5.7.2",
      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz",
      "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==",
      "bin": {
        "semver": "bin/semver"
      }
    },
    "node_modules/npm-run-all/node_modules/shebang-command": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
      "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==",
      "dependencies": {
        "shebang-regex": "^1.0.0"
      },
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/npm-run-all/node_modules/shebang-regex": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
      "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/npm-run-all/node_modules/supports-color": {
      "version": "5.5.0",
      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
      "dependencies": {
        "has-flag": "^3.0.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/npm-run-all/node_modules/which": {
      "version": "1.3.1",
      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
      "dependencies": {
        "isexe": "^2.0.0"
      },
      "bin": {
        "which": "bin/which"
      }
    },
    "node_modules/object-inspect": {
      "version": "1.12.3",
      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/object-keys": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/object.assign": {
      "version": "4.1.4",
      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz",
      "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "has-symbols": "^1.0.3",
        "object-keys": "^1.1.1"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/object.values": {
      "version": "1.1.6",
      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz",
      "integrity": "sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==",
      "peer": true,
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/once": {
      "version": "1.4.0",
      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
      "dependencies": {
        "wrappy": "1"
      }
    },
    "node_modules/optionator": {
      "version": "0.9.3",
      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
      "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
      "dependencies": {
        "@aashutoshrathi/word-wrap": "^1.2.3",
        "deep-is": "^0.1.3",
        "fast-levenshtein": "^2.0.6",
        "levn": "^0.4.1",
        "prelude-ls": "^1.2.1",
        "type-check": "^0.4.0"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/p-limit": {
      "version": "3.1.0",
      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
      "dependencies": {
        "yocto-queue": "^0.1.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/p-locate": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
      "dependencies": {
        "p-limit": "^3.0.2"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/parent-module": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
      "dependencies": {
        "callsites": "^3.0.0"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/parse-json": {
      "version": "5.2.0",
      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
      "dependencies": {
        "@babel/code-frame": "^7.0.0",
        "error-ex": "^1.3.1",
        "json-parse-even-better-errors": "^2.3.0",
        "lines-and-columns": "^1.1.6"
      },
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/path-exists": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/path-is-absolute": {
      "version": "1.0.1",
      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/path-key": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/path-parse": {
      "version": "1.0.7",
      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
    },
    "node_modules/path-type": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/pend": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
      "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="
    },
    "node_modules/pidtree": {
      "version": "0.3.1",
      "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz",
      "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==",
      "bin": {
        "pidtree": "bin/pidtree.js"
      },
      "engines": {
        "node": ">=0.10"
      }
    },
    "node_modules/pify": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
      "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/prelude-ls": {
      "version": "1.2.1",
      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/prettier": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz",
      "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==",
      "bin": {
        "prettier": "bin/prettier.cjs"
      },
      "engines": {
        "node": ">=14"
      },
      "funding": {
        "url": "https://github.com/prettier/prettier?sponsor=1"
      }
    },
    "node_modules/progress": {
      "version": "2.0.3",
      "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
      "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
      "engines": {
        "node": ">=0.4.0"
      }
    },
    "node_modules/proxy-from-env": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
    },
    "node_modules/pump": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
      "dependencies": {
        "end-of-stream": "^1.1.0",
        "once": "^1.3.1"
      }
    },
    "node_modules/punycode": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
      "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==",
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/puppeteer": {
      "version": "19.11.1",
      "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz",
      "integrity": "sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==",
      "hasInstallScript": true,
      "dependencies": {
        "@puppeteer/browsers": "0.5.0",
        "cosmiconfig": "8.1.3",
        "https-proxy-agent": "5.0.1",
        "progress": "2.0.3",
        "proxy-from-env": "1.1.0",
        "puppeteer-core": "19.11.1"
      }
    },
    "node_modules/puppeteer-core": {
      "version": "19.11.1",
      "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.11.1.tgz",
      "integrity": "sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==",
      "dependencies": {
        "@puppeteer/browsers": "0.5.0",
        "chromium-bidi": "0.4.7",
        "cross-fetch": "3.1.5",
        "debug": "4.3.4",
        "devtools-protocol": "0.0.1107588",
        "extract-zip": "2.0.1",
        "https-proxy-agent": "5.0.1",
        "proxy-from-env": "1.1.0",
        "tar-fs": "2.1.1",
        "unbzip2-stream": "1.4.3",
        "ws": "8.13.0"
      },
      "engines": {
        "node": ">=14.14.0"
      },
      "peerDependencies": {
        "typescript": ">= 4.7.4"
      },
      "peerDependenciesMeta": {
        "typescript": {
          "optional": true
        }
      }
    },
    "node_modules/queue-microtask": {
      "version": "1.2.3",
      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ]
    },
    "node_modules/read-pkg": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz",
      "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==",
      "dependencies": {
        "load-json-file": "^4.0.0",
        "normalize-package-data": "^2.3.2",
        "path-type": "^3.0.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/read-pkg/node_modules/path-type": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz",
      "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==",
      "dependencies": {
        "pify": "^3.0.0"
      },
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/readable-stream": {
      "version": "3.6.2",
      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
      "dependencies": {
        "inherits": "^2.0.3",
        "string_decoder": "^1.1.1",
        "util-deprecate": "^1.0.1"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/regexp.prototype.flags": {
      "version": "1.5.0",
      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz",
      "integrity": "sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.2.0",
        "functions-have-names": "^1.2.3"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/require-directory": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
      "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
      "engines": {
        "node": ">=0.10.0"
      }
    },
    "node_modules/resolve": {
      "version": "1.22.2",
      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
      "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==",
      "dependencies": {
        "is-core-module": "^2.11.0",
        "path-parse": "^1.0.7",
        "supports-preserve-symlinks-flag": "^1.0.0"
      },
      "bin": {
        "resolve": "bin/resolve"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/resolve-from": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/reusify": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
      "engines": {
        "iojs": ">=1.0.0",
        "node": ">=0.10.0"
      }
    },
    "node_modules/rimraf": {
      "version": "3.0.2",
      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
      "dependencies": {
        "glob": "^7.1.3"
      },
      "bin": {
        "rimraf": "bin.js"
      },
      "funding": {
        "url": "https://github.com/sponsors/isaacs"
      }
    },
    "node_modules/run-parallel": {
      "version": "1.2.0",
      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ],
      "dependencies": {
        "queue-microtask": "^1.2.2"
      }
    },
    "node_modules/safe-array-concat": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.0.0.tgz",
      "integrity": "sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "get-intrinsic": "^1.2.0",
        "has-symbols": "^1.0.3",
        "isarray": "^2.0.5"
      },
      "engines": {
        "node": ">=0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/safe-buffer": {
      "version": "5.2.1",
      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/feross"
        },
        {
          "type": "patreon",
          "url": "https://www.patreon.com/feross"
        },
        {
          "type": "consulting",
          "url": "https://feross.org/support"
        }
      ]
    },
    "node_modules/safe-regex-test": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz",
      "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "get-intrinsic": "^1.1.3",
        "is-regex": "^1.1.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/semver": {
      "version": "6.3.1",
      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
      "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
      "peer": true,
      "bin": {
        "semver": "bin/semver.js"
      }
    },
    "node_modules/shebang-command": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
      "dependencies": {
        "shebang-regex": "^3.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/shebang-regex": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/shell-quote": {
      "version": "1.8.1",
      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz",
      "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==",
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/side-channel": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
      "dependencies": {
        "call-bind": "^1.0.0",
        "get-intrinsic": "^1.0.2",
        "object-inspect": "^1.9.0"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/spdx-correct": {
      "version": "3.2.0",
      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz",
      "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==",
      "dependencies": {
        "spdx-expression-parse": "^3.0.0",
        "spdx-license-ids": "^3.0.0"
      }
    },
    "node_modules/spdx-exceptions": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
    },
    "node_modules/spdx-expression-parse": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
      "dependencies": {
        "spdx-exceptions": "^2.1.0",
        "spdx-license-ids": "^3.0.0"
      }
    },
    "node_modules/spdx-license-ids": {
      "version": "3.0.13",
      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz",
      "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w=="
    },
    "node_modules/string_decoder": {
      "version": "1.3.0",
      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
      "dependencies": {
        "safe-buffer": "~5.2.0"
      }
    },
    "node_modules/string-width": {
      "version": "4.2.3",
      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
      "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
      "dependencies": {
        "emoji-regex": "^8.0.0",
        "is-fullwidth-code-point": "^3.0.0",
        "strip-ansi": "^6.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/string.prototype.padend": {
      "version": "3.1.4",
      "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.4.tgz",
      "integrity": "sha512-67otBXoksdjsnXXRUq+KMVTdlVRZ2af422Y0aTyTjVaoQkGr3mxl2Bc5emi7dOQ3OGVVQQskmLEWwFXwommpNw==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/string.prototype.trim": {
      "version": "1.2.7",
      "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz",
      "integrity": "sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/string.prototype.trimend": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz",
      "integrity": "sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/string.prototype.trimstart": {
      "version": "1.0.6",
      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz",
      "integrity": "sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "define-properties": "^1.1.4",
        "es-abstract": "^1.20.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/strip-ansi": {
      "version": "6.0.1",
      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
      "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
      "dependencies": {
        "ansi-regex": "^5.0.1"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/strip-bom": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
      "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
      "engines": {
        "node": ">=4"
      }
    },
    "node_modules/strip-json-comments": {
      "version": "3.1.1",
      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
      "engines": {
        "node": ">=8"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/supports-color": {
      "version": "7.2.0",
      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
      "dependencies": {
        "has-flag": "^4.0.0"
      },
      "engines": {
        "node": ">=8"
      }
    },
    "node_modules/supports-preserve-symlinks-flag": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/tar-fs": {
      "version": "2.1.1",
      "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
      "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
      "dependencies": {
        "chownr": "^1.1.1",
        "mkdirp-classic": "^0.5.2",
        "pump": "^3.0.0",
        "tar-stream": "^2.1.4"
      }
    },
    "node_modules/tar-stream": {
      "version": "2.2.0",
      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
      "dependencies": {
        "bl": "^4.0.3",
        "end-of-stream": "^1.4.1",
        "fs-constants": "^1.0.0",
        "inherits": "^2.0.3",
        "readable-stream": "^3.1.1"
      },
      "engines": {
        "node": ">=6"
      }
    },
    "node_modules/text-table": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="
    },
    "node_modules/through": {
      "version": "2.3.8",
      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
      "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg=="
    },
    "node_modules/tr46": {
      "version": "0.0.3",
      "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
      "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
    },
    "node_modules/tsconfig-paths": {
      "version": "3.14.2",
      "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz",
      "integrity": "sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==",
      "peer": true,
      "dependencies": {
        "@types/json5": "^0.0.29",
        "json5": "^1.0.2",
        "minimist": "^1.2.6",
        "strip-bom": "^3.0.0"
      }
    },
    "node_modules/type-check": {
      "version": "0.4.0",
      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
      "dependencies": {
        "prelude-ls": "^1.2.1"
      },
      "engines": {
        "node": ">= 0.8.0"
      }
    },
    "node_modules/type-fest": {
      "version": "0.20.2",
      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    },
    "node_modules/typed-array-buffer": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz",
      "integrity": "sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "get-intrinsic": "^1.2.1",
        "is-typed-array": "^1.1.10"
      },
      "engines": {
        "node": ">= 0.4"
      }
    },
    "node_modules/typed-array-byte-length": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz",
      "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "for-each": "^0.3.3",
        "has-proto": "^1.0.1",
        "is-typed-array": "^1.1.10"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/typed-array-byte-offset": {
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz",
      "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==",
      "dependencies": {
        "available-typed-arrays": "^1.0.5",
        "call-bind": "^1.0.2",
        "for-each": "^0.3.3",
        "has-proto": "^1.0.1",
        "is-typed-array": "^1.1.10"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/typed-array-length": {
      "version": "1.0.4",
      "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz",
      "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "for-each": "^0.3.3",
        "is-typed-array": "^1.1.9"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/unbox-primitive": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
      "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
      "dependencies": {
        "call-bind": "^1.0.2",
        "has-bigints": "^1.0.2",
        "has-symbols": "^1.0.3",
        "which-boxed-primitive": "^1.0.2"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/unbzip2-stream": {
      "version": "1.4.3",
      "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz",
      "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==",
      "dependencies": {
        "buffer": "^5.2.1",
        "through": "^2.3.8"
      }
    },
    "node_modules/uri-js": {
      "version": "4.4.1",
      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
      "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
      "dependencies": {
        "punycode": "^2.1.0"
      }
    },
    "node_modules/util-deprecate": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
    },
    "node_modules/validate-npm-package-license": {
      "version": "3.0.4",
      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
      "dependencies": {
        "spdx-correct": "^3.0.0",
        "spdx-expression-parse": "^3.0.0"
      }
    },
    "node_modules/webidl-conversions": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
      "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
    },
    "node_modules/whatwg-url": {
      "version": "5.0.0",
      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
      "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
      "dependencies": {
        "tr46": "~0.0.3",
        "webidl-conversions": "^3.0.0"
      }
    },
    "node_modules/which": {
      "version": "2.0.2",
      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
      "dependencies": {
        "isexe": "^2.0.0"
      },
      "bin": {
        "node-which": "bin/node-which"
      },
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/which-boxed-primitive": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
      "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
      "dependencies": {
        "is-bigint": "^1.0.1",
        "is-boolean-object": "^1.1.0",
        "is-number-object": "^1.0.4",
        "is-string": "^1.0.5",
        "is-symbol": "^1.0.3"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/which-typed-array": {
      "version": "1.1.11",
      "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.11.tgz",
      "integrity": "sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew==",
      "dependencies": {
        "available-typed-arrays": "^1.0.5",
        "call-bind": "^1.0.2",
        "for-each": "^0.3.3",
        "gopd": "^1.0.1",
        "has-tostringtag": "^1.0.0"
      },
      "engines": {
        "node": ">= 0.4"
      },
      "funding": {
        "url": "https://github.com/sponsors/ljharb"
      }
    },
    "node_modules/wrap-ansi": {
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
      "dependencies": {
        "ansi-styles": "^4.0.0",
        "string-width": "^4.1.0",
        "strip-ansi": "^6.0.0"
      },
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
      }
    },
    "node_modules/wrappy": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
    },
    "node_modules/ws": {
      "version": "8.13.0",
      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
      "engines": {
        "node": ">=10.0.0"
      },
      "peerDependencies": {
        "bufferutil": "^4.0.1",
        "utf-8-validate": ">=5.0.2"
      },
      "peerDependenciesMeta": {
        "bufferutil": {
          "optional": true
        },
        "utf-8-validate": {
          "optional": true
        }
      }
    },
    "node_modules/y18n": {
      "version": "5.0.8",
      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
      "engines": {
        "node": ">=10"
      }
    },
    "node_modules/yallist": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
      "peer": true
    },
    "node_modules/yargs": {
      "version": "17.7.1",
      "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz",
      "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==",
      "dependencies": {
        "cliui": "^8.0.1",
        "escalade": "^3.1.1",
        "get-caller-file": "^2.0.5",
        "require-directory": "^2.1.1",
        "string-width": "^4.2.3",
        "y18n": "^5.0.5",
        "yargs-parser": "^21.1.1"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/yargs-parser": {
      "version": "21.1.1",
      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
      "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/yauzl": {
      "version": "2.10.0",
      "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
      "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
      "dependencies": {
        "buffer-crc32": "~0.2.3",
        "fd-slicer": "~1.1.0"
      }
    },
    "node_modules/yocto-queue": {
      "version": "0.1.0",
      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
      "engines": {
        "node": ">=10"
      },
      "funding": {
        "url": "https://github.com/sponsors/sindresorhus"
      }
    }
  }
}

README.md METASEP
<p align="center">
  <a href="https://ipyvizzu.vizzuhq.com/latest/">
    <img src="https://lib.vizzuhq.com/latest/readme/infinite-60.gif" alt="Vizzu" />
  </a>
  <p align="center"><b>ipyvizzu</b> - Build animated charts in Jupyter Notebook and similar environments with a simple Python syntax</p>
  <p align="center">
    <a href="https://ipyvizzu.vizzuhq.com/latest/">Documentation</a>
    · <a href="https://ipyvizzu.vizzuhq.com/latest/examples/">Examples</a>
    · <a href="https://ipyvizzu.vizzuhq.com/latest/reference/ipyvizzu/">Code reference</a>
    · <a href="https://github.com/vizzuhq/ipyvizzu">Repository</a>
  </p>
</p>

[![PyPI version](https://badge.fury.io/py/ipyvizzu.svg)](https://badge.fury.io/py/ipyvizzu)
[![Conda Version](https://img.shields.io/conda/vn/conda-forge/ipyvizzu.svg)](https://anaconda.org/conda-forge/ipyvizzu)
[![CI-CD](https://github.com/vizzuhq/ipyvizzu/actions/workflows/cicd.yml/badge.svg?branch=main)](https://github.com/vizzuhq/ipyvizzu/actions/workflows/cicd.yml)

# ipyvizzu

## About The Project

`ipyvizzu` is an animated charting tool for [Jupyter](https://jupyter.org),
[Google Colab](https://colab.research.google.com),
[Databricks](https://docs.databricks.com/notebooks),
[Kaggle](https://www.kaggle.com/code) and [Deepnote](https://deepnote.com)
notebooks among other platforms. `ipyvizzu` enables data scientists and analysts
to utilize animation for storytelling with data using `Python`. It's built on
the open-source `JavaScript`/`C++` charting library
[Vizzu](https://github.com/vizzuhq/vizzu-lib).

**There is a new extension of `ipyvizzu`,
[ipyvizzu-story](https://vizzuhq.github.io/ipyvizzu-story/)** with which the
animated charts can be presented right from the notebooks. Since
`ipyvizzu-story`'s syntax is a bit different to `ipyvizzu`'s, we suggest you to
start from the [ipyvizzu-story repo](https://github.com/vizzuhq/ipyvizzu-story)
if you're interested in using animated charts to present your findings live or
to share your presentation as an HTML file.

Similarly to `Vizzu`, `ipyvizzu` utilizes a generic dataviz engine that
generates many types of charts and seamlessly animates between them. It is
designed for building animated data stories as it enables showing different
perspectives of the data that the viewers can easily follow.

Main features:

- Designed with animation in focus;
- Defaults based on data visualization guidelines;
- Works with `Pandas` dataframe, while also `JSON` and inline data input is
  available;
- Auto scrolling feature to keep the actual chart in position while executing
  multiple cells.

## Installation

```sh
pip install ipyvizzu
```

Visit [Installation chapter](https://ipyvizzu.vizzuhq.com/latest/installation/)
for more options and details.

## Usage

You can create the animation below with the following code snippet.

<p align="center">
  <img src="https://ipyvizzu.vizzuhq.com/latest/assets/ipyvizzu-promo.gif" alt="ipyvizzu" />
</p>

```python
import pandas as pd
from ipyvizzu import Chart, Data, Config

df = pd.read_csv(
    "https://ipyvizzu.vizzuhq.com/latest/showcases/titanic/titanic.csv"
)
data = Data()
data.add_df(df)

chart = Chart(width="640px", height="360px")

chart.animate(data)

chart.animate(
    Config(
        {
            "x": "Count",
            "y": "Sex",
            "label": "Count",
            "title": "Passengers of the Titanic",
        }
    )
)
chart.animate(
    Config(
        {
            "x": ["Count", "Survived"],
            "label": ["Count", "Survived"],
            "color": "Survived",
        }
    )
)
chart.animate(Config({"x": "Count", "y": ["Sex", "Survived"]}))
```

## Documentation

Visit our [Documentation site](https://ipyvizzu.vizzuhq.com/latest/) for more
details and a step-by-step tutorial into `ipyvizzu` or check out our
[Example gallery](https://ipyvizzu.vizzuhq.com/latest/examples/).

## Environments

`ipyvizzu` can be used in a wide variety of environments, visit
[Environments chapter](https://ipyvizzu.vizzuhq.com/latest/environments/) for
more details.

- Notebooks
  - [Jupyter Notebook](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/jupyternotebook/)
  - [Colab](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/colab/)
  - [Databricks](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/databricks/)
  - [DataCamp](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/datacamp/)
  - [Deepnote](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/deepnote/)
  - [JupyterLab](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/jupyterlab/)
  - [JupyterLite](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/jupyterlite/)
  - [Kaggle](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/kaggle/)
  - [Noteable](https://ipyvizzu.vizzuhq.com/latest/environments/notebook/noteable/)
- App platforms
  - [Streamlit](https://ipyvizzu.vizzuhq.com/latest/environments/platform/streamlit/)
  - [Flask](https://ipyvizzu.vizzuhq.com/latest/environments/platform/flask/)
  - [Panel](https://ipyvizzu.vizzuhq.com/latest/environments/platform/panel/)
  - [Mercury](https://ipyvizzu.vizzuhq.com/latest/environments/platform/mercury/)
  - [Voilà](https://ipyvizzu.vizzuhq.com/latest/environments/platform/voila/)
- BI tools
  - [Mode](https://ipyvizzu.vizzuhq.com/latest/environments/bi/mode/)
- IDEs
  - [PyCharm](https://ipyvizzu.vizzuhq.com/latest/environments/ide/pycharm/)
  - [VSCode Python](https://ipyvizzu.vizzuhq.com/latest/environments/ide/vscode/)

## Extensions

- [ipyvizzu-story](https://ipyvizzu-story.vizzuhq.com/) adds presentation
  controls to present data stories live or to share them as an interactive HTML
  file.

## Contributing

We welcome contributions to the project, visit our contributing
[guide](https://ipyvizzu.vizzuhq.com/latest/CONTRIBUTING/) for further info.

## Contact

- Join our Slack if you have any questions or comments:
  [vizzu-community.slack.com](https://join.slack.com/t/vizzu-community/shared_invite/zt-w2nqhq44-2CCWL4o7qn2Ns1EFSf9kEg)
- Drop us a line at hello@vizzuhq.com
- Follow us on Twitter: [VizzuHQ](https://twitter.com/VizzuHQ)

## Usage Statistics

`ipyvizzu` collects aggregate usage statistics by default to follow the progress
and overall trends of our library. This feature is optional, and users can
choose to opt-out. However, we do not track, collect, or store any personal data
or personally identifiable information. Please note that even when this feature
is enabled, publishing anything made with `ipyvizzu` remains GDPR compatible.
For more details, please visit
[Analytics chapter](https://ipyvizzu.vizzuhq.com/latest/tutorial/chart_settings/#analytics).

## License

Copyright © 2022-2023 [Vizzu Inc.](https://vizzuhq.com)

Released under the
[Apache 2.0 License](https://ipyvizzu.vizzuhq.com/latest/LICENSE/).

CONTRIBUTING.md METASEP
# Contributing

## Issues

You can find our open issues in the project's
[issue tracker](https://github.com/vizzuhq/ipyvizzu/issues). Please let us know
if you find any issues or have any feature requests there.

## Contributing

If you want to contribute to the project, your help is very welcome. Just fork
the project, make your changes and send us a pull request. You can find the
detailed description of how to do this in
[Github's guide to contributing to projects](https://docs.github.com/en/get-started/quickstart/contributing-to-projects).

## CI-CD

### Development environment

For contributing to the project, it is recommended to use `Python` `3.10` as the
primary programming language for most parts of the source code. However, a
specific portion of the codebase is written in `JavaScript`. If you plan to
contribute to this `JavaScript` part or the documentation, you will need
`Node.js`, preferably version `18`.

The following steps demonstrate how to set up the development environment on an
`Ubuntu` `22.04` operating system. However, the process can be adapted for other
operating systems as well.

To start using the `ipyvizzu` development environment, you need to create a
virtual environment and install `pdm` within it.

```sh
python3.10 -m venv ".venv"
source .venv/bin/activate
pip install pdm==2.8.0
```

Once set up, you can utilize the pre-defined `pdm` scripts. For example, you can
initialize the entire development environment using the command `pdm run init`,
or specific parts like `init_src_py`, `init_src`, `init_docs`, or `init_tools`.

```sh
pdm run init
```

**Note:** For all available `pdm` scripts, run `pdm run --list`.

The development requirements are installed based on the `pdm.lock` and
`package-lock.json` files. To update the development requirements, you can use
the command `pdm run lock`.

For better development practices, you can set up `pre-commit` and `pre-push`
hooks in your local `Git` repository. The `pre-commit` hook will format the code
automatically, and the `pre-push` hook will run the CI steps before pushing your
changes.

```sh
pre-commit install --hook-type pre-commit --hook-type pre-push -c ./tools/ci/.pre-commit-ubuntu.yaml
```

**Note:** The provided `.pre-commit-ubuntu.yaml` configuration file is tailored
for `Ubuntu` `22.04`. If you intend to use another operating system, you may
need to create a custom configuration file suitable for that environment.

### CI

The CI pipeline includes code formatting checks, code analysis, typing
validation, and unit tests for the `ipyvizzu` project.

To run the entire CI pipeline, execute the following `pdm` script:

```sh
pdm run ci
```

However, if you want to run the CI steps on specific parts of the project, you
can use the following scripts: `ci_src_py`, `ci_src`, `ci_docs`, or `ci_tools`.

#### Formatting

You can check the code's formatting using the `format` script:

```sh
pdm run format
```

If you need to fix any formatting issues, you can use the `fix_format` script:

```sh
pdm run fix_format
```

If you wish to format specific parts of the project, you can use the following
scripts: `format_src_py`, `format_src`, `format_docs`, `format_tools`, or
`fix_format_src_py`, `fix_format_src`, `fix_format_docs`, `fix_format_tools`.

#### Code analyses

To perform code analyses, you can use the `lint` script:

```sh
pdm run lint
```

If you need to run code analyses for specific parts of the project, you can
utilize the following scripts: `lint_src_py`, `lint_src`, `lint_docs`, or
`lint_tools`.

#### Typing

For type checking, you can use the `type` script:

```sh
pdm run type
```

If you want to check specific parts of the project, you can use the following
scripts: `type_src` or `type_tools`.

#### Testing

The project is tested using the `unittest` testing framework and `tox`. To run
the tests, you can use the `test` script:

```sh
pdm run test
```

### Documentation

**Note:** The preset, static, animated, and analytical operation examples are
generated from the [vizzu-lib](https://github.com/vizzuhq/vizzu-lib) repository.
If you wish to build them as well, run the following command before building the
site.

```sh
git clone --depth 1 https://github.com/vizzuhq/vizzu-lib.git
```

To build the documentation, you can use the `docs_build` script:

```sh
pdm run docs_build
```

You can read the online version at [ipyvizzu.com](https://ipyvizzu.vizzuhq.com).

### Release

`ipyvizzu` is distributed on [pypi](https://pypi.org/project/ipyvizzu).
**Note:** You need to be an administrator to release the project.

To release `ipyvizzu`, follow the steps below:

- Increase the version number in `__version__.py`. The version bump should be in
  a separate commit.

- Generate the release notes and publish the new release on
  [Releases](https://github.com/vizzuhq/ipyvizzu/releases).

**Note:** Publishing a new release will automatically trigger the `release`
workflow, which builds, checks, and uploads the `ipyvizzu` package to
[pypi](https://pypi.org/project/ipyvizzu).

Before making a release, you can build and check the package using the
`pkg_release` script:

```sh
pdm run pkg_release
```

CODE_OF_CONDUCT.md METASEP
# Code of Conduct

See [Code of Conduct](https://lib.vizzuhq.com/latest/CODE_OF_CONDUCT/) of the
`Vizzu` community.

tests/utils/normalizer.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import re
import sys
from typing import Optional
from unittest.mock import MagicMock


class Normalizer:
    def __init__(self) -> None:
        self.id1_pattern = re.compile(r"'[a-f0-9]{7}'", flags=re.MULTILINE)
        self.id2_pattern = re.compile(r"\\'[a-f0-9]{7}\\'", flags=re.MULTILINE)
        self.id3_pattern = re.compile(r"\"[a-f0-9]{7}\"", flags=re.MULTILINE)

    def normalize_id(self, output: str) -> str:
        normalized_output = output
        normalized_output = self.id1_pattern.sub("id", normalized_output)
        normalized_output = self.id2_pattern.sub("id", normalized_output)
        normalized_output = self.id3_pattern.sub("id", normalized_output)
        return normalized_output

    def normalize_output(
        self, output: MagicMock, start_index: int = 0, end_index: Optional[int] = None
    ) -> str:
        output_items = []
        if not end_index:
            end_index = len(output.call_args_list)
        for block in output.call_args_list[start_index:end_index]:
            if sys.version_info >= (3, 8):
                args = block.args
            else:
                # TODO: remove once support for Python 3.7 is dropped
                args, _ = block
            output_items.append(args[0])
        return self.normalize_id("\n".join(output_items)).strip()

tests/utils/import_error.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from contextlib import contextmanager
import os


class RaiseImportError:
    @classmethod
    @contextmanager
    def module_name(cls, module_name: str):
        original_value = os.environ.get("RAISE_IMPORT_ERROR", None)
        os.environ["RAISE_IMPORT_ERROR"] = module_name
        try:
            yield
        finally:
            if original_value is None:
                os.environ.pop("RAISE_IMPORT_ERROR", None)
            else:
                os.environ["RAISE_IMPORT_ERROR"] = original_value

    @staticmethod
    def overwrite_imports() -> None:
        builtins = globals()["__builtins__"]

        def overwrite_import(original_import_builtin):
            def import_replacement(name, *args, **kwargs):
                module_name = os.environ.get("RAISE_IMPORT_ERROR", None)
                if name == module_name:
                    raise ImportError(f"{module_name} is not available")
                return original_import_builtin(name, *args, **kwargs)

            return import_replacement

        builtins["__import__"] = overwrite_import(builtins["__import__"])

tests/utils/__init__.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from tests.utils.import_error import RaiseImportError


RaiseImportError.overwrite_imports()

tests/test_method.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import unittest

from ipyvizzu import (
    Animate,
    AnimationMerger,
    ChartProperty,
    Config,
    EventHandler,
    EventOff,
    EventOn,
    Feature,
    Log,
    Method,
    Snapshot,
    Store,
    Style,
)


class TestMethod(unittest.TestCase):
    def test_method(self) -> None:
        method = Method()
        with self.assertRaises(AttributeError):
            method.dump()

    def test_animate_with_anim_without_option(self) -> None:
        animation = Snapshot("abc1234")
        method = Animate(chart_target=animation)
        self.assertEqual(
            {
                "chart_target": '"abc1234"',
                "chart_anim_opts": "undefined",
            },
            method.dump(),
        )

    def test_animate_with_animmerger_without_option(self) -> None:
        config = Config({"title": "My first chart"})
        style = Style({"title": {"backgroundColor": "#A0A0A0"}})
        animation_merger = AnimationMerger()
        animation_merger.merge(config)
        animation_merger.merge(style)
        method = Animate(chart_target=animation_merger)
        self.assertEqual(
            {
                "chart_target": '{"config": '
                + '{"title": "My first chart"}, '
                + '"style": {"title": {"backgroundColor": "#A0A0A0"}}}',
                "chart_anim_opts": "undefined",
            },
            method.dump(),
        )

    def test_animate_with_anim_with_option(self) -> None:
        animation = Snapshot("abc1234")
        option = {"duration": 1, "easing": "linear"}
        method = Animate(chart_target=animation, chart_anim_opts=option)
        self.assertEqual(
            {
                "chart_target": '"abc1234"',
                "chart_anim_opts": '{"duration": 1, "easing": "linear"}',
            },
            method.dump(),
        )

    def test_animate_with_animmerger_with_option(self) -> None:
        config = Config({"title": "My first chart"})
        style = Style({"title": {"backgroundColor": "#A0A0A0"}})
        animation_merger = AnimationMerger()
        animation_merger.merge(config)
        animation_merger.merge(style)
        option = {"duration": 1, "easing": "linear"}
        method = Animate(chart_target=animation_merger, chart_anim_opts=option)
        self.assertEqual(
            {
                "chart_target": '{"config": '
                + '{"title": "My first chart"}, '
                + '"style": {"title": {"backgroundColor": "#A0A0A0"}}}',
                "chart_anim_opts": '{"duration": 1, "easing": "linear"}',
            },
            method.dump(),
        )

    def test_feature(self) -> None:
        method = Feature(name="tooltip", enabled=True)
        self.assertEqual({"name": "tooltip", "enabled": "true"}, method.dump())

    def test_store(self) -> None:
        method = Store(snapshot_id="abc1234")
        self.assertEqual({"id": "abc1234"}, method.dump())

    def test_event_on(self) -> None:
        event_handler = EventHandler(
            event="click", handler="alert(JSON.stringify(event.data));"
        )
        method = EventOn(event_handler=event_handler)
        method_dump = method.dump()
        self.assertEqual(
            {
                "id": method_dump["id"],
                "event": "click",
                "handler": "alert(JSON.stringify(event.data));",
            },
            method_dump,
        )

    def test_event_off(self) -> None:
        event_handler = EventHandler(
            event="click", handler="alert(JSON.stringify(event.data));"
        )
        method = EventOff(event_handler=event_handler)
        method_dump = method.dump()
        self.assertEqual(
            {
                "id": method_dump["id"],
                "event": "click",
            },
            method_dump,
        )

    def test_log(self) -> None:
        method = Log(chart_property=ChartProperty.CONFIG)
        self.assertEqual(
            {
                "chart_property": "config",
            },
            method.dump(),
        )

tests/test_json.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import json
import unittest

from ipyvizzu import RawJavaScriptEncoder, RawJavaScript


class TestRawJavaScriptEncoder(unittest.TestCase):
    def test_encoder_with_rawjavascript(self) -> None:
        raw_javascript = RawJavaScript("null")
        self.assertEqual(
            json.dumps({"test": raw_javascript}, cls=RawJavaScriptEncoder),
            '{"test": null}',
        )

    def test_encoder_with_not_rawjavascript(self) -> None:
        class NotRawJavaScript:
            # pylint: disable=too-few-public-methods

            def __init__(self) -> None:
                pass

        not_raw_javascript = NotRawJavaScript()
        with self.assertRaises(TypeError):
            json.dumps({"test": not_raw_javascript}, cls=RawJavaScriptEncoder)

tests/test_fugue.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

from contextlib import redirect_stdout
import io
import pathlib
import sys
import unittest

import pandas as pd

from tests.utils.normalizer import Normalizer


if sys.version_info >= (3, 7):
    import fugue.api as fa
    import ipyvizzu.integrations.fugue  # register the extension  # pylint: disable=unused-import
else:
    # TODO: remove once support for Python 3.6 is dropped
    pass


class TestFugue(unittest.TestCase):
    # TODO: remove decorator once support for Python 3.6 is dropped
    @unittest.skipUnless(sys.version_info >= (3, 7), "at least Python 3.7 is required")
    def test_fugue_extension_preset(self) -> None:
        ref = pathlib.Path(__file__).parent / "assets" / "fugue_preset.txt"
        with open(ref, "r", encoding="utf8") as f_ref:
            ref_content = f_ref.read()
        df = pd.DataFrame({"a": list("abcde"), "b": range(5)})
        stdout = io.StringIO()
        with redirect_stdout(stdout):
            fa.fugue_sql_flow(
                """
                SELECT * FROM df WHERE b<5

                OUTPUT USING vizzu:bar(x="a",y="b")
            """,
                df=df,
            ).run()
        self.assertEqual(
            Normalizer().normalize_id("\n".join(stdout.getvalue().split("\n")[1:])),
            ref_content,
        )

    # TODO: remove decorator once support for Python 3.6 is dropped
    @unittest.skipUnless(sys.version_info >= (3, 7), "at least Python 3.7 is required")
    def test_fugue_extension_timeline(self) -> None:
        ref = pathlib.Path(__file__).parent / "assets" / "fugue_timeline.txt"
        with open(ref, "r", encoding="utf8") as f_ref:
            ref_content = f_ref.read()
        df = pd.DataFrame({"a": list("abcde"), "b": range(5), "c": [1, 1, 2, 2, 3]})
        stdout = io.StringIO()
        with redirect_stdout(stdout):
            fa.fugue_sql_flow(
                """
                SELECT * FROM df WHERE b<5

                OUTPUT USING vizzu:timeline_bar(
                    by="c",
                    config={"x":"b","y":"a",title="x %s"},
                    duration=0.3
                )
            """,
                df=df,
            ).run()
        self.assertEqual(
            Normalizer().normalize_id("\n".join(stdout.getvalue().split("\n")[1:])),
            ref_content,
        )

tests/test_chart.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import abc
from typing import Callable
import unittest
import unittest.mock

from ipyvizzu import (
    Animation,
    Chart,
    ChartProperty,
    Config,
    Data,
    EventHandler,
    Snapshot,
    Style,
)

from tests.utils.normalizer import Normalizer


class TestChart(unittest.TestCase, abc.ABC):
    normalizer: Normalizer

    @classmethod
    def setUpClass(cls) -> None:
        cls.normalizer = Normalizer()

    def setUp(self) -> None:
        self.patch = unittest.mock.patch(self.mock)
        self.trash = self.patch.start()
        self.chart = Chart()
        self.chart.initializing()

    def tearDown(self) -> None:
        self.patch.stop()

    @property
    def mock(self) -> str:
        return "ipyvizzu.chart.display_javascript"


class TestChartInit(TestChart):
    def test_init(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart()
            chart.initializing()
            self.assertEqual(
                self.normalizer.normalize_output(output, 2),
                "window.ipyvizzu.createChart("
                + "element, "
                + "id, "
                + "'https://cdn.jsdelivr.net/npm/vizzu@0.8/dist/vizzu.min.js', "
                + "'800px', '480px');",
            )

    def test_init_vizzu(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart(
                vizzu="https://cdn.jsdelivr.net/npm/vizzu@0.4.1/dist/vizzu.min.js"
            )
            chart.initializing()
            self.assertEqual(
                self.normalizer.normalize_output(output, 2),
                "window.ipyvizzu.createChart("
                + "element, "
                + "id, "
                + "'https://cdn.jsdelivr.net/npm/vizzu@0.4.1/dist/vizzu.min.js', "
                + "'800px', '480px');",
            )

    def test_init_div(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart(width="400px", height="240px")
            chart.initializing()
            self.assertEqual(
                self.normalizer.normalize_output(output, 2),
                "window.ipyvizzu.createChart("
                + "element, "
                + "id, "
                + "'https://cdn.jsdelivr.net/npm/vizzu@0.8/dist/vizzu.min.js', "
                + "'400px', '240px');",
            )

    def test_init_display_invalid(self) -> None:
        with self.assertRaises(ValueError):
            Chart(display="invalid")

    def test_init_display_begin(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart(display="begin")
            chart.animate(Snapshot("abc1234"))
            self.assertEqual(
                self.normalizer.normalize_output(output, 3),
                "window.ipyvizzu.animate(element, id, id, 'begin', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_init_display_actual(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart(display="actual")
            chart.animate(Snapshot("abc1234"))
            self.assertEqual(
                self.normalizer.normalize_output(output, 3),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_init_display_end(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart(display="end")
            chart.animate(Snapshot("abc1234"))
            self.assertEqual(
                self.normalizer.normalize_output(output, 3),
                "window.ipyvizzu.animate(element, id, id, 'end', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_manual_init(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.initializing()
            self.chart.initializing()
            self.chart.initializing()
            self.chart.animate(Snapshot("abc1234"))
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_init_register_events(self) -> None:
        class IPyEvents:
            # pylint: disable=too-few-public-methods

            @staticmethod
            def register(event: str, function: Callable[[], None]) -> None:
                # pylint: disable=unused-argument

                function()

        class IPy:
            # pylint: disable=too-few-public-methods

            events = IPyEvents

        get_ipython_mock = "ipyvizzu.chart.get_ipython"
        with unittest.mock.patch(get_ipython_mock, return_value=IPy()):
            with unittest.mock.patch(self.mock) as output:
                chart = Chart()
                chart.initializing()
                self.assertEqual(
                    self.normalizer.normalize_output(output, 2, 3),
                    "if (window.IpyVizzu) { window.IpyVizzu.clearInhibitScroll(element); }",
                )


class TestChartMethods(TestChart):
    def test_animate_chart_target_has_to_be_passed(self) -> None:
        with self.assertRaises(ValueError):
            self.chart.animate()

    def test_animate_chart_target_has_to_be_passed_even_if_chart_anim_opts_passed(
        self,
    ) -> None:
        with self.assertRaises(ValueError):
            self.chart.animate(duration="500ms")

    def test_animate_one_chart_target(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            data = Data()
            data.add_record(["Rock", "Hard", 96])
            self.chart.animate(data)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + 'lib => { return {"data": {"records": [["Rock", "Hard", 96]]}} }, '
                + "undefined);",
            )

    def test_animate_one_chart_target_with_chart_anim_opts(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            data = Data()
            data.add_record(["Rock", "Hard", 96])
            self.chart.animate(data, duration="500ms")
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + 'lib => { return {"data": {"records": [["Rock", "Hard", 96]]}} }, '
                + '{"duration": "500ms"});',
            )

    def test_animate_snapshot_chart_target(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            snapshot = Snapshot("abc1234")
            self.chart.animate(snapshot)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_animate_snapshot_chart_target_with_chart_anim_opts(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            snapshot = Snapshot("abc1234")
            self.chart.animate(snapshot, duration="500ms")
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + "lib => { return id }, "
                + '{"duration": "500ms"});',
            )

    def test_animate_stored_animation_chart_target(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            animation = Animation("abc1234")
            self.chart.animate(animation, duration="500ms")
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + "lib => { return id }, "
                + '{"duration": "500ms"});',
            )

    def test_animate_more_chart_target(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            data = Data()
            data.add_record(["Rock", "Hard", 96])
            config = Config({"channels": {"label": {"attach": ["Popularity"]}}})
            style = Style({"title": {"backgroundColor": "#A0A0A0"}})
            self.chart.animate(data, config, style)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + 'lib => { return {"data": {"records": [["Rock", "Hard", 96]]}, '
                + '"config": {"channels": {"label": {"attach": ["Popularity"]}}}, '
                + '"style": {"title": {"backgroundColor": "#A0A0A0"}}} }, '
                + "undefined);",
            )

    def test_animate_more_chart_target_with_chart_anim_opts(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            data = Data()
            data.add_record(["Rock", "Hard", 96])
            config = Config({"channels": {"label": {"attach": ["Popularity"]}}})
            style = Style({"title": {"backgroundColor": "#A0A0A0"}})
            self.chart.animate(data, config, style, duration="500ms")
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + 'lib => { return {"data": {"records": [["Rock", "Hard", 96]]}, '
                + '"config": {"channels": {"label": {"attach": ["Popularity"]}}}, '
                + '"style": {"title": {"backgroundColor": "#A0A0A0"}}} }, '
                + '{"duration": "500ms"});',
            )

    def test_animate_more_chart_target_with_conflict(self) -> None:
        data = Data()
        data.add_record(["Rock", "Hard", 96])
        config1 = Config({"channels": {"label": {"attach": ["Popularity"]}}})
        config2 = Config({"title": "Test"})
        style = Style({"title": {"backgroundColor": "#A0A0A0"}})
        with self.assertRaises(ValueError):
            self.chart.animate(data, config1, style, config2)

    def test_animate_more_chart_target_with_snapshot(self) -> None:
        data = Data()
        data.add_record(["Rock", "Hard", 96])
        config = Config({"channels": {"label": {"attach": ["Popularity"]}}})
        style = Style({"title": {"backgroundColor": "#A0A0A0"}})
        snapshot = Snapshot("abc1234")
        with self.assertRaises(ValueError):
            self.chart.animate(data, config, style, snapshot)

    def test_animate_more_calls(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            data = Data()
            data.add_record(["Rock", "Hard", 96])
            config1 = Config({"channels": {"label": {"attach": ["Popularity"]}}})
            config2 = Config({"title": "Test"})
            style = Style({"title": {"backgroundColor": "#A0A0A0"}})
            self.chart.animate(data, config1, style)
            self.chart.animate(config2)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + 'lib => { return {"data": {"records": [["Rock", "Hard", 96]]}, '
                + '"config": {"channels": {"label": {"attach": ["Popularity"]}}}, '
                + '"style": {"title": {"backgroundColor": "#A0A0A0"}}} }, '
                + "undefined);\n"
                + "window.ipyvizzu.animate(element, id, id, 'actual', false, "
                + 'lib => { return {"config": {"title": "Test"}} }, '
                + "undefined);",
            )

    def test_animate_with_not_default_scroll_into_view(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            data = Data()
            data.add_record(["Rock", "Hard", 96])
            scroll_into_view = not self.chart.scroll_into_view
            self.chart.scroll_into_view = scroll_into_view
            self.chart.animate(data)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate("
                + f"element, id, id, 'actual', {str(scroll_into_view).lower()}, "
                + 'lib => { return {"data": {"records": [["Rock", "Hard", 96]]}} }, '
                + "undefined);",
            )

    def test_feature(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.feature("tooltip", True)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.feature(element, id, 'tooltip', true);",
            )

    def test_store(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.store()
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.store(element, id, id);",
            )


class TestChartEvents(TestChart):
    def test_on(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            handler_method = """event.renderingContext.fillStyle =
                (event.data.text === 'Jazz') ? 'red' : 'gray';"""
            self.chart.on("plot-axis-label-draw", handler_method)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.setEvent("
                + "element, id, id, 'plot-axis-label-draw', "
                + "event => "
                + "{ event.renderingContext.fillStyle = "
                + "(event.data.text === 'Jazz') ? 'red' : 'gray'; });",
            )

    def test_off(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            handler_method = "alert(JSON.stringify(event.data));"
            handler = EventHandler("click", handler_method)
            self.chart.off(handler)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.clearEvent(element, id, id, 'click');",
            )


class TestChartLogs(TestChart):
    def test_log_config(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.log(ChartProperty.CONFIG)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.log(element, id, 'config');",
            )

    def test_log_style(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.log(ChartProperty.STYLE)
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.log(element, id, 'style');",
            )

    def test_log_invalid(self) -> None:
        with self.assertRaises(AttributeError):
            self.chart.log(ChartProperty.INVALID)  # type: ignore  # pylint: disable=no-member


class TestChartAnalytics(TestChart):
    def test_analytics_default_value(self) -> None:
        chart = Chart()
        self.assertEqual(
            chart.analytics,
            True,
        )

    def test_change_analytics_before_initializing(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart()
            chart.analytics = False
            chart.initializing()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "if (window.IpyVizzu) window.IpyVizzu.changeAnalyticsTo(false);" + "\n"
                "window.ipyvizzu.createChart("
                + "element, "
                + "id, "
                + "'https://cdn.jsdelivr.net/npm/vizzu@0.8/dist/vizzu.min.js', "
                + "'800px', '480px');",
            )

    def test_change_analytics_after_initializing(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            chart = Chart()
            chart.initializing()
            chart.analytics = False
            chart.analytics = True
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "if (window.IpyVizzu) window.IpyVizzu.changeAnalyticsTo(true);"
                + "\n"
                + "window.ipyvizzu.createChart("
                + "element, "
                + "id, "
                + "'https://cdn.jsdelivr.net/npm/vizzu@0.8/dist/vizzu.min.js', "
                + "'800px', '480px');"
                + "\n"
                + "if (window.IpyVizzu) window.IpyVizzu.changeAnalyticsTo(false);"
                + "\n"
                + "if (window.IpyVizzu) window.IpyVizzu.changeAnalyticsTo(true);",
            )


class TestChartDisplay(TestChart):
    def test_repr_html_if_display_is_not_manual(self) -> None:
        self.chart.animate(Snapshot("abc1234"))
        with self.assertRaises(AssertionError):
            self.chart._repr_html_()  # pylint: disable=protected-access

    def test_show_if_display_is_not_manual(self) -> None:
        self.chart.animate(Snapshot("abc1234"))
        with self.assertRaises(AssertionError):
            self.chart.show()

    def test_repr_html(self) -> None:
        display_mock = "ipyvizzu.Chart._display"
        with unittest.mock.patch(display_mock) as output:
            chart = Chart(display="manual")
            chart.animate(Snapshot("abc1234"))
            self.assertEqual(
                chart._showed,  # pylint: disable=protected-access
                False,
            )
            chart._repr_html_()  # pylint: disable=protected-access
            self.assertEqual(
                chart._showed,  # pylint: disable=protected-access
                True,
            )
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'manual', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_show(self) -> None:
        self.chart = Chart(display="manual")
        display_mock = "ipyvizzu.Chart._display"
        with unittest.mock.patch(display_mock) as output:
            self.chart.animate(Snapshot("abc1234"))
            self.assertEqual(
                self.chart._showed,  # pylint: disable=protected-access
                False,
            )
            self.chart.show()
            self.assertEqual(
                self.chart._showed,  # pylint: disable=protected-access
                True,
            )
            self.assertEqual(
                self.normalizer.normalize_output(output),
                "window.ipyvizzu.animate(element, id, id, 'manual', false, "
                + "lib => { return id }, "
                + "undefined);",
            )

    def test_repr_html_after_repr_html(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart._repr_html_()  # pylint: disable=protected-access
        with self.assertRaises(AssertionError):
            self.chart._repr_html_()  # pylint: disable=protected-access

    def test_repr_html_after_show(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart.show()
        with self.assertRaises(AssertionError):
            self.chart._repr_html_()  # pylint: disable=protected-access

    def test_show_after_show(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart.show()
        with self.assertRaises(AssertionError):
            self.chart.show()

    def test_show_after_repr_html(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart._repr_html_()  # pylint: disable=protected-access
        with self.assertRaises(AssertionError):
            self.chart.show()

    def test_animate_after_repr_html(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart._repr_html_()  # pylint: disable=protected-access
        with self.assertRaises(AssertionError):
            self.chart.animate(Snapshot("abc1234"))

    def test_animate_after_show(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart.show()
        with self.assertRaises(AssertionError):
            self.chart.animate(Snapshot("abc1234"))

    def test_feature_after_repr_html(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart._repr_html_()  # pylint: disable=protected-access
        with self.assertRaises(AssertionError):
            self.chart.feature("tooltip", True)

    def test_feature_after_show(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart.show()
        with self.assertRaises(AssertionError):
            self.chart.feature("tooltip", True)

    def test_store_after_repr_html_(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart._repr_html_()  # pylint: disable=protected-access
        with self.assertRaises(AssertionError):
            self.chart.store()

    def test_store_after_show(self) -> None:
        self.chart = Chart(display="manual")
        self.chart.animate(Snapshot("abc1234"))
        self.chart.show()
        with self.assertRaises(AssertionError):
            self.chart.store()

tests/test_animationcontrol.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import unittest
import unittest.mock

from ipyvizzu import Style

from tests.test_chart import TestChart


class TestAnimationControl(TestChart):
    def test_must_be_called_after_animate(self) -> None:
        with self.assertRaises(AssertionError):
            self.chart.control.seek("50%")

    def test_cancel(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.cancel()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'cancel', id, id);",
            )

    def test_pause(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.pause()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'pause', id, id);",
            )

    def test_play(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.play()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'play', id, id);",
            )

    def test_reverse(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.reverse()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'reverse', id, id);",
            )

    def test_seek(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.seek("50%")
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'seek', id, id, '50%');",
            )

    def test_stop(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.stop()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'stop', id, id);",
            )

    def test_store(self) -> None:
        with unittest.mock.patch(self.mock) as output:
            self.chart.animate(Style(None))
            self.chart.control.store()
            self.assertEqual(
                self.normalizer.normalize_output(output, 1),
                "window.ipyvizzu.control(element, 'store', id, id, id);",
            )

tests/test_animation.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import json
import pathlib
from typing import List
import unittest

import jsonschema  # type: ignore
import numpy as np
import pandas as pd

from ipyvizzu.data.type_alias import Record

from ipyvizzu import (
    Animation,
    AnimationMerger,
    Config,
    Data,
    Keyframe,
    PlainAnimation,
    Snapshot,
    Style,
)

from tests.utils.import_error import RaiseImportError


class TestPlainAnimation(unittest.TestCase):
    def test_plainanimation(self) -> None:
        animation = PlainAnimation(geometry="circle")
        self.assertEqual({"geometry": "circle"}, animation.build())


class TestDataSchema(unittest.TestCase):
    def setUp(self) -> None:
        self.data = Data()

    def test_schema_dimension_only(self) -> None:
        self.data.add_dimension("Genres", ["Pop", "Rock"])
        with self.assertRaises(jsonschema.ValidationError):
            self.data.build()

    def test_schema_measure_only(self) -> None:
        self.data.add_measure("Popularity", [[114, 96]])
        with self.assertRaises(jsonschema.ValidationError):
            self.data.build()

    def test_schema_data_cube_and_series(self) -> None:
        self.data.add_dimension("Genres", ["Pop", "Rock"])
        self.data.add_measure("Popularity", [[114, 96]])
        self.data.add_series("Kinds", ["Hard"])
        with self.assertRaises(jsonschema.ValidationError):
            self.data.build()

    def test_schema_data_cube_and_records(self) -> None:
        self.data.add_dimension("Genres", ["Pop", "Rock"])
        self.data.add_measure("Popularity", [[114, 96]])
        self.data.add_records([["Rock", "Hard", 96], ["Pop", "Hard", 114]])
        with self.assertRaises(jsonschema.ValidationError):
            self.data.build()


class TestDataClassmethods(unittest.TestCase):
    asset_dir: pathlib.Path

    @classmethod
    def setUpClass(cls) -> None:
        cls.asset_dir = pathlib.Path(__file__).parent / "assets"

    def test_filter(self) -> None:
        data = Data.filter("filter_expr")
        # instead of build() test with dump() because contains raw js
        self.assertEqual(
            '{"data": {"filter": record => { return (filter_expr) }}}',
            data.dump(),
        )

    def test_filter_multiline(self) -> None:
        filter_expr = """
        A && 
            B ||
            C
        """
        data = Data.filter(filter_expr)
        # instead of build() test with dump() because contains raw js
        self.assertEqual(
            '{"data": {"filter": record => { return (A && B || C) }}}',
            data.dump(),
        )

    def test_filter_can_be_none(self) -> None:
        data = Data.filter(None)
        # instead of build() test with dump() because contains raw js
        self.assertEqual(
            '{"data": {"filter": null}}',
            data.dump(),
        )

    def test_from_json(self) -> None:
        data = Data.from_json(self.asset_dir / "data_from_json.json")
        self.assertEqual(
            {
                "data": {
                    "dimensions": [
                        {"name": "Genres", "values": ["Rock", "Pop"]},
                        {"name": "Kinds", "values": ["Hard"]},
                    ],
                    "measures": [{"name": "Popularity", "values": [[114, 96]]}],
                }
            },
            data.build(),
        )


class TestData(unittest.TestCase):
    def setUp(self) -> None:
        self.data = Data()

    def test_set_filter(self) -> None:
        self.data.add_records([["Rock", "Hard", 96], ["Pop", "Hard", 114]])
        self.data.set_filter("filter_expr")
        self.assertEqual(
            '{"data": {"records": '
            + '[["Rock", "Hard", 96], ["Pop", "Hard", 114]], '
            + '"filter": record => { return (filter_expr) }}}',
            self.data.dump(),
        )

    def test_set_filter_can_be_none(self) -> None:
        self.data.add_records([["Rock", "Hard", 96], ["Pop", "Hard", 114]])
        self.data.set_filter(None)
        self.assertEqual(
            '{"data": {"records": [["Rock", "Hard", 96], ["Pop", "Hard", 114]], "filter": null}}',
            self.data.dump(),
        )

    def test_record_list(self) -> None:
        self.data.add_record(["Rock", "Hard", 96])
        self.data.add_record(["Pop", "Hard", 114])
        self.assertEqual(
            {"data": {"records": [["Rock", "Hard", 96], ["Pop", "Hard", 114]]}},
            self.data.build(),
        )

    def test_record_dict(self) -> None:
        self.data.add_record({"Genres": "Rock", "Kinds": "Hard", "Popularity": 96})
        self.data.add_record({"Genres": "Pop", "Kinds": "Hard", "Popularity": 114})
        self.assertEqual(
            {
                "data": {
                    "records": [
                        {"Genres": "Rock", "Kinds": "Hard", "Popularity": 96},
                        {"Genres": "Pop", "Kinds": "Hard", "Popularity": 114},
                    ]
                }
            },
            self.data.build(),
        )

    def test_records(self) -> None:
        self.data.add_records([["Rock", "Hard", 96], ["Pop", "Hard", 114]])
        self.assertEqual(
            {"data": {"records": [["Rock", "Hard", 96], ["Pop", "Hard", 114]]}},
            self.data.build(),
        )

    def test_series(self) -> None:
        self.data.add_series("Genres", ["Rock", "Pop"], type="dimension")
        self.data.add_series("Kinds", ["Hard"])
        self.data.add_series("Popularity", [96, 114], type="measure")
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "Genres",
                            "type": "dimension",
                            "values": ["Rock", "Pop"],
                        },
                        {"name": "Kinds", "values": ["Hard"]},
                        {"name": "Popularity", "type": "measure", "values": [96, 114]},
                    ]
                }
            },
            self.data.build(),
        )

    def test_series_without_values(self) -> None:
        self.data.add_series("Genres", type="dimension")
        self.data.add_series("Kinds", type="dimension")
        self.data.add_series("Popularity", type="measure")
        records: List[Record] = [["Rock", "Hard", 96], ["Pop", "Hard", 114]]
        self.data.add_records(records)
        self.assertEqual(
            {
                "data": {
                    "records": [["Rock", "Hard", 96], ["Pop", "Hard", 114]],
                    "series": [
                        {"name": "Genres", "type": "dimension"},
                        {"name": "Kinds", "type": "dimension"},
                        {"name": "Popularity", "type": "measure"},
                    ],
                }
            },
            self.data.build(),
        )

    def test_data_cube(self) -> None:
        self.data.add_dimension("Genres", ["Pop", "Rock"])
        self.data.add_dimension("Kinds", ["Hard"])
        self.data.add_measure("Popularity", [[114, 96]])
        self.assertEqual(
            {
                "data": {
                    "dimensions": [
                        {"name": "Genres", "values": ["Pop", "Rock"]},
                        {"name": "Kinds", "values": ["Hard"]},
                    ],
                    "measures": [
                        {
                            "name": "Popularity",
                            "values": [[114, 96]],
                        }
                    ],
                }
            },
            self.data.build(),
        )


class TestDataAddDf(unittest.TestCase):
    asset_dir: pathlib.Path

    @classmethod
    def setUpClass(cls) -> None:
        cls.asset_dir = pathlib.Path(__file__).parent / "assets"

    def setUp(self) -> None:
        self.data = Data()

    def test_add_df_with_none(self) -> None:
        data = Data()
        data.add_df(None)
        self.assertEqual(
            {"data": {}},
            data.build(),
        )

    def test_add_df_with_df(self) -> None:
        with open(self.asset_dir / "df_in.json", encoding="utf8") as fh_in:
            fc_in = json.load(fh_in)
        with open(self.asset_dir / "df_out.json", encoding="utf8") as fh_out:
            fc_out = json.load(fh_out)

        df = pd.DataFrame(fc_in)
        df = df.astype({"PopularityAsDimension": str})
        self.data.add_df(df)
        self.assertEqual(
            fc_out,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = pd.read_csv(
            self.asset_dir / "df_na.csv", dtype={"PopularityAsDimension": str}
        )
        self.data.add_df(df)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "Popularity",
                            "type": "measure",
                            "values": [100.0, 0.0],
                        },
                        {
                            "name": "PopularityAsDimension",
                            "type": "dimension",
                            "values": ["", "100"],
                        },
                    ]
                }
            },
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        data = Data()
        data.add_df(pd.Series([1, 2], name="series1"))
        data.add_df(
            pd.Series({"x": 3, "y": 4, "z": 5}, index=["x", "y"], name="series2")
        )
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "series1", "type": "measure", "values": [1.0, 2.0]},
                        {"name": "series2", "type": "measure", "values": [3.0, 4.0]},
                    ]
                }
            },
            data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        data = Data()
        df = pd.DataFrame({"series": [1, 2, 3]}, index=["x", "y", "z"])
        data.add_df(df, include_index="Index")
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "Index",
                            "type": "dimension",
                            "values": ["x", "y", "z"],
                        },
                        {
                            "name": "series",
                            "type": "measure",
                            "values": [1.0, 2.0, 3.0],
                        },
                    ]
                }
            },
            data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        data = Data()
        df = pd.Series({"x": 1, "y": 2, "z": 3}, index=["x", "y"], name="series")
        data.add_df(df, include_index="Index")
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "Index", "type": "dimension", "values": ["x", "y"]},
                        {"name": "series", "type": "measure", "values": [1.0, 2.0]},
                    ]
                }
            },
            data.build(),
        )

    def test_add_df_index(self) -> None:
        data = Data()
        df = pd.Series({"x": 1, "y": 2, "z": 3}, index=["x", "y"], name="series")
        data.add_df_index(df, column_name="Index")
        data.add_df(df)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "Index", "type": "dimension", "values": ["x", "y"]},
                        {"name": "series", "type": "measure", "values": [1.0, 2.0]},
                    ]
                }
            },
            data.build(),
        )

    def test_add_df_index_with_none(self) -> None:
        data = Data()
        df = pd.DataFrame()
        data.add_df_index(df, column_name="Index")
        data.add_df(df)
        self.assertEqual(
            {"data": {}},
            data.build(),
        )

    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            data = Data()
            with self.assertRaises(ImportError):
                data.add_df(pd.DataFrame())


class TestDataAddDataframe(unittest.TestCase):
    asset_dir: pathlib.Path

    @classmethod
    def setUpClass(cls) -> None:
        cls.asset_dir = pathlib.Path(__file__).parent / "assets"

    def setUp(self) -> None:
        self.data = Data()

    def test_add_data_frame_with_none(self) -> None:
        data = Data()
        data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        with open(self.asset_dir / "df_in.json", encoding="utf8") as fh_in:
            fc_in = json.load(fh_in)
        with open(self.asset_dir / "df_out.json", encoding="utf8") as fh_out:
            fc_out = json.load(fh_out)

        df = pd.DataFrame(fc_in)
        df = df.astype({"PopularityAsDimension": str})
        self.data.add_data_frame(df)
        self.assertEqual(
            fc_out,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = pd.read_csv(
            self.asset_dir / "df_na.csv", dtype={"PopularityAsDimension": str}
        )
        self.data.add_data_frame(df)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "Popularity",
                            "type": "measure",
                            "values": [100.0, 0.0],
                        },
                        {
                            "name": "PopularityAsDimension",
                            "type": "dimension",
                            "values": ["", "100"],
                        },
                    ]
                }
            },
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        data = Data()
        data.add_data_frame(pd.Series([1, 2], name="series1"))
        data.add_data_frame(
            pd.Series({"x": 3, "y": 4, "z": 5}, index=["x", "y"], name="series2")
        )
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "series1", "type": "measure", "values": [1.0, 2.0]},
                        {"name": "series2", "type": "measure", "values": [3.0, 4.0]},
                    ]
                }
            },
            data.build(),
        )

    def test_add_data_frame_index(self) -> None:
        data = Data()
        df = pd.Series({"x": 1, "y": 2, "z": 3}, index=["x", "y"], name="series")
        data.add_data_frame_index(df, name="Index")
        data.add_data_frame(df)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "Index", "type": "dimension", "values": ["x", "y"]},
                        {"name": "series", "type": "measure", "values": [1.0, 2.0]},
                    ]
                }
            },
            data.build(),
        )


class TestDataAddNpArray(unittest.TestCase):
    def test_add_np_array_none(self) -> None:
        data = Data()
        data.add_np_array(None)
        self.assertEqual(
            {"data": {}},
            data.build(),
        )

    def test_add_np_array_empty(self) -> None:
        np_array = np.empty([])
        data = Data()
        data.add_np_array(np_array)
        self.assertEqual(
            {"data": {}},
            data.build(),
        )

    def test_add_np_array1dim(self) -> None:
        np_array = np.array([127, 128, 129])
        data = Data()
        data.add_np_array(np_array)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "0", "type": "measure", "values": [127, 128, 129]},
                    ]
                }
            },
            data.build(),
        )

    def test_add_np_array1dim_with_str_value(self) -> None:
        np_array = np.array([127, "128", 129])
        data = Data()
        data.add_np_array(np_array)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "0",
                            "type": "dimension",
                            "values": ["127", "128", "129"],
                        },
                    ]
                }
            },
            data.build(),
        )

    def test_add_np_array1dim_with_str_and_na_value_and_column_name_and_dtype(
        self,
    ) -> None:
        np_array = np.array([127, "128", np.nan])
        data = Data()
        data.add_np_array(np_array, column_name="First", column_dtype=int)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "First",
                            "type": "measure",
                            "values": [127, 128, 0],
                        },
                    ]
                }
            },
            data.build(),
        )

    def test_add_np_array2dim(self) -> None:
        np_array = np.array([[127, 128, 129], [255, 256, 257], [511, 512, 513]])
        data = Data()
        data.add_np_array(np_array)
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {"name": "0", "type": "measure", "values": [127, 255, 511]},
                        {"name": "1", "type": "measure", "values": [128, 256, 512]},
                        {"name": "2", "type": "measure", "values": [129, 257, 513]},
                    ]
                }
            },
            data.build(),
        )

    def test_add_np_array2dim_with_str_and_na_value_and_column_name_and_dtype(
        self,
    ) -> None:
        np_array = np.array([[127, "128", 129], [255, np.nan, 257], [511, 512, 513]])
        data = Data()
        data.add_np_array(np_array, column_name={0: "First"}, column_dtype={2: int})
        self.assertEqual(
            {
                "data": {
                    "series": [
                        {
                            "name": "First",
                            "type": "dimension",
                            "values": ["127", "255", "511"],
                        },
                        {
                            "name": "1",
                            "type": "dimension",
                            "values": ["128", "", "512"],
                        },
                        {
                            "name": "2",
                            "type": "measure",
                            "values": [129, 257, 513],
                        },
                    ]
                }
            },
            data.build(),
        )

    def test_add_np_array2dim_with_non_dict_column_name(self) -> None:
        np_array = np.zeros((2, 2))
        data = Data()
        with self.assertRaises(ValueError):
            data.add_np_array(np_array, column_name="First")

    def test_add_np_array2dim_with_non_dict_column_dtype(self) -> None:
        np_array = np.zeros((2, 2))
        data = Data()
        with self.assertRaises(ValueError):
            data.add_np_array(np_array, column_dtype=str)

    def test_add_np_array3dim(self) -> None:
        np_array = np.zeros((3, 3, 3))
        data = Data()
        with self.assertRaises(ValueError):
            data.add_np_array(np_array)

    def test_add_df_if_numpy_not_installed(self) -> None:
        with RaiseImportError.module_name("numpy"):
            data = Data()
            with self.assertRaises(ImportError):
                data.add_np_array(np.empty(()))


class TestConfig(unittest.TestCase):
    def test_config(self) -> None:
        animation = Config({"color": {"set": ["Genres"]}})
        self.assertEqual({"config": {"color": {"set": ["Genres"]}}}, animation.build())

    def test_config_preset(self) -> None:
        animation = Config.column({"x": "foo", "y": "bar"})
        # instead of build() test with dump() because contains raw js
        self.assertEqual(
            "{\"config\": lib.presets.column({'x': 'foo', 'y': 'bar'})}",
            animation.dump(),
        )


class TestStyle(unittest.TestCase):
    def test_style(self) -> None:
        animation = Style({"title": {"backgroundColor": "#A0A0A0"}})
        self.assertEqual(
            {"style": {"title": {"backgroundColor": "#A0A0A0"}}}, animation.build()
        )

    def test_style_can_be_none(self) -> None:
        animation = Style(None)
        self.assertEqual({"style": None}, animation.build())


class TestKeyframe(unittest.TestCase):
    def test_animation_has_to_be_passed_even_if_options_passed(
        self,
    ) -> None:
        with self.assertRaises(ValueError):
            Keyframe(duration="500ms")

    def test_keyframe_cannot_be_passed(
        self,
    ) -> None:
        with self.assertRaises(ValueError):
            Keyframe(Keyframe(Style(None)))

    def test_animation_and_snapshot_cannot_be_passed(
        self,
    ) -> None:
        with self.assertRaises(ValueError):
            Keyframe(Keyframe(Style(None), Snapshot("abc123")))

    def test_animation_and_stored_animation_cannot_be_passed(
        self,
    ) -> None:
        with self.assertRaises(ValueError):
            Keyframe(Keyframe(Style(None), Animation("abc123")))

    def test_keyframe(self) -> None:
        animation = Keyframe(
            Data.filter(None), Style(None), Config({"title": "Keyframe"})
        )
        self.assertEqual(
            animation.build(),
            {
                "target": {
                    "config": {"title": "Keyframe"},
                    "data": {"filter": None},
                    "style": None,
                }
            },
        )

    def test_keyframe_with_snapshot(self) -> None:
        animation = Keyframe(Snapshot("abc123"))
        self.assertEqual(
            animation.build(),
            {
                "target": "abc123",
            },
        )

    def test_keyframe_with_stored_animation(self) -> None:
        animation = Keyframe(Animation("abc123"))
        self.assertEqual(
            animation.build(),
            {
                "target": "abc123",
            },
        )

    def test_keyframe_with_options(self) -> None:
        animation = Keyframe(
            Data.filter(None), Style(None), Config({"title": "Keyframe"}), duration=1
        )
        self.assertEqual(
            animation.build(),
            {
                "target": {
                    "config": {"title": "Keyframe"},
                    "data": {"filter": None},
                    "style": None,
                },
                "options": {"duration": 1},
            },
        )


class TestSnapshot(unittest.TestCase):
    def test_snapshot(self) -> None:
        animation = Snapshot("abc1234")
        self.assertEqual("abc1234", animation.build())

    def test_snapshot_dump(self) -> None:
        animation = Snapshot("abc1234")
        self.assertEqual('"abc1234"', animation.dump())


class TestAnimation(unittest.TestCase):
    def test_animation(self) -> None:
        animation = Animation("abc1234")
        self.assertEqual("abc1234", animation.build())

    def test_animation_dump(self) -> None:
        animation = Animation("abc1234")
        self.assertEqual('"abc1234"', animation.dump())


class TestMerger(unittest.TestCase):
    def setUp(self) -> None:
        self.merger = AnimationMerger()

        self.data = Data()
        self.data.add_record(["Rock", "Hard", 96])

        self.config = Config({"channels": {"label": {"attach": ["Popularity"]}}})

    def test_merge(self) -> None:
        self.merger.merge(self.data)
        self.merger.merge(self.config)
        self.merger.merge(Style({"title": {"backgroundColor": "#A0A0A0"}}))
        self.assertEqual(
            json.dumps(
                {
                    "data": {"records": [["Rock", "Hard", 96]]},
                    "config": {"channels": {"label": {"attach": ["Popularity"]}}},
                    "style": {"title": {"backgroundColor": "#A0A0A0"}},
                }
            ),
            self.merger.dump(),
        )

    def test_merge_none(self) -> None:
        self.merger.merge(self.config)
        self.merger.merge(Style(None))
        self.assertEqual(
            '{"config": {"channels": {"label": {"attach": ["Popularity"]}}}, "style": null}',
            self.merger.dump(),
        )

    def test_snapshot_can_not_be_merged(self) -> None:
        self.merger.merge(self.data)
        self.merger.merge(self.config)
        self.merger.merge(Style({"title": {"backgroundColor": "#A0A0A0"}}))
        self.assertRaises(ValueError, self.merger.merge, Snapshot("abc1234"))

    def test_stored_animation_can_not_be_merged(self) -> None:
        self.merger.merge(self.data)
        self.merger.merge(self.config)
        self.merger.merge(Style({"title": {"backgroundColor": "#A0A0A0"}}))
        self.assertRaises(ValueError, self.merger.merge, Animation("abc1234"))

    def test_only_different_animations_can_be_merged(self) -> None:
        self.merger.merge(self.data)
        self.merger.merge(self.config)
        self.merger.merge(Style({"title": {"backgroundColor": "#A0A0A0"}}))

        data = Data()
        data.add_record(["Pop", "Hard", 114])

        self.assertRaises(ValueError, self.merger.merge, data)
        self.assertRaises(ValueError, self.merger.merge, Config({"title": "Test"}))
        self.assertRaises(ValueError, self.merger.merge, Style(None))

    def test_merge_keyframes(self) -> None:
        self.merger.merge(Keyframe(Style(None)))
        self.merger.merge(Keyframe(Style(None), duration=0))
        self.merger.merge(Keyframe(Style(None)))

        self.assertEqual(
            self.merger.dump(),
            json.dumps(
                [
                    {"target": {"style": None}},
                    {"target": {"style": None}, "options": {"duration": 0}},
                    {"target": {"style": None}},
                ]
            ),
        )

    def test_keyframe_and_animation_can_not_be_merged(self) -> None:
        self.merger.merge(Keyframe(Style(None)))
        self.assertRaises(ValueError, self.merger.merge, self.data)

    def test_animation_and_keyframe_can_not_be_merged(self) -> None:
        self.merger.merge(self.data)
        self.assertRaises(ValueError, self.merger.merge, Keyframe(Style(None)))

    def test_merge_animations_keyframe(self) -> None:
        animations = tuple([Keyframe(Style(None))])
        merger = AnimationMerger.merge_animations(animations)

        self.assertEqual(
            merger.dump(),
            json.dumps(
                [
                    {"target": {"style": None}},
                ]
            ),
        )

tests/__init__.py METASEP
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

tests/test_data/test_pandas.py METASEP

# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_data_frame_index(df, name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDfIndexWithSeries(DataWithAssets):
    def test_add_df_index_with_series(self) -> None:
        self.data.add_df_index(
            self.in_pd_series_dimension_with_index,
            column_name="DimensionIndex",
        )
        self.data.add_df_index(
            self.in_pd_series_measure_with_index,
            column_name="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_only_index,
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_data_frame_index(df, name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDfIndexWithSeries(DataWithAssets):
    def test_add_df_index_with_series(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_data_frame_index(df, name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDfIndexWithSeries(DataWithAssets):
    def test_add_df_index_with_series(self) -> None:
        self.data.add_df_index(
            self.in_pd_series_dimension_with_index,
            column_name="DimensionIndex",
        )
        self.data.add_df_index(
            self.in_pd_series_measure_with_index,
            column_name="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndexWithSeries(DataWithAssets):
    def test_add_data_frame_index_with_series(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
inproject
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

non_informative
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


non_informative
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

non_informative
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_data_frame_index(df, name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDfIndexWithSeries(DataWithAssets):
    def test_add_df_index_with_series(self) -> None:
        self.data.add_df_index(
            self.in_pd_series_dimension_with_index,
            column_name="DimensionIndex",
        )
        self.data.add_df_index(
            self.in_pd_series_measure_with_index,
            column_name="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndexWithSeries(DataWithAssets):
non_informative
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
non_informative
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_data_frame_index(df, name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDfIndexWithSeries(DataWithAssets):
    def test_add_df_index_with_series(self) -> None:
        self.data.add_df_index(
random
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_data_frame_index(df, name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDfIndexWithSeries(DataWithAssets):
    def test_add_df_index_with_series(self) -> None:
        self.data.add_df_index(
            self.in_pd_series_dimension_with_index,
            column_name="DimensionIndex",
        )
        self.data.add_df_index(
            self.in_pd_series_measure_with_index,
random
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
random
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
random
# pylint: disable=missing-module-docstring,missing-class-docstring,missing-function-docstring

import pandas as pd

from tests.test_data import DataWithAssets
from tests.utils.import_error import RaiseImportError


class TestDf(DataWithAssets):
    def test_add_df_if_pandas_not_installed(self) -> None:
        with RaiseImportError.module_name("pandas"):
            with self.assertRaises(ImportError):
                self.data.add_df(pd.DataFrame())

    def test_add_df_with_none(self) -> None:
        self.data.add_df(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_empty_df(self) -> None:
        self.data.add_df(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_df_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_df(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_df_and_with_include_index(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df(df, include_index="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_with_index,
            self.data.build(),
        )

    def test_add_df_with_df_and_max_rows(self) -> None:
        df = self.in_pd_df_by_series
        self.data.add_df(df, max_rows=2)
        self.assertEqual(
            self.ref_pd_df_by_series_max_rows,
            self.data.build(),
        )


class TestDataFrame(DataWithAssets):
    def test_add_data_frame_with_none(self) -> None:
        self.data.add_data_frame(None)
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_empty_df(self) -> None:
        self.data.add_data_frame(pd.DataFrame())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_duplicated_popularity
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_duplicated_popularity,
            self.data.build(),
        )

    def test_add_data_frame_with_df_contains_na(self) -> None:
        df = self.in_pd_df_by_series_with_nan
        self.data.add_data_frame(df)
        self.assertEqual(
            self.ref_pd_df_by_series_with_nan,
            self.data.build(),
        )


class TestDfWithSeries(DataWithAssets):
    def test_add_df_with_empty_series(self) -> None:
        self.data.add_df(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_with_series(self) -> None:
        self.data.add_df(self.in_pd_series_dimension)
        self.data.add_df(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_df_with_series_contains_na(self) -> None:
        self.data.add_df(self.in_pd_series_dimension_with_nan)
        self.data.add_df(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )

    def test_add_df_with_series_and_with_include_index(self) -> None:
        self.data.add_df(
            self.in_pd_series_dimension_with_index,
            include_index="DimensionIndex",
        )
        self.data.add_df(
            self.in_pd_series_measure_with_index,
            include_index="MeasureIndex",
        )
        self.assertEqual(
            self.ref_pd_series_with_index,
            self.data.build(),
        )


class TestDataFrameWithSeries(DataWithAssets):
    def test_add_data_frame_with_empty_series(self) -> None:
        self.data.add_data_frame(pd.Series())
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_data_frame_with_series(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension)
        self.data.add_data_frame(self.in_pd_series_measure)
        self.assertEqual(
            self.ref_pd_series,
            self.data.build(),
        )

    def test_add_data_frame_with_series_contains_na(self) -> None:
        self.data.add_data_frame(self.in_pd_series_dimension_with_nan)
        self.data.add_data_frame(self.in_pd_series_measure_with_nan)
        self.assertEqual(
            self.ref_pd_series_with_nan,
            self.data.build(),
        )


class TestDfIndex(DataWithAssets):
    def test_add_df_index_with_none(self) -> None:
        self.data.add_df_index(None, column_name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
        )

    def test_add_df_index_with_df(self) -> None:
        df = self.in_pd_df_by_series_with_index
        self.data.add_df_index(df, column_name="Index")
        self.assertEqual(
            self.ref_pd_df_by_series_only_index,
            self.data.build(),
        )


class TestDataFrameIndex(DataWithAssets):
    def test_add_data_frame_index_with_none(self) -> None:
        self.data.add_data_frame_index(None, name="Index")
        self.assertEqual(
            {"data": {}},
            self.data.build(),
random
            self.data.build(),         self.data.add_data_frame(pd.Series())         with RaiseImportError.module_name("pandas"):         self.data.add_df(pd.DataFrame())         self.data.add_data_frame(self.in_pd_series_dimension)         self.data.add_data_frame(self.in_pd_series_measure)         self.data.add_df(None)         self.data.add_data_frame(self.in_pd_series_dimension_with_nan)         self.data.add_data_frame(self.in_pd_series_measure_with_nan)         self.data.add_df(df)         self.data.add_df_index(None, column_name="Index")         self.data.add_df_index(df, column_name="Index")         self.data.add_df(df, include_index="Index")         self.data.add_data_frame_index(None, name="Index")         self.data.add_df(df, max_rows=2)         self.data.add_data_frame_index(df, name="Index")         self.data.add_data_frame(None)         self.data.add_df_index(         self.data.add_data_frame(pd.DataFrame())         self.data.add_data_frame(df)         self.data.add_data_frame_index(         self.data.add_df(pd.Series())         self.data.add_df(self.in_pd_series_dimension)         self.data.add_df(self.in_pd_series_measure)         self.data.add_df(self.in_pd_series_dimension_with_nan)         self.data.add_df(self.in_pd_series_measure_with_nan)         self.data.add_df(     def test_add_data_frame_index_with_df(self) -> None: class TestDfIndex(DataWithAssets):     def test_add_data_frame_index_with_series(self) -> None: from tests.utils.import_error import RaiseImportError             self.in_pd_series_dimension_with_index,             column_name="MeasureIndex",             self.ref_pd_df_by_series_only_index,         self.assertEqual(         )