Repository: inseq-team/inseq (language: python)

Issue:
Test case for larger (prompting-based)  language models (+ LLM.int8())
## 🚀 Feature Request

Following our discussion, it might be valuable to add a test case including larger language models that work with prompting such as [T0 and its variants](https://huggingface.co/bigscience/T0pp). Since availability of these kinds of models is becoming more common (see "Motivation"), we should show an example of feature attribution for them.


## 🔈 Motivation

The [bitsandbytes integration and 8-bit precision (Dettmers et al., 2022)](https://arxiv.org/abs/2208.07339) released in August enables the use of larger models on single GPU setups.

Add support for decoder-only models
## 🚀 Feature Request

Adding support for decoder-only models like GPT-2 on top of the AttributionModel abstraction. The change will involve a radical refactoring of the whole attribution pipeline to enable target-only attribution and passing `Batch` objects instead of `EncoderDecoderBatch` if decoder-only attribution is performed.

The output attribution classes would mostly stay the same, with the exception of source attributions becoming optional.



Discussion / hints:
From preliminary tests gradient-based attributions are broken when INT8 is used - likely to require a dedicated PR.

**Edit**: Opened an issue with minimal failure case to ask for clarifications in the [`bitsandbytes` repo](https://github.com/TimDettmers/bitsandbytes/issues/67)


Fix patch:
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index c881fdcc..31d9b9a8 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -36,17 +36,17 @@ repos:
 
   - repo: local
     hooks:
-      - id: flake8
-        name: flake8
-        entry: poetry run flake8 --config setup.cfg
+      - id: black
+        name: black
+        entry: poetry run black --config pyproject.toml
         types: [python]
         language: system
 
   - repo: local
     hooks:
-      - id: black
-        name: black
-        entry: poetry run black --config pyproject.toml
+      - id: flake8
+        name: flake8
+        entry: poetry run flake8 --config setup.cfg
         types: [python]
         language: system
 
diff --git a/Makefile b/Makefile
index d060e1bb..7957d8d4 100644
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,9 @@ install-ci:
 
 .PHONY: update-deps
 update-deps:
-	poetry lock && poetry export --without-hashes > requirements.txt
+	poetry lock
+	poetry export --without-hashes > requirements.txt
+	poetry export --without-hashes -E sklearn -E datasets -E notebook --with lint,docs > requirements-dev.txt
 
 #* Linting
 .PHONY: check-style
@@ -90,7 +92,7 @@ fix-style:
 .PHONY: check-safety
 check-safety:
 	poetry check
-	poetry run safety check --full-report
+	poetry run safety check --full-report -i 51499 -i 51457
 	poetry run bandit -ll --recursive inseq tests
 
 .PHONY: lint
diff --git a/README.md b/README.md
index 58fab699..8e81b3bc 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 <div align="center">
   <img src="/docs/source/images/inseq_logo.png" width="300"/>
-  <h4>Intepretability for Sequence-to-sequence Models 🔍</h4>
+  <h4>Intepretability for Sequence Generation Models 🔍</h4>
 </div>
 <br/>
 <div align="center">
@@ -46,18 +46,34 @@ import inseq
 model = inseq.load_model("Helsinki-NLP/opus-mt-en-fr", "integrated_gradients")
 out = model.attribute(
   "The developer argued with the designer because her idea cannot be implemented.",
-  return_convergence_delta=True,
   n_steps=100
 )
 out.show()
 ```
 
+This produces a visualization of the attribution scores for each token in the input sentence (token-level aggregation is handled automatically). Here is what the visualization looks like inside a Jupyter Notebook:
+
 ![WinoMT Attribution Map](docs/source/images/heatmap_winomt.png)
 
+Inseq also supports decoder-only models such as [GPT-2](https://huggingface.co/transformers/model_doc/gpt2.html), enabling usage of a variety of attribution methods and customizable settings directly from the console:
+
+```python
+import inseq
+
+model = inseq.load_model("gpt2", "integrated_gradients")
+model.attribute(
+    "Hello ladies and",
+    generation_args={"max_new_tokens": 9},
+    n_steps=500,
+    internal_batch_size=50
+).show()
+```
+
+![GPT-2 Attribution in the console](docs/source/images/inseq_python_console.gif)
 
 ## Using the Inseq client
 
-See the available options by typing `inseq -h` in the terminal after installing the package.
+The Inseq library also provides useful client commands to enable repeated attribution of individual examples and even entire 🤗 datasets directly from the console. See the available options by typing `inseq -h` in the terminal after installing the package.
 
 For now, two commands are supported:
 
@@ -67,64 +83,25 @@ For now, two commands are supported:
 
 Both commands support the full range of parameters available for `attribute`, attribution visualization in the console and saving outputs to disk.
 
-**Example:** The following command can be used to perform attribution (both source and target-side) of Italian translations for a dummy sample of 20 English sentences taken from the FLORES-101 parallel corpus, using a MarianNMT translation model from Hugging Face `transformers`. The output is shown in the console and saved to disk to `out.json` (you can load it later using `inseq.FeatureAttributionOutput.load("out.json")`).
+**Example:** The following command can be used to perform attribution (both source and target-side) of Italian translations for a dummy sample of 20 English sentences taken from the FLORES-101 parallel corpus, using a MarianNMT translation model from Hugging Face `transformers`. We save the visualizations in HTML format in the file `attributions.html`. See the `--help` flag for more options.
 
 ```bash
 inseq attribute-dataset \
   --model_name_or_path Helsinki-NLP/opus-mt-en-it \
-  --attribution_method integrated_gradients \
+  --attribution_method saliency \
   --do_prefix_attribution \
   --dataset_name inseq/dummy_enit \
   --input_text_field en \
   --dataset_split "train[:20]" \
-  --save_path out.json \
-  --batch_size 8
+  --viz_path attributions.html \
+  --batch_size 8 \
+  --hide
 ```
 
-### Dealing with minimal pairs
-
-Inseq support minimal pair analysis via the `PairAggregator` component. Here is an example of using `PairAggregator` to produce a heatmap containing the score difference between two `FeatureAttributionSequenceOutput` objects:
-
-
-```python
-import inseq
-from inseq.data.aggregator import AggregatorPipeline, ContiguousSpanAggregator, SequenceAttributionAggregator, PairAggregator
-
-# Load the EN-FR translation model and attach the IG method
-model = inseq.load_model("Helsinki-NLP/opus-mt-en-fr", "integrated_gradients")
-
-# Perform the attribution with forced decoding. Return convergence deltas, probabilities and target attributions.
-out = model.attribute(
-    [
-        "The manager told the hairdresser that the haircut he made her was terrible.",
-        "The manager told the hairdresser that the haircut he made her was terrible.",
-    ],
-    [
-        "Le gérant a dit au coiffeur que la coupe de cheveux qu'il lui a faite était terrible.",
-        "La gérante a dit au coiffeur que la coupe de cheveux qu'il lui a faite était terrible.",
-    ],
-    n_steps=300,
-    return_convergence_delta=True,
-    attribute_target=True,
-    step_scores=["probability"],
-    internal_batch_size=100,
-    include_eos_baseline=False,
-)
-
-# Aggregation pipeline composed by two steps:
-# 1. Aggregate contiguous tokens across all attribution dimensions
-# 2. Aggregate the last dimension of the neuron-level attribution to make it token-level
-squeezesum = AggregatorPipeline([ContiguousSpanAggregator, SequenceAttributionAggregator])
+### Class structure
 
-# Simply aggregate over the last dimension for the masculine variant
-masculine = out.sequence_attributions[0].aggregate(aggregator=SequenceAttributionAggregator)
+The following diagram provides an overview of the main classes in the library:
 
-# For the feminine variant, we also use the contiguous span aggregator to merge "▁gérant" "e"
-# in a single token to match masc shape
-feminine = out.sequence_attributions[1].aggregate(aggregator=squeezesum, target_spans=(1, 3))
-
-# Take the diff of the scores of the two attribution and show it
-masculine.show(aggregator=PairAggregator, paired_attr=feminine)
-```
+![Class structure](docs/source/images/classes.png)
 
-![Minimal Pair Diff Attribution Map](docs/source/images/heatmap_pair.png)
+When `inseq.load_model` is called using a model name and feature attribution method identifier, the correct model class and the corresponding method are instantiated and tied together (the method is accessible via `model.attribution_method`).
\ No newline at end of file
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 033e342b..1c7af60a 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -108,7 +108,7 @@
 intersphinx_mapping = {
     "python": ("https://docs.python.org/3", None),
     "torch": ("https://pytorch.org/docs/stable/", None),
-    "numpy": ("https://docs.scipy.org/doc/numpy/", None),
+    "numpy": ("https://numpy.org/doc/stable/", None),
 }
 
 # -- Options for HTML output -------------------------------------------------
diff --git a/docs/source/diagrams/classes.drawio b/docs/source/diagrams/classes.drawio
new file mode 100644
index 00000000..3cd1848c
--- /dev/null
+++ b/docs/source/diagrams/classes.drawio
@@ -0,0 +1,183 @@
+<mxfile host="65bd71144e">
+    <diagram id="wnJHaeVWVRqouhSKW7HH" name="Classes">
+        <mxGraphModel dx="487" dy="868" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="850" pageHeight="1100" background="#FFFFFF" math="0" shadow="0">
+            <root>
+                <mxCell id="0"/>
+                <mxCell id="1" parent="0"/>
+                <mxCell id="50" value="" style="rounded=0;whiteSpace=wrap;html=1;fontSize=13;fontColor=#1A1A1A;strokeColor=#1A1A1A;fillColor=#FFFFFF;gradientColor=none;" parent="1" vertex="1">
+                    <mxGeometry x="-250" y="-80" width="930" height="430" as="geometry"/>
+                </mxCell>
+                <mxCell id="22" value="" style="endArrow=none;dashed=1;html=1;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;strokeWidth=2;" parent="1" edge="1">
+                    <mxGeometry width="50" height="50" relative="1" as="geometry">
+                        <mxPoint x="19" y="340" as="sourcePoint"/>
+                        <mxPoint x="19" y="110" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="20" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;" parent="1" source="2" target="12" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <Array as="points">
+                            <mxPoint x="-11" y="140"/>
+                            <mxPoint x="-150" y="140"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="21" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;" parent="1" source="2" target="15" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <Array as="points">
+                            <mxPoint x="-11" y="140"/>
+                            <mxPoint x="-231" y="140"/>
+                            <mxPoint x="-230" y="200"/>
+                            <mxPoint x="-230" y="240"/>
+                            <mxPoint x="-190" y="240"/>
+                            <mxPoint x="-150" y="240"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="43" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontSize=15;fontColor=#FFFFFF;strokeColor=#1A1A1A;" parent="1" source="2" target="16" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <Array as="points">
+                            <mxPoint x="49" y="140"/>
+                            <mxPoint x="120" y="140"/>
+                            <mxPoint x="190" y="140"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="2" value="&lt;b&gt;AttributionModel&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FAA8A8;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="-41" y="40" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="5" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;fontColor=#000000;strokeColor=#1A1A1A;" parent="1" source="3" target="4" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="37" style="edgeStyle=none;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;fontSize=15;fontColor=#FFFFFF;strokeColor=#1A1A1A;" parent="1" source="3" target="36" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <Array as="points">
+                            <mxPoint x="400" y="120"/>
+                            <mxPoint x="320" y="120"/>
+                            <mxPoint x="320" y="220"/>
+                            <mxPoint x="400" y="220"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="3" value="&lt;b&gt;FeatureAttribution&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#82AEFA;strokeColor=#1A1A1A;fontColor=#000000;gradientColor=none;" parent="1" vertex="1">
+                    <mxGeometry x="340" y="40" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="33" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FFFFFF;strokeColor=#1A1A1A;" parent="1" source="4" target="7" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <Array as="points">
+                            <mxPoint x="508" y="169"/>
+                            <mxPoint x="508" y="112"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="34" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FFFFFF;strokeColor=#1A1A1A;" parent="1" source="4" target="6" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="35" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FFFFFF;strokeColor=#1A1A1A;" parent="1" source="4" target="8" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <Array as="points">
+                            <mxPoint x="508" y="169"/>
+                            <mxPoint x="508" y="226"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="4" value="&lt;b&gt;GradientAttribution&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#82AEFA;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="340" y="144" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="6" value="&lt;b&gt;SaliencyAttribution&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#3C6CEF;strokeColor=#1A1A1A;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="538" y="149" width="120" height="40" as="geometry"/>
+                </mxCell>
+                <mxCell id="7" value="&lt;b&gt;IntegratedGradients&lt;br&gt;Attribution&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#3C6CEF;strokeColor=#1A1A1A;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="538" y="94" width="120" height="40" as="geometry"/>
+                </mxCell>
+                <mxCell id="8" value="&lt;b&gt;...&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#3C6CEF;strokeColor=#1A1A1A;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="538" y="204" width="120" height="40" as="geometry"/>
+                </mxCell>
+                <mxCell id="25" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;" parent="1" source="12" target="19" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="12" value="&lt;b&gt;DecoderOnly&lt;br&gt;AttributionModel&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FAA8A8;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="-210" y="159" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="13" value="&lt;b style=&quot;font-size: 15px&quot;&gt;&lt;font style=&quot;font-size: 15px&quot;&gt;&lt;font&gt;Architectural&lt;br&gt;Classes&lt;/font&gt;&lt;br&gt;&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#1A1A1A;" parent="1" vertex="1">
+                    <mxGeometry x="-150" y="90" width="60" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="28" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;" parent="1" source="15" target="26" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="15" value="&lt;b&gt;EncoderDecoder&lt;br&gt;AttributionModel&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FAA8A8;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="-210" y="257" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="24" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;" parent="1" source="16" target="19" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="27" style="edgeStyle=none;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FAA8A8;strokeColor=#1A1A1A;" parent="1" source="16" target="26" edge="1">
+                    <mxGeometry relative="1" as="geometry">
+                        <mxPoint x="130" y="212" as="sourcePoint"/>
+                        <Array as="points">
+                            <mxPoint x="109" y="186"/>
+                            <mxPoint x="109" y="250"/>
+                            <mxPoint x="109" y="282"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="16" value="&lt;b&gt;HuggingfaceModel&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FAA8A8;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="130" y="159" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="17" value="&lt;b style=&quot;font-size: 15px&quot;&gt;&lt;font style=&quot;font-size: 15px&quot;&gt;&lt;font&gt;Framework&lt;br&gt;Classes&lt;/font&gt;&lt;br&gt;&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontColor=#1A1A1A;" parent="1" vertex="1">
+                    <mxGeometry x="120" y="90" width="60" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="19" value="&lt;b&gt;Huggingface&lt;br&gt;DecoderOnlyModel&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FA5D5D;strokeColor=#1A1A1A;fontColor=#FFFFFF;" parent="1" vertex="1">
+                    <mxGeometry x="-41" y="159" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="26" value="&lt;b&gt;Huggingface&lt;br&gt;EncoderDecoderModel&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FA5D5D;strokeColor=#1A1A1A;fontColor=#FFFFFF;" parent="1" vertex="1">
+                    <mxGeometry x="-51.5" y="257" width="141" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="41" style="edgeStyle=none;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;fontSize=15;fontColor=#FFFFFF;strokeColor=#1A1A1A;" parent="1" source="36" target="40" edge="1">
+                    <mxGeometry relative="1" as="geometry"/>
+                </mxCell>
+                <mxCell id="36" value="&lt;b&gt;AttentionAttribution&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#82AEFA;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="340" y="257" width="120" height="50" as="geometry"/>
+                </mxCell>
+                <mxCell id="40" value="&lt;b&gt;...&lt;br&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#3C6CEF;strokeColor=#1A1A1A;fontColor=#ffffff;" parent="1" vertex="1">
+                    <mxGeometry x="538" y="262" width="120" height="40" as="geometry"/>
+                </mxCell>
+                <mxCell id="44" value="&lt;font color=&quot;#1a1a1a&quot; size=&quot;1&quot;&gt;&lt;b style=&quot;font-size: 13px&quot;&gt;Model-method connection&lt;/b&gt;&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=15;fontColor=#FFFFFF;" parent="1" vertex="1">
+                    <mxGeometry x="115" y="30" width="200" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="45" value="&lt;b&gt;ClassName&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#FAF3F3;strokeColor=#1A1A1A;fontColor=#000000;" parent="1" vertex="1">
+                    <mxGeometry x="466" y="-70" width="80" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="46" value="&lt;b&gt;&lt;font color=&quot;#ffffff&quot;&gt;ClassName&lt;/font&gt;&lt;/b&gt;" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#1A1A1A;strokeColor=none;fontColor=default;" parent="1" vertex="1">
+                    <mxGeometry x="466" y="-30" width="80" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="47" value="&lt;font color=&quot;#1a1a1a&quot; size=&quot;1&quot;&gt;&lt;b style=&quot;font-size: 13px&quot;&gt;= Abstract class&lt;/b&gt;&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontColor=default;" parent="1" vertex="1">
+                    <mxGeometry x="546" y="-70" width="120" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="49" value="&lt;font color=&quot;#1a1a1a&quot; size=&quot;1&quot;&gt;&lt;b style=&quot;font-size: 13px&quot;&gt;= Concrete class&lt;/b&gt;&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontColor=default;" parent="1" vertex="1">
+                    <mxGeometry x="546" y="-30" width="120" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="52" value="&lt;b&gt;&lt;font style=&quot;font-size: 23px&quot;&gt;Inseq Classes Overview&lt;/font&gt;&lt;/b&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=13;fontColor=#1A1A1A;" parent="1" vertex="1">
+                    <mxGeometry x="-230" y="-60" width="280" height="30" as="geometry"/>
+                </mxCell>
+                <mxCell id="53" value="" style="shape=flexArrow;endArrow=classic;startArrow=classic;html=1;fontSize=23;fontColor=#1A1A1A;strokeColor=#1A1A1A;strokeWidth=2;exitX=0;exitY=0.5;exitDx=0;exitDy=0;entryX=1;entryY=0.5;entryDx=0;entryDy=0;width=6;endSize=7.14;startSize=7.14;endWidth=12;startWidth=12;" parent="1" source="3" target="2" edge="1">
+                    <mxGeometry width="100" height="100" relative="1" as="geometry">
+                        <mxPoint x="170" y="190" as="sourcePoint"/>
+                        <mxPoint x="270" y="90" as="targetPoint"/>
+                        <Array as="points">
+                            <mxPoint x="220" y="65"/>
+                        </Array>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="55" value="" style="endArrow=classic;html=1;fontSize=23;fontColor=#1A1A1A;strokeColor=#1A1A1A;strokeWidth=2;" parent="1" edge="1">
+                    <mxGeometry width="50" height="50" relative="1" as="geometry">
+                        <mxPoint x="483" y="29" as="sourcePoint"/>
+                        <mxPoint x="538" y="30" as="targetPoint"/>
+                    </mxGeometry>
+                </mxCell>
+                <mxCell id="57" value="&lt;font color=&quot;#1a1a1a&quot; size=&quot;1&quot;&gt;&lt;b style=&quot;font-size: 13px&quot;&gt;= Inheritance&lt;/b&gt;&lt;/font&gt;" style="text;html=1;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;fontSize=14;fontColor=default;" parent="1" vertex="1">
+                    <mxGeometry x="528" y="14" width="134" height="30" as="geometry"/>
+                </mxCell>
+            </root>
+        </mxGraphModel>
+    </diagram>
+</mxfile>
diff --git a/docs/source/examples/custom_attribute_target.rst b/docs/source/examples/custom_attribute_target.rst
index 5bc557e6..7fe9421e 100644
--- a/docs/source/examples/custom_attribute_target.rst
+++ b/docs/source/examples/custom_attribute_target.rst
@@ -113,7 +113,7 @@ Now that we have our custom attribution function, integrating it in Inseq is ver
     attribution_model = inseq.load_model("Helsinki-NLP/opus-mt-en-it", "saliency")
 
     # Pre-compute ids and attention map for the contrastive target
-    contrast = attribution_model.encode("Ho salutato la manager", as_targets=True, prepend_bos_token=True)
+    contrast = attribution_model.encode("Ho salutato la manager", as_targets=True)
 
     # Perform the contrastive attribution:
     # Regular (forced) target -> "Non posso crederci."
diff --git a/docs/source/images/classes.png b/docs/source/images/classes.png
new file mode 100644
index 00000000..49f38321
Binary files /dev/null and b/docs/source/images/classes.png differ
diff --git a/docs/source/images/inseq_python_console.gif b/docs/source/images/inseq_python_console.gif
new file mode 100644
index 00000000..4cb3b63f
Binary files /dev/null and b/docs/source/images/inseq_python_console.gif differ
diff --git a/inseq/__init__.py b/inseq/__init__.py
index 121de618..c690d025 100644
--- a/inseq/__init__.py
+++ b/inseq/__init__.py
@@ -2,7 +2,7 @@
 
 from .attr import list_feature_attribution_methods, list_step_scores, register_step_score
 from .data import FeatureAttributionOutput, show_attributions
-from .models import AttributionModel, load_model
+from .models import AttributionModel, list_supported_frameworks, load_model
 
 
 def get_version() -> str:
@@ -21,5 +21,6 @@ def get_version() -> str:
     "show_attributions",
     "list_feature_attribution_methods",
     "list_step_scores",
+    "list_supported_frameworks",
     "register_step_score",
 ]
diff --git a/inseq/attr/__init__.py b/inseq/attr/__init__.py
index d9b5a43b..f2f897b0 100644
--- a/inseq/attr/__init__.py
+++ b/inseq/attr/__init__.py
@@ -1,6 +1,7 @@
 from .feat import (
     STEP_SCORES_MAP,
     FeatureAttribution,
+    extract_args,
     list_feature_attribution_methods,
     list_step_scores,
     register_step_score,
@@ -13,4 +14,5 @@
     "list_step_scores",
     "register_step_score",
     "STEP_SCORES_MAP",
+    "extract_args",
 ]
diff --git a/inseq/attr/attribution_decorators.py b/inseq/attr/attribution_decorators.py
index 8bd717c3..465f93f2 100644
--- a/inseq/attr/attribution_decorators.py
+++ b/inseq/attr/attribution_decorators.py
@@ -54,7 +54,7 @@ def unset_hook_wrapper(self, **kwargs):
     return unset_hook_wrapper
 
 
-def batched(f: Callable[[Any], Any]) -> Callable[[Any], Any]:
+def batched(f: Callable[..., Any]) -> Callable[..., Any]:
     """
     Decorator that enables batching of the args
     """
@@ -64,8 +64,10 @@ def batched_wrapper(self, *args, batch_size: Optional[int] = None, **kwargs):
         def get_batched(bs: Optional[int], seq: Sequence[Any]) -> List[List[Any]]:
             if isinstance(seq, str):
                 seq = [seq]
-            if isinstance(seq, list) or isinstance(seq, tuple):
+            if isinstance(seq, list):
                 return [seq[i : i + bs] for i in range(0, len(seq), bs)]  # noqa
+            if isinstance(seq, tuple):
+                return list(zip(*[get_batched(bs, s) for s in seq]))
             elif isinstance(seq, TensorWrapper):
                 return [seq.slice_batch(slice(i, i + bs)) for i in range(0, len(seq), bs)]  # noqa
             else:
diff --git a/inseq/attr/feat/__init__.py b/inseq/attr/feat/__init__.py
index 642ee61b..4d1aff13 100644
--- a/inseq/attr/feat/__init__.py
+++ b/inseq/attr/feat/__init__.py
@@ -1,4 +1,4 @@
-from .attribution_utils import STEP_SCORES_MAP, list_step_scores, register_step_score
+from .attribution_utils import STEP_SCORES_MAP, extract_args, join_token_ids, list_step_scores, register_step_score
 from .feature_attribution import FeatureAttribution, list_feature_attribution_methods
 from .gradient_attribution import (
     DeepLiftAttribution,
@@ -15,9 +15,11 @@
 
 __all__ = [
     "FeatureAttribution",
+    "extract_args",
     "list_feature_attribution_methods",
     "STEP_SCORES_MAP",
     "register_step_score",
+    "join_token_ids",
     "list_step_scores",
     "GradientAttribution",
     "DeepLiftAttribution",
diff --git a/inseq/attr/feat/attribution_utils.py b/inseq/attr/feat/attribution_utils.py
index 677feb46..b6e781d6 100644
--- a/inseq/attr/feat/attribution_utils.py
+++ b/inseq/attr/feat/attribution_utils.py
@@ -1,12 +1,13 @@
-from typing import Any, Callable, Dict, List, Optional, Tuple
+from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union
 
+import logging
 import math
 
 import torch
 
-from ...data.attribution import DEFAULT_ATTRIBUTION_AGGREGATE_DICT, FeatureAttributionStepOutput
+from ...data.attribution import DEFAULT_ATTRIBUTION_AGGREGATE_DICT
 from ...data.batch import EncoderDecoderBatch
-from ...utils import output2ce, output2ent, output2ppl, output2prob
+from ...utils import extract_signature_args, output2ce, output2ent, output2ppl, output2prob
 from ...utils.typing import (
     OneOrMoreAttributionSequences,
     OneOrMoreIdSequences,
@@ -18,6 +19,11 @@
 )
 
 
+if TYPE_CHECKING:
+    from ...models import AttributionModel
+    from .feature_attribution import FeatureAttribution
+
+
 STEP_SCORES_MAP = {
     "probability": output2prob,
     "entropy": output2ent,
@@ -25,6 +31,8 @@
     "perplexity": output2ppl,
 }
 
+logger = logging.getLogger(__name__)
+
 
 def tok2string(
     attribution_model: "AttributionModel",
@@ -33,6 +41,7 @@ def tok2string(
     end: Optional[int] = None,
     as_targets: bool = True,
 ) -> TextInput:
+    """Enables bounded tokenization of a list of lists of tokens with start and end positions."""
     start = [0 if start is None else start for _ in token_lists]
     end = [len(tokens) if end is None else end for tokens in token_lists]
     return attribution_model.convert_tokens_to_string(
@@ -41,38 +50,6 @@ def tok2string(
     )
 
 
-def get_attribution_sentences(
-    attribution_model: "AttributionModel",
-    batch: EncoderDecoderBatch,
-    start: int,
-    end: int,
-) -> Tuple[List[str], List[str], List[int]]:
-    source_sentences = tok2string(attribution_model, batch.sources.input_tokens, as_targets=False)
-    target_sentences = tok2string(attribution_model, batch.targets.input_tokens)
-    if isinstance(source_sentences, str):
-        source_sentences = [source_sentences]
-        target_sentences = [target_sentences]
-    tokenized_target_sentences = [
-        attribution_model.convert_string_to_tokens(sent, as_targets=True) for sent in target_sentences
-    ]
-    lengths = [min(end, len(tts) + 1) - start for tts in tokenized_target_sentences]
-    return source_sentences, target_sentences, lengths
-
-
-def get_split_targets(
-    attribution_model: "AttributionModel",
-    targets: OneOrMoreTokenSequences,
-    start: int,
-    end: int,
-    step: int,
-) -> Tuple[List[str], List[str], List[str], List[str]]:
-    skipped_prefixes = tok2string(attribution_model, targets, end=start)
-    attributed_sentences = tok2string(attribution_model, targets, start, step + 1)
-    unattributed_suffixes = tok2string(attribution_model, targets, step + 1, end)
-    skipped_suffixes = tok2string(attribution_model, targets, start=end)
-    return skipped_prefixes, attributed_sentences, unattributed_suffixes, skipped_suffixes
-
-
 def rescale_attributions_to_tokens(
     attributions: OneOrMoreAttributionSequences, tokens: OneOrMoreTokenSequences
 ) -> OneOrMoreAttributionSequences:
@@ -104,10 +81,10 @@ def check_attribute_positions(
         `tuple[int, int]`: The start and end positions for attribution.
     """
     if attr_pos_start is None:
-        attr_pos_start = 1
+        attr_pos_start = 0
     if attr_pos_end is None or attr_pos_end > max_length:
         attr_pos_end = max_length
-    if attr_pos_start > attr_pos_end or attr_pos_start < 1:
+    if attr_pos_start > attr_pos_end:
         raise ValueError("Invalid starting position for attribution")
     if attr_pos_start == attr_pos_end:
         raise ValueError("Start and end attribution positions cannot be the same.")
@@ -127,56 +104,67 @@ def get_step_scores(
     if attribution_model is None:
         raise ValueError("Attribution model is not set.")
     with torch.no_grad():
-        output = attribution_model.model(
-            inputs_embeds=batch.sources.input_embeds,
-            decoder_inputs_embeds=batch.targets.input_embeds,
-            attention_mask=batch.sources.attention_mask,
-            decoder_attention_mask=batch.targets.attention_mask,
-        )
-        return STEP_SCORES_MAP[score_identifier](
-            attribution_model=attribution_model,
+        output = attribution_model.get_forward_output(**attribution_model.format_forward_args(batch))
+        step_scores_args = attribution_model.format_step_function_args(
             forward_output=output,
-            encoder_input_ids=batch.sources.input_ids,
-            decoder_input_ids=batch.targets.input_ids,
-            encoder_input_embeds=batch.sources.input_embeds,
-            decoder_input_embeds=batch.targets.input_embeds,
+            encoder_input_ids=batch.source_ids,
+            decoder_input_ids=batch.target_ids,
+            encoder_input_embeds=batch.source_embeds,
+            decoder_input_embeds=batch.target_embeds,
             target_ids=target_ids,
-            encoder_attention_mask=batch.sources.attention_mask,
-            decoder_attention_mask=batch.targets.attention_mask,
+            encoder_attention_mask=batch.source_mask,
+            decoder_attention_mask=batch.target_mask,
             **step_scores_args,
         )
+        return STEP_SCORES_MAP[score_identifier](**step_scores_args)
 
 
 def join_token_ids(tokens: OneOrMoreTokenSequences, ids: OneOrMoreIdSequences) -> List[TokenWithId]:
     return [[TokenWithId(token, id) for token, id in zip(tok_seq, idx_seq)] for tok_seq, idx_seq in zip(tokens, ids)]
 
 
-def enrich_step_output(
-    step_output: FeatureAttributionStepOutput,
-    batch: EncoderDecoderBatch,
-    target_tokens: OneOrMoreTokenSequences,
-    target_ids: TargetIdsTensor,
-) -> FeatureAttributionStepOutput:
-    r"""
-    Enriches the attribution output with token information, producing the finished
-    :class:`~inseq.data.FeatureAttributionStepOutput` object.
-
-    Args:
-        step_output (:class:`~inseq.data.FeatureAttributionStepOutput`): The output produced
-            by the attribution step, with missing batch information.
-        batch (:class:`~inseq.data.EncoderDecoderBatch`): The batch on which attribution was performed.
-        target_ids (:obj:`torch.Tensor`): Target token ids of size `(batch_size, 1)` corresponding to tokens
-            for which the attribution step was performed.
-
-    Returns:
-        :class:`~inseq.data.FeatureAttributionStepOutput`: The enriched attribution output.
-    """
-    if len(target_ids.shape) == 0:
-        target_ids = target_ids.unsqueeze(0)
-    step_output.source = join_token_ids(batch.sources.input_tokens, batch.sources.input_ids.tolist())
-    step_output.target = [[TokenWithId(token[0], id)] for token, id in zip(target_tokens, target_ids.tolist())]
-    step_output.prefix = join_token_ids(batch.targets.input_tokens, batch.targets.input_ids.tolist())
-    return step_output
+def extract_args(
+    attribution_method: "FeatureAttribution",
+    attributed_fn: Callable[..., SingleScorePerStepTensor],
+    step_scores: List[str],
+    default_args: List[str],
+    **kwargs,
+) -> Tuple[Dict[str, Any], Dict[str, Any], Dict[str, Any]]:
+    attribution_args = kwargs.pop("attribution_args", {})
+    attributed_fn_args = kwargs.pop("attributed_fn_args", {})
+    step_scores_args = kwargs.pop("step_scores_args", {})
+    extra_attribution_args, attribution_unused_args = attribution_method.get_attribution_args(**kwargs)
+    extra_attributed_fn_args, attributed_fn_unused_args = extract_signature_args(
+        kwargs, attributed_fn, exclude_args=default_args, return_remaining=True
+    )
+    extra_step_scores_args = {}
+    for step_score in step_scores:
+        if step_score not in STEP_SCORES_MAP:
+            raise AttributeError(
+                f"Step score {step_score} not found. Available step scores are: "
+                f"{', '.join([x for x in STEP_SCORES_MAP.keys()])}. Use the inseq.register_step_score"
+                f"function to register a custom step score."
+            )
+        extra_step_scores_args.update(
+            **extract_signature_args(
+                kwargs,
+                STEP_SCORES_MAP[step_score],
+                exclude_args=default_args,
+                return_remaining=False,
+            )
+        )
+    step_scores_unused_args = {k: v for k, v in kwargs.items() if k not in extra_step_scores_args}
+    unused_args = {
+        k: v
+        for k, v in kwargs.items()
+        if k in attribution_unused_args.keys() & attributed_fn_unused_args.keys() & step_scores_unused_args.keys()
+    }
+    if unused_args:
+        logger.warning(f"Unused arguments during attribution: {unused_args}")
+    attribution_args.update(extra_attribution_args)
+    attributed_fn_args.update(extra_attributed_fn_args)
+    step_scores_args.update(extra_step_scores_args)
+    return attribution_args, attributed_fn_args, step_scores_args
 
 
 def list_step_scores() -> List[str]:
@@ -231,3 +219,21 @@ def register_step_score(
             if agg_name not in DEFAULT_ATTRIBUTION_AGGREGATE_DICT["step_scores"]:
                 DEFAULT_ATTRIBUTION_AGGREGATE_DICT["step_scores"][agg_name] = {}
             DEFAULT_ATTRIBUTION_AGGREGATE_DICT["step_scores"][agg_name][identifier] = agg_fn
+
+
+def get_source_target_attributions(
+    attr: Union[torch.Tensor, Tuple[torch.Tensor, torch.Tensor]],
+    is_encoder_decoder: bool,
+) -> Tuple[torch.Tensor, torch.Tensor]:
+    if is_encoder_decoder:
+        if isinstance(attr, tuple) and len(attr) > 1:
+            return attr[0], attr[1]
+        elif isinstance(attr, tuple) and len(attr) == 1:
+            return attr[0], None
+        else:
+            return attr, None
+    else:
+        if isinstance(attr, tuple):
+            return None, attr[0]
+        else:
+            return None, attr
diff --git a/inseq/attr/feat/feature_attribution.py b/inseq/attr/feat/feature_attribution.py
index 2f09580c..018843ce 100644
--- a/inseq/attr/feat/feature_attribution.py
+++ b/inseq/attr/feat/feature_attribution.py
@@ -16,20 +16,17 @@
 Todo:
     * 🟡: Allow custom arguments for model loading in the :class:`FeatureAttribution` :meth:`load` method.
 """
-
-from typing import Any, Callable, Dict, List, NoReturn, Optional, Tuple, Union
+from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Sequence, Tuple, Union
 
 import logging
 from abc import abstractmethod
 from datetime import datetime
 
-import torch
 from torchtyping import TensorType
 
 from ...data import (
     Batch,
-    BatchEmbedding,
-    BatchEncoding,
+    DecoderOnlyBatch,
     EncoderDecoderBatch,
     FeatureAttributionInput,
     FeatureAttributionOutput,
@@ -43,18 +40,16 @@
     extract_signature_args,
     find_char_indexes,
     get_available_methods,
+    get_front_padding,
     pretty_tensor,
 )
 from ...utils.typing import ModelIdentifier, SingleScorePerStepTensor, TargetIdsTensor
 from ..attribution_decorators import batched, set_hook, unset_hook
-from .attribution_utils import (
-    STEP_SCORES_MAP,
-    check_attribute_positions,
-    enrich_step_output,
-    get_attribution_sentences,
-    get_split_targets,
-    get_step_scores,
-)
+from .attribution_utils import STEP_SCORES_MAP, check_attribute_positions, get_step_scores, tok2string
+
+
+if TYPE_CHECKING:
+    from ...models import AttributionModel
 
 
 logger = logging.getLogger(__name__)
@@ -73,10 +68,10 @@ class FeatureAttribution(Registry):
             naming convention.
     """
 
-    attr = "method_name"
+    registry_attr = "method_name"
     ignore_extra_args = ["inputs", "baselines", "target", "additional_forward_args"]
 
-    def __init__(self, attribution_model, hook_to_model: bool = True, **kwargs):
+    def __init__(self, attribution_model: "AttributionModel", hook_to_model: bool = True, **kwargs):
         r"""
         Common instantiation steps for FeatureAttribution methods. Hooks the attribution method
         to the model calling the :meth:`~inseq.attr.feat.FeatureAttribution.hook` method of the child class.
@@ -108,8 +103,8 @@ def __init__(self, attribution_model, hook_to_model: bool = True, **kwargs):
     def load(
         cls,
         method_name: str,
-        attribution_model=None,
-        model_name_or_path: ModelIdentifier = None,
+        attribution_model: Optional["AttributionModel"] = None,
+        model_name_or_path: Optional[ModelIdentifier] = None,
         **kwargs,
     ) -> "FeatureAttribution":
         r"""
@@ -134,26 +129,28 @@ def load(
         Returns:
             :class:`~inseq.attr.feat.FeatureAttribution`: The loaded attribution method.
         """
-        from inseq import AttributionModel
+        from ...models import load_model
 
-        if model_name_or_path is None == attribution_model is None:  # noqa
+        if model_name_or_path is not None:
+            model = load_model(model_name_or_path)
+        elif attribution_model is not None:
+            model = attribution_model
+        else:
             raise RuntimeError(
                 "Only one among an initialized model and a model identifier "
                 "must be defined when loading the attribution method."
             )
-        if model_name_or_path:
-            attribution_model = AttributionModel.load(model_name_or_path)
         methods = cls.available_classes()
         if method_name not in methods:
             raise UnknownAttributionMethodError(method_name)
-        return methods[method_name](attribution_model, **kwargs)
+        return methods[method_name](model, **kwargs)
 
     @batched
     def prepare_and_attribute(
         self,
-        sources: FeatureAttributionInput,
+        sources: Sequence[str],
         targets: FeatureAttributionInput,
-        attr_pos_start: Optional[int] = 1,
+        attr_pos_start: Optional[int] = None,
         attr_pos_end: Optional[int] = None,
         show_progress: bool = True,
         pretty_progress: bool = True,
@@ -161,7 +158,6 @@ def prepare_and_attribute(
         attribute_target: bool = False,
         step_scores: List[str] = [],
         include_eos_baseline: bool = False,
-        prepend_bos_token: bool = True,
         attributed_fn: Union[str, Callable[..., SingleScorePerStepTensor], None] = None,
         attribution_args: Dict[str, Any] = {},
         attributed_fn_args: Dict[str, Any] = {},
@@ -171,10 +167,10 @@ def prepare_and_attribute(
         Prepares inputs and performs attribution.
 
         Wraps the attribution method :meth:`~inseq.attr.feat.FeatureAttribution.attribute` method
-        and the :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
+        and the :meth:`~inseq.models.AttributionModel.prepare_inputs_for_attribution` method.
 
         Args:
-            sources (:obj:`FeatureAttributionInput`): The sources provided to the
+            sources (:obj:`list(str)`): The sources provided to the
                 :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
             targets (:obj:`FeatureAttributionInput): The targets provided to the
                 :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
@@ -193,8 +189,6 @@ def prepare_and_attribute(
                 step scores can be added by using the :meth:`~inseq.register_step_score` function.
             include_eos_baseline (:obj:`bool`, `optional`): Whether to include the EOS token in the baseline for
                 attribution. By default the EOS token is not used for attribution. Defaults to False.
-            prepend_bos_token (:obj:`bool`, `optional`): Whether to prepend the BOS token to the input sequence.
-                Defaults to True.
             attributed_fn (:obj:`str` or :obj:`Callable[..., SingleScorePerStepTensor]`, `optional`): The identifier or
                 function of model outputs representing what should be attributed (e.g. output probits of model best
                 prediction after softmax). If it is a string, it must be a valid function.
@@ -209,7 +203,18 @@ def prepare_and_attribute(
                 an optional added list of single :class:`~inseq.data.FeatureAttributionStepOutput` for each step and
                 extra information regarding the attribution parameters.
         """
-        batch = self.prepare(sources, targets, prepend_bos_token, include_eos_baseline)
+        inputs = (sources, targets)
+        if not self.attribution_model.is_encoder_decoder:
+            inputs = targets
+            encoded_sources = self.attribution_model.encode(sources, return_baseline=True)
+            # We do this here to support separate attr_pos_start for different sentences when batching
+            if attr_pos_start is None or attr_pos_start < encoded_sources.input_ids.shape[1]:
+                attr_pos_start = encoded_sources.input_ids.shape[1]
+        batch = self.attribution_model.prepare_inputs_for_attribution(
+            inputs,
+            include_eos_baseline,
+            self.is_layer_attribution,
+        )
         # If prepare_and_attribute was called from AttributionModel.attribute,
         # attributed_fn is already a Callable. Keep here to allow for usage independently
         # of AttributionModel.attribute.
@@ -224,16 +229,12 @@ def prepare_and_attribute(
             output_step_attributions=output_step_attributions,
             attribute_target=attribute_target,
             step_scores=step_scores,
-            prepend_bos_token=prepend_bos_token,
             attribution_args=attribution_args,
             attributed_fn_args=attributed_fn_args,
             step_scores_args=step_scores_args,
         )
         # Same here, repeated from AttributionModel.attribute
         # to allow independent usage
-        attribution_output.info["input_texts"] = [sources] if isinstance(sources, str) else sources
-        attribution_output.info["generated_texts"] = [targets] if isinstance(targets, str) else targets
-        attribution_output.info["prepend_bos_token"] = prepend_bos_token
         attribution_output.info["include_eos_baseline"] = include_eos_baseline
         attribution_output.info["attributed_fn"] = attributed_fn.__name__
         attribution_output.info["attribution_args"] = attribution_args
@@ -241,93 +242,27 @@ def prepare_and_attribute(
         attribution_output.info["step_scores_args"] = step_scores_args
         return attribution_output
 
-    def prepare(
-        self,
-        sources: FeatureAttributionInput,
-        targets: FeatureAttributionInput,
-        prepend_bos_token: bool = True,
-        include_eos_baseline: bool = False,
-    ) -> EncoderDecoderBatch:
-        r"""
-        Prepares sources and target to produce an :class:`~inseq.data.EncoderDecoderBatch`.
-        There are two stages of preparation:
-
-            1. Raw text sources and target texts are encoded by the model.
-            2. The encoded sources and targets are converted to tensors for the forward pass.
-
-        This method is agnostic of the preparation stage of sources and targets. If they are both
-        raw text, they will undergo both steps. If they are already encoded, they will only be embedded.
-        If the feature attribution method works on layers, the embedding step is skipped and embeddings are
-        set to None.
-        The final result will be consistent in both cases.
-
-        Args:
-            sources (:obj:`FeatureAttributionInput`): The sources provided to the
-                :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
-            targets (:obj:`FeatureAttributionInput): The targets provided to the
-                :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
-            prepend_bos_token (:obj:`bool`, `optional`): Whether to prepend a BOS token to the
-                targets, if they are to be encoded. Defaults to True.
-            include_eos_baseline (:obj:`bool`, `optional`): Whether to include the EOS token in the baseline for
-                attribution. By default the EOS token is not used for attribution. Defaults to False.
-
-        Returns:
-            :obj:`EncoderDecoderBatch`: An :class:`~inseq.data.EncoderDecoderBatch` object containing sources
-                and targets in encoded and embedded formats for all inputs.
-        """
-        if isinstance(sources, str) or isinstance(sources, list):
-            sources: BatchEncoding = self.attribution_model.encode(
-                sources, return_baseline=True, include_eos_baseline=include_eos_baseline
-            )
-        if isinstance(sources, BatchEncoding):
-            # Even when we are performing layer attribution, we might need the embeddings
-            # to compute step probabilities.
-            embeds = BatchEmbedding(
-                input_embeds=self.attribution_model.embed(sources.input_ids),
-                baseline_embeds=self.attribution_model.embed(sources.baseline_ids),
-            )
-            sources = Batch(sources, embeds)
-        if isinstance(targets, str) or isinstance(targets, list):
-            targets: BatchEncoding = self.attribution_model.encode(
-                targets,
-                as_targets=True,
-                prepend_bos_token=prepend_bos_token,
-                return_baseline=True,
-                include_eos_baseline=include_eos_baseline,
-            )
-        if isinstance(targets, BatchEncoding):
-            baseline_embeds = None
-            if not self.is_layer_attribution:
-                baseline_embeds = self.attribution_model.embed(targets.baseline_ids, as_targets=True)
-            target_embeds = BatchEmbedding(
-                input_embeds=self.attribution_model.embed(targets.input_ids, as_targets=True),
-                baseline_embeds=baseline_embeds,
-            )
-            targets = Batch(targets, target_embeds)
-        sources_targets = EncoderDecoderBatch(sources, targets)
-        return sources_targets.to(self.attribution_model.device)
-
     def attribute(
         self,
-        batch: EncoderDecoderBatch,
+        batch: Union[DecoderOnlyBatch, EncoderDecoderBatch],
         attributed_fn: Callable[..., SingleScorePerStepTensor],
-        attr_pos_start: Optional[int] = 1,
+        attr_pos_start: Optional[int] = None,
         attr_pos_end: Optional[int] = None,
         show_progress: bool = True,
         pretty_progress: bool = True,
         output_step_attributions: bool = False,
         attribute_target: bool = False,
         step_scores: List[str] = [],
-        prepend_bos_token: bool = True,
         attribution_args: Dict[str, Any] = {},
         attributed_fn_args: Dict[str, Any] = {},
         step_scores_args: Dict[str, Any] = {},
     ) -> FeatureAttributionOutput:
         r"""
-        Attributes each target token to each source token for every sequence in the batch.
+        Performs the feature attribution procedure using the specified attribution method.
 
         Args:
-            batch (:class:`~inseq.data.EncoderDecoderBatch`): The batch of sequences to attribute.
+            batch (:class:`~inseq.data.EncoderDecoderBatch` or :class:`~inseq.data.DecoderOnlyBatch`): The batch of
+                sequences to attribute.
             attributed_fn (:obj:`Callable[..., SingleScorePerStepTensor]`): The function of model
                 outputs representing what should be attributed (e.g. output probits of model best
                 prediction after softmax). It must be a function that taking multiple keyword
@@ -346,8 +281,6 @@ def attribute(
             step_scores (:obj:`list` of `str`): List of identifiers for step scores that need to be computed during
                 attribution. The available step scores are defined in :obj:`inseq.attr.feat.STEP_SCORES_MAP` and new
                 step scores can be added by using the :meth:`~inseq.register_step_score` function.
-            prepend_bos_token (:obj:`bool`, `optional`): Whether to prepend a BOS token to the
-                targets, if they are to be encoded. Defaults to True.
             attribution_args (:obj:`dict`, `optional`): Additional arguments to pass to the attribution method.
             attributed_fn_args (:obj:`dict`, `optional`): Additional arguments to pass to the attributed function.
             step_scores_args (:obj:`dict`, `optional`): Additional arguments to pass to the step scores function.
@@ -360,33 +293,53 @@ def attribute(
             raise ValueError(
                 "Layer attribution methods do not support attribute_target=True. Use regular ones instead."
             )
-        start = datetime.now()
-        max_generated_length = batch.targets.input_ids.shape[1]
         attr_pos_start, attr_pos_end = check_attribute_positions(
-            max_generated_length,
+            batch.max_generation_length,
             attr_pos_start,
             attr_pos_end,
         )
         logger.debug("=" * 30 + f"\nfull batch: {batch}\n" + "=" * 30)
-        sources, targets, lengths = get_attribution_sentences(
-            self.attribution_model, batch, attr_pos_start, attr_pos_end
+        # Sources are empty for decoder-only models
+        sequences = self.attribution_model.get_text_sequences(batch)
+        target_tokens_with_ids = self.attribution_model.tokenize_with_ids(
+            sequences.targets, as_targets=True, skip_special_tokens=False
         )
+        # Manages front padding for decoder-only models, using 0 as lower bound
+        # when attr_pos_start exceeds target length.
+        targets_lengths = [
+            max(
+                0,
+                min(attr_pos_end, len(target_tokens_with_ids[idx]))
+                - attr_pos_start
+                + get_front_padding(batch.target_mask)[idx],
+            )
+            for idx in range(len(target_tokens_with_ids))
+        ]
         pbar = get_progress_bar(
-            all_sentences=(sources, targets, lengths),
+            sequences=sequences,
+            target_lengths=targets_lengths,
             method_name=self.method_name,
             show=show_progress,
             pretty=pretty_progress,
             attr_pos_start=attr_pos_start,
             attr_pos_end=attr_pos_end,
         )
-        whitespace_indexes = find_char_indexes(targets, " ")
+        whitespace_indexes = find_char_indexes(sequences.targets, " ")
         attribution_outputs = []
-        for step in range(attr_pos_start, attr_pos_end):
+        if self.attribution_model.is_encoder_decoder:
+            iter_pos_start, iter_pos_end = attr_pos_start + 1, min(attr_pos_end + 1, batch.max_generation_length)
+        else:
+            iter_pos_start, iter_pos_end = attr_pos_start, attr_pos_end
+        start = datetime.now()
+
+        # Attribution loop for generation
+        for step in range(iter_pos_start, iter_pos_end):
+            tgt_ids, tgt_mask = batch.get_step_target(step, with_attention=True)
             step_output = self.filtered_attribute_step(
                 batch[:step],
-                target_ids=batch.targets.input_ids[:, step].unsqueeze(1),
+                target_ids=tgt_ids.unsqueeze(1),
                 attributed_fn=attributed_fn,
-                target_attention_mask=batch.targets.attention_mask[:, step].unsqueeze(1),
+                target_attention_mask=tgt_mask.unsqueeze(1),
                 attribute_target=attribute_target,
                 step_scores=step_scores,
                 attribution_args=attribution_args,
@@ -395,32 +348,36 @@ def attribute(
             )
             attribution_outputs.append(step_output)
             if pretty_progress:
-                split_targets = get_split_targets(
-                    self.attribution_model, batch.targets.input_tokens, attr_pos_start, attr_pos_end, step
-                )
+                tgt_tokens = batch.target_tokens
+                skipped_prefixes = tok2string(self.attribution_model, tgt_tokens, end=iter_pos_start)
+                attributed_sentences = tok2string(self.attribution_model, tgt_tokens, iter_pos_start, step + 1)
+                unattributed_suffixes = tok2string(self.attribution_model, tgt_tokens, step + 1, iter_pos_end)
+                skipped_suffixes = tok2string(self.attribution_model, tgt_tokens, start=iter_pos_end)
                 update_progress_bar(
                     pbar,
-                    split_targets,
+                    skipped_prefixes,
+                    attributed_sentences,
+                    unattributed_suffixes,
+                    skipped_suffixes,
                     whitespace_indexes,
                     show=show_progress,
                     pretty=pretty_progress,
                 )
             else:
                 update_progress_bar(pbar, show=show_progress, pretty=pretty_progress)
+        end = datetime.now()
         close_progress_bar(pbar, show=show_progress, pretty=pretty_progress)
         batch.to("cpu")
-        torch.cuda.empty_cache()
-        end = datetime.now()
-        return FeatureAttributionOutput(
+        out = FeatureAttributionOutput(
             sequence_attributions=FeatureAttributionSequenceOutput.from_step_attributions(
-                attribution_outputs, self.attribution_model.pad_token, prepend_bos_token
+                attributions=attribution_outputs,
+                tokenized_target_sentences=target_tokens_with_ids,
+                pad_id=self.attribution_model.pad_token,
+                has_bos_token=self.attribution_model.is_encoder_decoder,
+                attr_pos_end=attr_pos_end,
             ),
             step_attributions=attribution_outputs if output_step_attributions else None,
             info={
-                "model_name": self.attribution_model.model_name,
-                "model_class": self.attribution_model.model.__class__.__name__,
-                "tokenizer_name": self.attribution_model.tokenizer_name,
-                "tokenizer_class": self.attribution_model.tokenizer.__class__.__name__,
                 "attribution_method": self.method_name,
                 "attr_pos_start": attr_pos_start,
                 "attr_pos_end": attr_pos_end,
@@ -431,10 +388,12 @@ def attribute(
                 "exec_time": (end - start).total_seconds(),
             },
         )
+        out.info.update(self.attribution_model.info)
+        return out
 
     def filtered_attribute_step(
         self,
-        batch: EncoderDecoderBatch,
+        batch: Union[DecoderOnlyBatch, EncoderDecoderBatch],
         target_ids: TensorType["batch_size", 1, int],
         attributed_fn: Callable[..., SingleScorePerStepTensor],
         target_attention_mask: Optional[TensorType["batch_size", 1, int]] = None,
@@ -451,7 +410,8 @@ def filtered_attribute_step(
         faster and then reinserted before returning.
 
         Args:
-            batch (:class:`~inseq.data.EncoderDecoderBatch`): The batch of sequences to attribute.
+            batch (:class:`~inseq.data.EncoderDecoderBatch` or :class:`~inseq.data.DecoderOnlyBatch`): The batch of
+                sequences to attribute.
             target_ids (:obj:`torch.Tensor`): Target token ids of size `(batch_size, 1)` corresponding to tokens
                 for which the attribution step must be performed.
             attributed_fn (:obj:`Callable[..., SingleScorePerStepTensor]`): The function of model outputs
@@ -488,14 +448,17 @@ def filtered_attribute_step(
             f"\ntarget_ids: {pretty_tensor(target_ids)},\n"
             f"target_attention_mask: {pretty_tensor(target_attention_mask)}"
         )
+        attribute_main_args = self.format_attribute_args(
+            batch=batch,
+            target_ids=target_ids,
+            attributed_fn=attributed_fn,
+            attribute_target=attribute_target,
+            attributed_fn_args=attributed_fn_args,
+        )
         # Perform attribution step
         step_output = self.attribute_step(
-            batch,
-            target_ids,
-            attributed_fn,
-            attribute_target,
+            attribute_main_args,
             attribution_args,
-            attributed_fn_args,
         )
         # Calculate step scores
         for step_score in step_scores:
@@ -509,7 +472,7 @@ def filtered_attribute_step(
                 self.attribution_model, batch, target_ids, step_score, step_scores_args
             )
         # Add batch information to output
-        step_output = enrich_step_output(
+        step_output = self.attribution_model.enrich_step_output(
             step_output,
             orig_batch,
             self.attribution_model.convert_ids_to_tokens(orig_target_ids, skip_special_tokens=False),
@@ -519,7 +482,6 @@ def filtered_attribute_step(
         if target_attention_mask is not None and is_filtered:
             step_output.remap_from_filtered(target_attention_mask)
         step_output = step_output.detach().to("cpu")
-        torch.cuda.empty_cache()
         return step_output
 
     def get_attribution_args(self, **kwargs) -> Tuple[Dict[str, Any], Dict[str, Any]]:
@@ -529,69 +491,18 @@ def get_attribution_args(self, **kwargs) -> Tuple[Dict[str, Any], Dict[str, Any]
 
     def format_attribute_args(
         self,
-        batch: EncoderDecoderBatch,
+        batch: Union[Batch, EncoderDecoderBatch],
         target_ids: TargetIdsTensor,
         attributed_fn: Callable[..., SingleScorePerStepTensor],
-        attribute_target: bool = False,
         attributed_fn_args: Dict[str, Any] = {},
         **kwargs,
     ) -> Dict[str, Any]:
-        if self.is_layer_attribution:
-            inputs = (batch.sources.input_ids,)
-            baselines = (batch.sources.baseline_ids,)
-        else:
-            inputs = (batch.sources.input_embeds,)
-            baselines = (batch.sources.baseline_embeds,)
-        if attribute_target:
-            inputs = inputs + (batch.targets.input_embeds,)
-            baselines = baselines + (batch.targets.baseline_embeds,)
-        attribute_fn_args = {
-            "inputs": inputs,
-            "additional_forward_args": (
-                # Ids are always explicitly passed as extra arguments to enable
-                # usage in custom attribution functions.
-                batch.sources.input_ids,
-                batch.targets.input_ids,
-                # Making targets 2D enables _expand_additional_forward_args
-                # in Captum to preserve the expected batch dimension for methods
-                # such as intergrated gradients.
-                target_ids.unsqueeze(-1),
-                attributed_fn,
-                batch.sources.attention_mask,
-                batch.targets.attention_mask,
-                # Defines how to treat source and target tensors
-                # Maps on the use_embeddings argument of forward
-                not self.is_layer_attribution,
-                list(attributed_fn_args.keys()),
-            )
-            + tuple(attributed_fn_args.values()),
-        }
-        if not attribute_target:
-            attribute_fn_args["additional_forward_args"] = (batch.targets.input_embeds,) + attribute_fn_args[
-                "additional_forward_args"
-            ]
-        if self.use_baseline:
-            attribute_fn_args["baselines"] = baselines
-        return attribute_fn_args
-
-    @abstractmethod
-    def attribute_step(
-        self,
-        batch: EncoderDecoderBatch,
-        target_ids: TensorType["batch_size", int],
-        attributed_fn: Callable[..., SingleScorePerStepTensor],
-        attribute_target: bool = False,
-        attribution_args: Dict[str, Any] = {},
-        attributed_fn_args: Dict[str, Any] = {},
-    ) -> FeatureAttributionStepOutput:
         r"""
-        Performs a single attribution step for the specified target_ids,
-        given sources and targets in the batch.
-
-        Abstract method, must be implemented by subclasses.
+        Formats inputs for the attribution method based on the model type and the attribution method requirements.
 
         Args:
-            batch (:class:`~inseq.data.EncoderDecoderBatch`): The batch of sequences on which attribution is performed.
+            batch (:class:`~inseq.data.Batch` or :class:`~inseq.data.EncoderDecoderBatch`): The batch of sequences on
+                which attribution is performed.
             target_ids (:obj:`torch.Tensor`): Target token ids of size `(batch_size)` corresponding to tokens
                 for which the attribution step must be performed.
             attributed_fn (:obj:`Callable[..., SingleScorePerStepTensor]`): The function of model outputs
@@ -600,20 +511,51 @@ def attribute_step(
                 of size (batch_size,). If not provided, the default attributed function for the model will be used
                 (change attribution_model.default_attributed_fn_id).
             attribute_target (:obj:`bool`, optional): Whether to attribute the target prefix or not. Defaults to False.
-            attribution_args (:obj:`dict`, `optional`): Additional arguments to pass to the attribution method.
-                Defaults to {}.
             attributed_fn_args (:obj:`dict`, `optional`): Additional arguments to pass to the attributed function.
                 Defaults to {}.
+            **kwargs: Additional arguments to pass to the model-specific
+                :meth:`inseq.models.AttributionModel.format_attribution_args` method.
         Returns:
-            :class:`~inseq.data.FeatureAttributionStepOutput`: A dataclass containing attribution tensors for source
-                and target attributions of size `(batch_size, source_length)` and `(batch_size, prefix length)`.
-                (target optional if attribute_target=True), plus batch information and any step score present.
+            :obj:`dict`: A dictionary containing the formatted attribution arguments.
         """
-        pass
+        logger.debug(f"batch: {batch},\ntarget_ids: {pretty_tensor(target_ids, lpad=4)}")
+        attribute_fn_args, baselines = self.attribution_model.format_attribution_args(
+            batch=batch,
+            target_ids=target_ids,
+            attributed_fn=attributed_fn,
+            attributed_fn_args=attributed_fn_args,
+            is_layer_attribution=self.is_layer_attribution,
+            **kwargs,
+        )
+        if self.use_baseline:
+            attribute_fn_args["baselines"] = baselines
+        return attribute_fn_args
+
+    def attribute_step(
+        self,
+        attribute_fn_main_args: Dict[str, Any],
+        attribution_args: Dict[str, Any] = {},
+    ) -> Any:
+        r"""
+        Performs a single attribution step for the specified attribution arguments.
+
+        Args:
+            attribute_fn_main_args (:obj:`dict`): Main arguments used for the attribution method. These are built from
+                model inputs at the current step of the feature attribution process.
+            attribution_args (:obj:`dict`, `optional`): Additional arguments to pass to the attribution method.
+                These can be specified by the user while calling the top level `attribute` methods. Defaults to {}.
+
+        Returns:
+            :class:`~inseq.data.FeatureAttributionStepOutput`: A dataclass containing a tensor of source
+                attributions of size `(batch_size, source_length)`. At this point the batch
+                information is empty, and will later be filled by the enrich_step_output function.
+        """
+        attr = self.method.attribute(**attribute_fn_main_args, **attribution_args)
+        return FeatureAttributionStepOutput(source_attributions=attr, step_scores={})
 
     @abstractmethod
     @set_hook
-    def hook(self, **kwargs) -> NoReturn:
+    def hook(self, **kwargs) -> None:
         r"""
         Hooks the attribution method to the model. Useful to implement pre-attribution logic
         (e.g. freezing layers, replacing embeddings, raise warnings, etc.).
@@ -624,7 +566,7 @@ def hook(self, **kwargs) -> NoReturn:
 
     @abstractmethod
     @unset_hook
-    def unhook(self, **kwargs) -> NoReturn:
+    def unhook(self, **kwargs) -> None:
         r"""
         Unhooks the attribution method from the model. If the model was modified in any way, this
         should restore its initial state.
diff --git a/inseq/attr/feat/gradient_attribution.py b/inseq/attr/feat/gradient_attribution.py
index a0d8b89a..d99d5096 100644
--- a/inseq/attr/feat/gradient_attribution.py
+++ b/inseq/attr/feat/gradient_attribution.py
@@ -28,9 +28,10 @@
 )
 
 from ...data import EncoderDecoderBatch, GradientFeatureAttributionStepOutput
-from ...utils import Registry, extract_signature_args, pretty_tensor, rgetattr
+from ...utils import Registry, extract_signature_args, rgetattr
 from ...utils.typing import SingleScorePerStepTensor, TargetIdsTensor
 from ..attribution_decorators import set_hook, unset_hook
+from .attribution_utils import get_source_target_attributions
 from .feature_attribution import FeatureAttribution
 from .ops import DiscretetizedIntegratedGradients
 
@@ -67,31 +68,18 @@ def unhook(self, **kwargs):
 
     def attribute_step(
         self,
-        batch: EncoderDecoderBatch,
-        target_ids: TargetIdsTensor,
-        attributed_fn: Callable[..., SingleScorePerStepTensor],
-        attribute_target: bool = False,
+        attribute_fn_main_args: Dict[str, Any],
         attribution_args: Dict[str, Any] = {},
-        attributed_fn_args: Dict[str, Any] = {},
     ) -> GradientFeatureAttributionStepOutput:
         r"""
-        Performs a single attribution step for the specified target_ids,
-        given sources and targets in the batch.
+        Performs a single attribution step for the specified attribution arguments.
 
         Args:
-            batch (:class:`~inseq.data.EncoderDecoderBatch`): The batch of sequences on which attribution is performed.
-            target_ids (:obj:`torch.Tensor`): Target token ids of size `(batch_size)` corresponding to tokens
-                for which the attribution step must be performed.
-            attributed_fn (:obj:`Callable[..., SingleScorePerStepTensor]`): The function of model outputs
-                representing what should be attributed (e.g. output probits of model best prediction after softmax).
-                The parameter must be a function that taking multiple keyword arguments and returns a :obj:`tensor`
-                of size (batch_size,). If not provided, the default attributed function for the model will be used
-                (change attribution_model.default_attributed_fn_id).
-            attribute_target (:obj:`bool`, optional): Whether to attribute the target prefix or not. Defaults to False.
+            attribute_fn_main_args (:obj:`dict`): Main arguments used for the attribution method. These are built from
+                model inputs at the current step of the feature attribution process.
             attribution_args (:obj:`dict`, `optional`): Additional arguments to pass to the attribution method.
-                Defaults to {}.
-            attributed_fn_args (:obj:`dict`, `optional`): Additional arguments to pass to the attributed function.
-                Defaults to {}.
+                These can be specified by the user while calling the top level `attribute` methods. Defaults to {}.
+
         Returns:
             :class:`~inseq.data.GradientFeatureAttributionStepOutput`: A dataclass containing a tensor of source
                 attributions of size `(batch_size, source_length)`, possibly a tensor of target attributions of size
@@ -99,11 +87,7 @@ def attribute_step(
                 `(batch_size)` if the attribution step supports deltas and they are requested. At this point the batch
                 information is empty, and will later be filled by the enrich_step_output function.
         """
-        logger.debug(f"batch: {batch},\ntarget_ids: {pretty_tensor(target_ids, lpad=4)}")
-        attribute_fn_args = self.format_attribute_args(
-            batch, target_ids, attributed_fn, attribute_target, attributed_fn_args, **attribution_args
-        )
-        attr = self.method.attribute(**attribute_fn_args, **attribution_args)
+        attr = self.method.attribute(**attribute_fn_main_args, **attribution_args)
         deltas = None
         if (
             attribution_args.get("return_convergence_delta", False)
@@ -111,11 +95,12 @@ def attribute_step(
             and self.method.has_convergence_delta()
         ):
             attr, deltas = attr
+        source_attributions, target_attributions = get_source_target_attributions(
+            attr, self.attribution_model.is_encoder_decoder
+        )
         return GradientFeatureAttributionStepOutput(
-            source_attributions=attr if not isinstance(attr, tuple) else attr[0],
-            target_attributions=None
-            if not isinstance(attr, tuple) or (isinstance(attr, tuple) and len(attr) == 1)
-            else attr[1],
+            source_attributions=source_attributions,
+            target_attributions=target_attributions,
             step_scores={"deltas": deltas} if deltas is not None else {},
         )
 
@@ -165,7 +150,7 @@ def hook(self, **kwargs):
             self.attribution_model.model_name,
             vocabulary_embeddings=self.attribution_model.vocabulary_embeddings.detach(),
             special_tokens=self.attribution_model.special_tokens_ids,
-            embedding_scaling=self.attribution_model.encoder_embed_scale,
+            embedding_scaling=self.attribution_model.embed_scale,
             **load_kwargs,
         )
         super().hook(**other_kwargs)
@@ -179,10 +164,13 @@ def format_attribute_args(
         attributed_fn_args: Dict[str, Any] = {},
         n_steps: Optional[int] = None,
         strategy: Optional[str] = None,
-        **kwargs,
     ) -> Dict[str, Any]:
         attribute_fn_args = super().format_attribute_args(
-            batch, target_ids, attributed_fn, attribute_target, attributed_fn_args, **kwargs
+            batch=batch,
+            target_ids=target_ids,
+            attributed_fn=attributed_fn,
+            attribute_target=attribute_target,
+            attributed_fn_args=attributed_fn_args,
         )
         attribute_fn_args["inputs"] = (
             self.method.path_builder.scale_inputs(
diff --git a/inseq/commands/attribute.py b/inseq/commands/attribute.py
index 8b0c1337..f6015bb4 100644
--- a/inseq/commands/attribute.py
+++ b/inseq/commands/attribute.py
@@ -1,10 +1,10 @@
 from typing import List, Optional
 
+import logging
 from dataclasses import dataclass, field
 
-import torch
-
 from .. import list_feature_attribution_methods, load_model
+from ..utils import get_default_device
 from .base import BaseCLICommand
 
 
@@ -16,7 +16,7 @@ class AttributeBaseArgs:
     attribution_method: Optional[str] = field(
         default="integrated_gradients",
         metadata={
-            "alias": "-am",
+            "alias": "-a",
             "help": "The attribution method used to perform feature attribution.",
             "choices": list_feature_attribution_methods(),
         },
@@ -24,31 +24,29 @@ class AttributeBaseArgs:
     do_prefix_attribution: bool = field(
         default=False,
         metadata={
-            "alias": "-pa",
             "help": "Performs the attribution procedure including the generated prefix at every step.",
         },
     )
     step_scores: List[str] = field(
-        default_factory=list, metadata={"alias": "-ss", "help": "Adds step scores to the attribution output."}
+        default_factory=list, metadata={"help": "Adds step scores to the attribution output."}
     )
     output_step_attributions: bool = field(
-        default=False, metadata={"alias": "-sa", "help": "Adds step-level feature attributions to the output."}
+        default=False, metadata={"help": "Adds step-level feature attributions to the output."}
     )
     include_eos_baseline: bool = field(
         default=False,
         metadata={
-            "alias": "-eos",
+            "alias": "--eos",
             "help": "Whether the EOS token should be included in the baseline, used for some attribution methods.",
         },
     )
     n_approximation_steps: Optional[int] = field(
         default=100,
-        metadata={"alias": "-ns", "help": "Number of approximation steps, used for some attribution methods."},
+        metadata={"alias": "-n", "help": "Number of approximation steps, used for some attribution methods."},
     )
     return_convergence_delta: bool = field(
         default=False,
         metadata={
-            "alias": "-cd",
             "help": "Returns the convergence delta of the approximation, used for some attribution methods.",
         },
     )
@@ -62,18 +60,17 @@ class AttributeBaseArgs:
     attribution_batch_size: Optional[int] = field(
         default=50,
         metadata={
-            "alias": "-abs",
             "help": "The internal batch size used by the attribution method, used for some attribution methods.",
         },
     )
     device: str = field(
-        default="cuda:0" if torch.cuda.is_available() else "cpu",
-        metadata={"alias": "-dev", "help": "The device used for inference with Pytorch. Multi-GPU is not supported."},
+        default=get_default_device(),
+        metadata={"alias": "--dev", "help": "The device used for inference with Pytorch. Multi-GPU is not supported."},
     )
     hide_attributions: bool = field(
         default=False,
         metadata={
-            "alias": "-noshow",
+            "alias": "--hide",
             "help": "If specified, the attribution visualization are not shown in the output.",
         },
     )
@@ -81,6 +78,32 @@ class AttributeBaseArgs:
         default=None,
         metadata={"alias": "-o", "help": "Path where the attribution output should be saved in JSON format."},
     )
+    viz_path: Optional[str] = field(
+        default=None,
+        metadata={
+            "help": "Path where the attribution visualization should be saved in HTML format.",
+        },
+    )
+    max_gen_length: Optional[int] = field(
+        default=None,
+        metadata={"alias": "-l", "help": "Max generation length for model outputs. Default: 512"},
+    )
+    start_pos: Optional[int] = field(
+        default=None,
+        metadata={"alias": "-s", "help": "Start position for the attribution. Default: first token"},
+    )
+    end_pos: Optional[int] = field(
+        default=None,
+        metadata={"alias": "-e", "help": "End position for the attribution. Default: last token"},
+    )
+    verbose: bool = field(
+        default=False,
+        metadata={"alias": "-v", "help": "If specified, use INFO as logging level for the attribution."},
+    )
+    very_verbose: bool = field(
+        default=False,
+        metadata={"alias": "-vv", "help": "If specified, use DEBUG as logging level for the attribution."},
+    )
 
 
 @dataclass
@@ -91,7 +114,7 @@ class AttributeArgs(AttributeBaseArgs):
     generated_texts: Optional[List[str]] = field(
         default=None,
         metadata={
-            "alias": "-gen",
+            "alias": "-g",
             "help": "If specified, constrains the decoding procedure to the specified outputs.",
         },
     )
@@ -106,7 +129,22 @@ def __post_init__(self):
 
 
 def attribute(input_texts, generated_texts, args: AttributeBaseArgs):
-    model = load_model(args.model_name_or_path, attribution_method=args.attribution_method)
+    if args.very_verbose:
+        log_level = logging.DEBUG
+    elif args.verbose:
+        log_level = logging.INFO
+    else:
+        log_level = logging.WARNING
+    logging.basicConfig(
+        level=log_level,
+        format="%(asctime)s.%(msecs)03d %(levelname)s %(module)s - %(funcName)s: %(message)s",
+        datefmt="%Y-%m-%d %H:%M:%S",
+    )
+    model = load_model(
+        args.model_name_or_path,
+        attribution_method=args.attribution_method,
+        device=args.device,
+    )
     out = model.attribute(
         input_texts,
         generated_texts,
@@ -119,9 +157,17 @@ def attribute(input_texts, generated_texts, args: AttributeBaseArgs):
         internal_batch_size=args.attribution_batch_size,
         return_convergence_delta=args.return_convergence_delta,
         device=args.device,
-    )
-    if not args.hide_attributions:
-        out.show()
+        generation_args={"max_new_tokens": args.max_gen_length},
+        attr_pos_start=args.start_pos,
+        attr_pos_end=args.end_pos,
+    )
+    if args.viz_path:
+        print(f"Saving visualization to {args.viz_path}")
+        html = out.show(return_html=True, display=not args.hide_attributions)
+        with open(args.viz_path, "w") as f:
+            f.write(html)
+    else:
+        out.show(display=not args.hide_attributions)
     if args.save_path:
         print(f"Saving attributions to {args.save_path}")
         out.save(args.save_path, overwrite=True)
diff --git a/inseq/data/__init__.py b/inseq/data/__init__.py
index 9d50b02e..b854ab99 100644
--- a/inseq/data/__init__.py
+++ b/inseq/data/__init__.py
@@ -13,7 +13,7 @@
     FeatureAttributionStepOutput,
     GradientFeatureAttributionStepOutput,
 )
-from .batch import Batch, BatchEmbedding, BatchEncoding, EncoderDecoderBatch
+from .batch import Batch, BatchEmbedding, BatchEncoding, DecoderOnlyBatch, EncoderDecoderBatch
 from .viz import show_attributions
 
 
@@ -25,6 +25,7 @@
     "SubwordAggregator",
     "PairAggregator",
     "Batch",
+    "DecoderOnlyBatch",
     "BatchEmbedding",
     "BatchEncoding",
     "EncoderDecoderBatch",
diff --git a/inseq/data/aggregator.py b/inseq/data/aggregator.py
index c79631ab..f3b9ca8e 100644
--- a/inseq/data/aggregator.py
+++ b/inseq/data/aggregator.py
@@ -166,7 +166,8 @@ def post_aggregate_hook(cls, attr, **kwargs):
     def end_aggregation_hook(cls, attr: TensorWrapper, **kwargs):
         super().end_aggregation_hook(attr, **kwargs)
         # Needed to ensure the attribution can be visualized
-        assert len(attr.source_attributions.shape) == 2
+        if attr.source_attributions is not None:
+            assert len(attr.source_attributions.shape) == 2
         if attr.target_attributions is not None:
             assert len(attr.target_attributions.shape) == 2
 
@@ -180,6 +181,8 @@ def aggregate_target(attr, **kwargs):
 
     @staticmethod
     def aggregate_source_attributions(attr, aggregate_fn: Union[Dict[str, Callable], Callable], **kwargs):
+        if attr.source_attributions is None:
+            return attr.source_attributions
         if attr.target_attributions is None:
             return aggregate_fn(attr.source_attributions)
         else:
@@ -189,6 +192,8 @@ def aggregate_source_attributions(attr, aggregate_fn: Union[Dict[str, Callable],
     def aggregate_target_attributions(attr, aggregate_fn: Callable, **kwargs):
         if attr.target_attributions is None:
             return attr.target_attributions
+        if attr.source_attributions is None:
+            return aggregate_fn(attr.target_attributions)
         else:
             return aggregate_fn((attr.source_attributions, attr.target_attributions))[1]
 
@@ -200,19 +205,28 @@ def aggregate_step_scores(attr, **kwargs):
     def aggregate_sequence_scores(attr, **kwargs):
         return attr.sequence_scores
 
+    @staticmethod
+    def aggregate_attr_pos_start(attr, **kwargs):
+        return attr.attr_pos_start
+
+    @staticmethod
+    def aggregate_attr_pos_end(attr, **kwargs):
+        return attr.attr_pos_end
+
     @staticmethod
     def is_compatible(attr):
         from .attribution import FeatureAttributionSequenceOutput
 
         assert isinstance(attr, FeatureAttributionSequenceOutput)
-        assert attr.source_attributions.shape[0] == len(attr.source)
-        assert attr.source_attributions.shape[1] == len(attr.target)
+        if attr.source_attributions is not None:
+            assert attr.source_attributions.shape[0] == len(attr.source)
+            assert attr.source_attributions.shape[1] == attr.attr_pos_end - attr.attr_pos_start
         if attr.target_attributions is not None:
-            assert attr.target_attributions.shape[0] == len(attr.target)
-            assert attr.target_attributions.shape[1] == len(attr.target)
+            assert attr.target_attributions.shape[0] == min(len(attr.target), attr.attr_pos_end)
+            assert attr.target_attributions.shape[1] == attr.attr_pos_end - attr.attr_pos_start
         if attr.step_scores is not None:
             for step_score in attr.step_scores.values():
-                assert len(step_score) == len(attr.target)
+                assert len(step_score) == attr.attr_pos_end - attr.attr_pos_start
         if attr.sequence_scores is not None:
             for sequence_score in attr.sequence_scores.values():
                 assert sequence_score.shape == attr.source_attributions.shape
@@ -311,6 +325,8 @@ def aggregate_target(attr, target_spans, **kwargs):
 
     @staticmethod
     def aggregate_source_attributions(attr, source_spans, target_spans, aggregate_fn, **kwargs):
+        if attr.source_attributions is None:
+            return attr.source_attributions
         # First aggregate along generated target sequence, then along attributed source
         return ContiguousSpanAggregator._aggregate_sequential_scores(
             attr.source_attributions, source_spans, target_spans, aggregate_fn
@@ -438,9 +454,10 @@ def aggregate(
     def validate_pair(cls, attr, paired_attr):
         assert len(attr.source) == len(paired_attr.source), "Source sequences must be the same length."
         assert len(attr.target) == len(paired_attr.target), "Target sequences must be the same length."
-        assert (
-            attr.source_attributions.shape == paired_attr.source_attributions.shape
-        ), "Source attributions must be the same shape."
+        if attr.source_attributions is not None:
+            assert (
+                attr.source_attributions.shape == paired_attr.source_attributions.shape
+            ), "Source attributions must be the same shape."
         if attr.target_attributions is not None:
             assert (
                 attr.target_attributions.shape == paired_attr.target_attributions.shape
@@ -468,6 +485,8 @@ def aggregate_target(attr, paired_attr, **kwargs):
 
     @staticmethod
     def aggregate_source_attributions(attr, paired_attr, aggregate_fn, **kwargs):
+        if attr.source_attributions is None:
+            return attr.source_attributions
         return aggregate_fn(attr.source_attributions, paired_attr.source_attributions)
 
     @staticmethod
diff --git a/inseq/data/attribution.py b/inseq/data/attribution.py
index 4aec1fe7..aa67b17a 100644
--- a/inseq/data/attribution.py
+++ b/inseq/data/attribution.py
@@ -1,5 +1,6 @@
 from typing import Any, Dict, List, Optional, Type, Union
 
+import logging
 import os
 from dataclasses import dataclass, field
 
@@ -48,6 +49,8 @@
     },
 }
 
+logger = logging.getLogger(__name__)
+
 
 @dataclass(eq=False, repr=False)
 class FeatureAttributionSequenceOutput(TensorWrapper, AggregableMixin):
@@ -73,10 +76,12 @@ class FeatureAttributionSequenceOutput(TensorWrapper, AggregableMixin):
 
     source: List[TokenWithId]
     target: List[TokenWithId]
-    source_attributions: SequenceAttributionTensor
+    source_attributions: Optional[SequenceAttributionTensor] = None
     target_attributions: Optional[SequenceAttributionTensor] = None
     step_scores: Optional[Dict[str, SingleScoresPerSequenceTensor]] = None
     sequence_scores: Optional[Dict[str, MultipleScoresPerSequenceTensor]] = None
+    attr_pos_start: int = 0
+    attr_pos_end: Optional[int] = None
     _aggregator: Union[AggregatorPipeline, Type[Aggregator]] = None
     _dict_aggregate_fn: Dict[str, Any] = None
 
@@ -89,37 +94,56 @@ def __post_init__(self):
             self._dict_aggregate_fn = aggregate_dict
         if self._aggregator is None:
             self._aggregator = SequenceAttributionAggregator
+        if self.attr_pos_end is None or self.attr_pos_end > len(self.target):
+            self.attr_pos_end = len(self.target)
 
     @classmethod
     def from_step_attributions(
         cls,
         attributions: List["FeatureAttributionStepOutput"],
+        tokenized_target_sentences: Optional[List[List[TokenWithId]]] = None,
         pad_id: Optional[Any] = None,
         has_bos_token: bool = True,
+        attr_pos_end: Optional[int] = None,
     ) -> List["FeatureAttributionSequenceOutput"]:
         attr = attributions[0]
         seq_attr_cls = attr._sequence_cls
-        num_sequences = len(attr.source_attributions)
-        if not all([len(att.source_attributions) == num_sequences for att in attributions]):
+        num_sequences = len(attr.prefix)
+        if not all([len(attr.prefix) == num_sequences for attr in attributions]):
             raise ValueError("All the attributions must include the same number of sequences.")
-        source_attributions = get_sequences_from_batched_steps([att.source_attributions for att in attributions])
         seq_attributions = []
-        sources = [drop_padding(attr.source[seq_id], pad_id) for seq_id in range(num_sequences)]
+        sources = None
+        if attr.source_attributions is not None:
+            sources = [drop_padding(attr.source[seq_id], pad_id) for seq_id in range(num_sequences)]
         targets = [
             drop_padding([a.target[seq_id][0] for a in attributions], pad_id) for seq_id in range(num_sequences)
         ]
+        if tokenized_target_sentences is None:
+            tokenized_target_sentences = targets
+        if attr_pos_end is None:
+            attr_pos_end = max([len(t) for t in tokenized_target_sentences])
+        pos_start = [
+            min(len(tokenized_target_sentences[seq_id]), attr_pos_end) - len(targets[seq_id])
+            for seq_id in range(num_sequences)
+        ]
         for seq_id in range(num_sequences):
-            # Remove padding from tensor
-            filtered_source_attribution = source_attributions[seq_id][
-                : len(sources[seq_id]), : len(targets[seq_id]), ...
-            ]
+            source = tokenized_target_sentences[seq_id][: pos_start[seq_id]] if sources is None else sources[seq_id]
             seq_attributions.append(
                 seq_attr_cls(
-                    source=sources[seq_id],
-                    target=targets[seq_id],
-                    source_attributions=filtered_source_attribution,
+                    source=source,
+                    target=tokenized_target_sentences[seq_id],
+                    attr_pos_start=pos_start[seq_id],
+                    attr_pos_end=attr_pos_end,
                 )
             )
+        if attr.source_attributions is not None:
+            source_attributions = get_sequences_from_batched_steps([att.source_attributions for att in attributions])
+            for seq_id in range(num_sequences):
+                # Remove padding from tensor
+                filtered_source_attribution = source_attributions[seq_id][
+                    : len(sources[seq_id]), : len(targets[seq_id]), ...
+                ]
+                seq_attributions[seq_id].source_attributions = filtered_source_attribution
         if attr.target_attributions is not None:
             target_attributions = get_sequences_from_batched_steps(
                 [att.target_attributions for att in attributions], pad_dims=(1,)
@@ -127,10 +151,12 @@ def from_step_attributions(
             for seq_id in range(num_sequences):
                 if has_bos_token:
                     target_attributions[seq_id] = target_attributions[seq_id][1:, ...]
+                start_idx = max(pos_start) - pos_start[seq_id]
+                end_idx = start_idx + len(tokenized_target_sentences[seq_id])
                 target_attributions[seq_id] = target_attributions[seq_id][
-                    : len(targets[seq_id]), : len(targets[seq_id]), ...
+                    start_idx:end_idx, : len(targets[seq_id]), ...  # noqa: E203
                 ]
-                if target_attributions[seq_id].shape[0] != len(targets[seq_id]):
+                if target_attributions[seq_id].shape[0] != len(tokenized_target_sentences[seq_id]):
                     empty_final_row = torch.ones(1, *target_attributions[seq_id].shape[1:]) * float("nan")
                     target_attributions[seq_id] = torch.cat([target_attributions[seq_id], empty_final_row], dim=0)
                 seq_attributions[seq_id].target_attributions = target_attributions[seq_id]
@@ -170,31 +196,41 @@ def show(
         from inseq import show_attributions
 
         aggregated = self.aggregate(aggregator, **kwargs)
-        return show_attributions(aggregated, min_val, max_val, display, return_html)
+        if (aggregated.source_attributions is not None and aggregated.source_attributions.shape[1] == 0) or (
+            aggregated.target_attributions is not None and aggregated.target_attributions.shape[1] == 0
+        ):
+            tokens = "".join(tid.token for tid in self.target)
+            logger.warning(f"Found empty attributions, skipping attribution matching generation: {tokens}")
+        else:
+            return show_attributions(aggregated, min_val, max_val, display, return_html)
 
     @property
     def minimum(self) -> float:
-        minimum = float(self.source_attributions.min())
+        minimum = 0
+        if self.source_attributions is not None:
+            minimum = min(minimum, float(self.source_attributions.min()))
         if self.target_attributions is not None:
             minimum = min(minimum, float(self.target_attributions.min()))
         return minimum
 
     @property
     def maximum(self) -> float:
-        maxmimum = float(self.source_attributions.max())
+        maximum = 0
+        if self.source_attributions is not None:
+            maximum = max(maximum, float(self.source_attributions.max()))
         if self.target_attributions is not None:
-            maxmimum = max(maxmimum, float(self.target_attributions.max()))
-        return maxmimum
+            maximum = max(maximum, float(self.target_attributions.max()))
+        return maximum
 
     def weight_attributions(self, step_score_id: str):
         aggregated_attr = self.aggregate()
         step_scores = self.step_scores[step_score_id].T.unsqueeze(1)
-        source_attr = aggregated_attr.source_attributions.float().T
-        self.source_attributions = (step_scores * source_attr).T
+        if self.source_attributions is not None:
+            source_attr = aggregated_attr.source_attributions.float().T
+            self.source_attributions = (step_scores * source_attr).T
         if self.target_attributions is not None:
             target_attr = aggregated_attr.target_attributions.float().T
             self.target_attributions = (step_scores * target_attr).T
-        print(step_scores.shape, source_attr.shape, target_attr.shape)
         self._aggregator = AggregatorPipeline([])
         return self
 
@@ -206,9 +242,9 @@ class FeatureAttributionStepOutput(TensorWrapper):
     extra information related to what was attributed.
     """
 
-    source_attributions: StepAttributionTensor
-    target_attributions: Optional[StepAttributionTensor] = None
+    source_attributions: Optional[StepAttributionTensor] = None
     step_scores: Optional[Dict[str, SingleScorePerStepTensor]] = None
+    target_attributions: Optional[StepAttributionTensor] = None
     sequence_scores: Optional[Dict[str, MultipleScoresPerStepTensor]] = None
     source: Optional[OneOrMoreTokenWithIdSequences] = None
     prefix: Optional[OneOrMoreTokenWithIdSequences] = None
@@ -219,11 +255,12 @@ def remap_from_filtered(
         self,
         target_attention_mask: TargetIdsTensor,
     ) -> None:
-        self.source_attributions = remap_from_filtered(
-            original_shape=(len(self.source), *self.source_attributions.shape[1:]),
-            mask=target_attention_mask,
-            filtered=self.source_attributions,
-        )
+        if self.source_attributions is not None:
+            self.source_attributions = remap_from_filtered(
+                original_shape=(len(self.source), *self.source_attributions.shape[1:]),
+                mask=target_attention_mask,
+                filtered=self.source_attributions,
+            )
         if self.target_attributions is not None:
             self.target_attributions = remap_from_filtered(
                 original_shape=(len(self.prefix), *self.target_attributions.shape[1:]),
@@ -271,7 +308,6 @@ class FeatureAttributionOutput:
         "model_class",
         "model_name",
         "step_scores",
-        "prepend_bos_token",
         "tokenizer_class",
         "tokenizer_name",
     ]
@@ -359,10 +395,14 @@ def show(
         Returns:
             str: Attribution visualization as HTML if `return_html=True`, None otherwise.
         """
-        from inseq import show_attributions
-
-        attributions = [attr.aggregate(aggregator, **kwargs) for attr in self.sequence_attributions]
-        return show_attributions(attributions, min_val, max_val, display, return_html)
+        out_str = ""
+        for attr in self.sequence_attributions:
+            if return_html:
+                out_str += attr.show(min_val, max_val, display, return_html, aggregator, **kwargs)
+            else:
+                attr.show(min_val, max_val, display, return_html, aggregator, **kwargs)
+        if return_html:
+            return out_str
 
     @classmethod
     def merge_attributions(cls, attributions: List["FeatureAttributionOutput"]) -> "FeatureAttributionOutput":
diff --git a/inseq/data/batch.py b/inseq/data/batch.py
index f04093f5..d1f048c7 100644
--- a/inseq/data/batch.py
+++ b/inseq/data/batch.py
@@ -1,8 +1,8 @@
-from typing import List, Optional, Union
+from typing import List, Optional, Tuple, Union
 
 from dataclasses import dataclass
 
-from ..utils.typing import EmbeddingsTensor, IdsTensor, OneOrMoreTokenSequences
+from ..utils.typing import EmbeddingsTensor, ExpandedTargetIdsTensor, IdsTensor, OneOrMoreTokenSequences
 from .data_utils import TensorWrapper
 
 
@@ -39,8 +39,10 @@ class BatchEmbedding(TensorWrapper):
     input_embeds: Optional[EmbeddingsTensor] = None
     baseline_embeds: Optional[EmbeddingsTensor] = None
 
-    def __len__(self) -> int:
-        return self.input_embeds.shape[0]
+    def __len__(self) -> Optional[int]:
+        if self.input_embeds is not None:
+            return self.input_embeds.shape[0]
+        return None
 
 
 @dataclass(eq=False, repr=False)
@@ -53,7 +55,7 @@ def input_ids(self) -> IdsTensor:
         return self.encoding.input_ids
 
     @property
-    def input_tokens(self) -> List[List[str]]:
+    def input_tokens(self) -> OneOrMoreTokenSequences:
         return self.encoding.input_tokens
 
     @property
@@ -104,3 +106,94 @@ class EncoderDecoderBatch(TensorWrapper):
 
     def __getitem__(self, subscript: Union[slice, int]) -> "EncoderDecoderBatch":
         return EncoderDecoderBatch(sources=self.sources, targets=self.targets[subscript])
+
+    @property
+    def max_generation_length(self) -> int:
+        return self.targets.input_ids.shape[1]
+
+    @property
+    def source_tokens(self) -> OneOrMoreTokenSequences:
+        return self.sources.input_tokens
+
+    @property
+    def target_tokens(self) -> OneOrMoreTokenSequences:
+        return self.targets.input_tokens
+
+    @property
+    def source_ids(self) -> IdsTensor:
+        return self.sources.input_ids
+
+    @property
+    def target_ids(self) -> IdsTensor:
+        return self.targets.input_ids
+
+    @property
+    def source_embeds(self) -> EmbeddingsTensor:
+        return self.sources.input_embeds
+
+    @property
+    def target_embeds(self) -> EmbeddingsTensor:
+        return self.targets.input_embeds
+
+    @property
+    def source_mask(self) -> IdsTensor:
+        return self.sources.attention_mask
+
+    @property
+    def target_mask(self) -> IdsTensor:
+        return self.targets.attention_mask
+
+    def get_step_target(
+        self, step: int, with_attention: bool = False
+    ) -> Union[ExpandedTargetIdsTensor, Tuple[ExpandedTargetIdsTensor, ExpandedTargetIdsTensor]]:
+        tgt = self.targets.input_ids[:, step]
+        if with_attention:
+            return tgt, self.targets.attention_mask[:, step]
+        return tgt
+
+
+@dataclass(eq=False, repr=False)
+class DecoderOnlyBatch(Batch):
+    @property
+    def max_generation_length(self) -> int:
+        return self.input_ids.shape[1]
+
+    @property
+    def source_tokens(self) -> OneOrMoreTokenSequences:
+        return None
+
+    @property
+    def target_tokens(self) -> OneOrMoreTokenSequences:
+        return self.input_tokens
+
+    @property
+    def source_ids(self) -> IdsTensor:
+        return None
+
+    @property
+    def target_ids(self) -> IdsTensor:
+        return self.input_ids
+
+    @property
+    def source_embeds(self) -> EmbeddingsTensor:
+        return None
+
+    @property
+    def target_embeds(self) -> EmbeddingsTensor:
+        return self.input_embeds
+
+    @property
+    def source_mask(self) -> IdsTensor:
+        return None
+
+    @property
+    def target_mask(self) -> IdsTensor:
+        return self.attention_mask
+
+    def get_step_target(
+        self, step: int, with_attention: bool = False
+    ) -> Union[ExpandedTargetIdsTensor, Tuple[ExpandedTargetIdsTensor, ExpandedTargetIdsTensor]]:
+        tgt = self.input_ids[:, step]
+        if with_attention:
+            return tgt, self.attention_mask[:, step]
+        return tgt
diff --git a/inseq/data/data_utils.py b/inseq/data/data_utils.py
index ae6bada6..5cf79c07 100644
--- a/inseq/data/data_utils.py
+++ b/inseq/data/data_utils.py
@@ -137,6 +137,8 @@ def to(self, device: str):
         for field in fields(self.__class__):
             attr = getattr(self, field.name)
             setattr(self, field.name, self._to(attr, device))
+        if device == "cpu" and torch.cuda.is_available():
+            torch.cuda.empty_cache()
         return self
 
     def detach(self):
diff --git a/inseq/data/viz.py b/inseq/data/viz.py
index 843f0187..ce948ce8 100644
--- a/inseq/data/viz.py
+++ b/inseq/data/viz.py
@@ -29,13 +29,14 @@
 from rich.live import Live
 from rich.padding import Padding
 from rich.panel import Panel
-from rich.progress import BarColumn, Progress, TextColumn
+from rich.progress import BarColumn, Progress, TextColumn, TimeRemainingColumn
 from rich.style import Style
 from rich.table import Column, Table
 from rich.text import Text
 from tqdm.std import tqdm
 
 from ..utils import isnotebook
+from ..utils.typing import TextSequences
 from ..utils.viz_utils import (
     final_plot_html,
     get_colors,
@@ -83,24 +84,35 @@ def show_attributions(
     for ex_id, attribution in enumerate(attributions):
         instance_html = get_instance_html(ex_id)
         curr_html = ""
-        curr_html += instance_html
-        curr_html += get_heatmap_type(attribution, html_colors[idx], "Source", use_html=True)
+        curr_html_color = html_colors[idx]
+        if attribution.source_attributions is not None:
+            curr_html += instance_html
+            curr_html += get_heatmap_type(attribution, curr_html_color, "Source", use_html=True)
+            if attribution.target_attributions is not None:
+                curr_html_color = html_colors[idx + 1]
         if attribution.target_attributions is not None:
             curr_html += instance_html
-            curr_html += get_heatmap_type(attribution, html_colors[idx + 1], "Target", use_html=True)
+            curr_html += get_heatmap_type(attribution, curr_html_color, "Target", use_html=True)
         if display and isnotebook():
             from IPython.core.display import HTML, display
 
             display(HTML(curr_html))
         html_out += curr_html
         if not isnotebook():
-            rprint(get_heatmap_type(attribution, colors[idx], "Source", use_html=False))
-            if attribution.target_attributions is not None:
+            curr_color = colors[idx]
+            if attribution.source_attributions is not None:
+                if display:
+                    print("\n\n")
+                    rprint(get_heatmap_type(attribution, curr_color, "Source", use_html=False))
+                if attribution.target_attributions is not None:
+                    curr_color = colors[idx + 1]
+            if attribution.target_attributions is not None and display:
                 print("\n\n")
-                rprint(get_heatmap_type(attribution, colors[idx + 1], "Target", use_html=False))
-        idx += 1
-        if attribution.target_attributions is not None:
+                rprint(get_heatmap_type(attribution, curr_color, "Target", use_html=False))
+        if any(x is None for x in [attribution.source_attributions, attribution.target_attributions]):
             idx += 1
+        else:
+            idx += 2
     if return_html:
         return html_out
 
@@ -122,9 +134,12 @@ def get_attribution_colors(
         min_val = -max_val
     colors = []
     for attribution in attributions:
-        colors.append(
-            get_colors(attribution.source_attributions.numpy(), min_val, max_val, cmap, return_alpha, return_strings)
-        )
+        if attribution.source_attributions is not None:
+            colors.append(
+                get_colors(
+                    attribution.source_attributions.numpy(), min_val, max_val, cmap, return_alpha, return_strings
+                )
+            )
         if attribution.target_attributions is not None:
             colors.append(
                 get_colors(
@@ -147,16 +162,18 @@ def get_heatmap_type(
     if heatmap_type == "Source":
         return heatmap_func(
             attribution.source_attributions.numpy(),
-            [t.token for t in attribution.target],
+            [t.token for t in attribution.target[attribution.attr_pos_start : attribution.attr_pos_end]],  # noqa
             [t.token for t in attribution.source],
             colors,
             step_scores,
             label="Source",
         )
     elif heatmap_type == "Target":
+        mask = np.ones_like(attribution.target_attributions.numpy()) * float("nan")
+        mask = np.tril(mask, k=-attribution.attr_pos_start)
         return heatmap_func(
-            attribution.target_attributions.numpy(),
-            [t.token for t in attribution.target],
+            attribution.target_attributions.numpy() + mask,
+            [t.token for t in attribution.target[attribution.attr_pos_start : attribution.attr_pos_end]],  # noqa
             [t.token for t in attribution.target],
             colors,
             step_scores,
@@ -257,14 +274,14 @@ def get_saliency_heatmap_rich(
 
 
 def get_progress_bar(
-    all_sentences: Tuple[List[str], List[str], List[int]],
+    sequences: TextSequences,
+    target_lengths: List[int],
     method_name: str,
     show: bool,
     pretty: bool,
     attr_pos_start: int,
     attr_pos_end: int,
 ) -> Union[tqdm, Tuple[Progress, Live], None]:
-    sources, targets, lengths = all_sentences
     if not show:
         return None
     elif show and not pretty:
@@ -275,27 +292,37 @@ def get_progress_bar(
         )
     elif show and pretty:
         job_progress = Progress(
-            "{task.description}",
-            BarColumn(),
+            TextColumn("{task.description}", table_column=Column(ratio=3, no_wrap=False)),
+            BarColumn(table_column=Column(ratio=1)),
             TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
+            TimeRemainingColumn(),
         )
-        for idx, (tgt, tgt_len) in enumerate(zip(targets, lengths)):
-            job_progress.add_task(f"{idx}. {tgt}", total=tgt_len)
+        for idx, (tgt, tgt_len) in enumerate(zip(sequences.targets, target_lengths)):
+            clean_tgt = tgt.replace("\n", "\\n")
+            job_progress.add_task(f"{idx}. {clean_tgt}", total=tgt_len)
         progress_table = Table.grid()
-        progress_table.add_row(
-            Panel.fit(
-                "\n".join([f"{idx}. {src}" for idx, src in enumerate(sources)]),
-                title="Source sentences",
-                border_style="red",
-                padding=(1, 2),
-            ),
+        row_contents = [
             Panel.fit(
                 job_progress,
                 title=f"[b]Attributing with {method_name}",
                 border_style="green",
                 padding=(1, 2),
-            ),
-        )
+            )
+        ]
+        if sequences.sources is not None:
+            sources = []
+            for idx, src in enumerate(sequences.sources):
+                clean_src = src.replace("\n", "\\n")
+                sources.append(f"{idx}. {clean_src}")
+            row_contents = [
+                Panel.fit(
+                    "\n".join(sources),
+                    title="Source sentences",
+                    border_style="red",
+                    padding=(1, 2),
+                )
+            ] + row_contents
+        progress_table.add_row(*row_contents)
         live = Live(Padding(progress_table, (1, 0, 1, 0)), refresh_per_second=10)
         live.start(refresh=live._renderable is not None)
         return job_progress, live
@@ -303,7 +330,10 @@ def get_progress_bar(
 
 def update_progress_bar(
     pbar: Union[tqdm, Tuple[Progress, Live], None],
-    split_targets: Tuple[List[str], List[str], List[str], List[str]] = None,
+    skipped_prefixes: Optional[List[str]] = None,
+    attributed_sentences: Optional[List[str]] = None,
+    unattributed_suffixes: Optional[List[str]] = None,
+    skipped_suffixes: Optional[List[str]] = None,
     whitespace_indexes: List[List[int]] = None,
     show: bool = False,
     pretty: bool = False,
@@ -313,6 +343,7 @@ def update_progress_bar(
     elif show and not pretty:
         pbar.update(1)
     else:
+        split_targets = (skipped_prefixes, attributed_sentences, unattributed_suffixes, skipped_suffixes)
         for job in pbar[0].tasks:
             if not job.finished:
                 pbar[0].advance(job.id)
@@ -320,7 +351,7 @@ def update_progress_bar(
                 past_length = 0
                 for split, color in zip(split_targets, ["grey58", "green", "orange1", "grey58"]):
                     if split[job.id]:
-                        formatted_desc += f"[{color}]" + split[job.id] + "[/]"
+                        formatted_desc += f"[{color}]" + split[job.id].replace("\n", "\\n") + "[/]"
                         past_length += len(split[job.id])
                         if past_length in whitespace_indexes[job.id]:
                             formatted_desc += " "
diff --git a/inseq/models/__init__.py b/inseq/models/__init__.py
index f78f31dd..7e220a02 100644
--- a/inseq/models/__init__.py
+++ b/inseq/models/__init__.py
@@ -1,9 +1,51 @@
-from .attribution_model import AttributionModel, load_model
-from .huggingface_model import HuggingfaceModel
+from typing import List, Optional, Union
+
+import logging
+
+from rich.status import Status
+
+from ..utils import isnotebook, optional
+from ..utils.typing import ModelClass, ModelIdentifier
+from .attribution_model import AttributionModel
+from .decoder_only import DecoderOnlyAttributionModel
+from .encoder_decoder import EncoderDecoderAttributionModel
+from .huggingface_model import HuggingfaceDecoderOnlyModel, HuggingfaceEncoderDecoderModel, HuggingfaceModel
+
+
+logger = logging.getLogger(__name__)
+
+FRAMEWORKS_MAP = {
+    "hf_transformers": HuggingfaceModel,
+}
+
+
+def load_model(
+    model: Union[ModelIdentifier, ModelClass],
+    attribution_method: Optional[str] = None,
+    framework: str = "hf_transformers",
+    **kwargs,
+) -> AttributionModel:
+    model_name = model if isinstance(model, str) else "model"
+    method_desc = f"with {attribution_method} method..." if attribution_method else " without attribution methods..."
+    load_msg = f"Loading {model_name} {method_desc}"
+    with optional(not isnotebook(), Status(load_msg), logger.info, msg=load_msg):
+        return FRAMEWORKS_MAP[framework].load(model, attribution_method, **kwargs)
+
+
+def list_supported_frameworks() -> List[str]:
+    """
+    Lists identifiers for all available step scores.
+    """
+    return list(FRAMEWORKS_MAP.keys())
 
 
 __all__ = [
     "AttributionModel",
     "HuggingfaceModel",
+    "HuggingfaceEncoderDecoderModel",
+    "HuggingfaceDecoderOnlyModel",
+    "DecoderOnlyAttributionModel",
+    "EncoderDecoderAttributionModel",
     "load_model",
+    "list_supported_frameworks",
 ]
diff --git a/inseq/models/attribution_model.py b/inseq/models/attribution_model.py
index 8788e95d..5ee0179a 100644
--- a/inseq/models/attribution_model.py
+++ b/inseq/models/attribution_model.py
@@ -1,29 +1,40 @@
-from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+from typing import Any, Callable, Dict, List, Optional, Tuple, TypeVar, Union
 
 import logging
-from abc import ABC, abstractmethod, abstractstaticmethod
+from abc import ABC, abstractmethod
 
 import torch
-from rich.status import Status
 
 from ..attr import STEP_SCORES_MAP
-from ..attr.feat.feature_attribution import FeatureAttribution
-from ..data import BatchEncoding, FeatureAttributionOutput
-from ..utils import MissingAttributionMethodError, extract_signature_args, format_input_texts, isnotebook
+from ..attr.feat import FeatureAttribution, extract_args, join_token_ids
+from ..data import (
+    BatchEncoding,
+    DecoderOnlyBatch,
+    EncoderDecoderBatch,
+    FeatureAttributionOutput,
+    FeatureAttributionStepOutput,
+)
+from ..utils import MissingAttributionMethodError, check_device, format_input_texts, get_default_device, isnotebook
 from ..utils.typing import (
     EmbeddingsTensor,
+    ExpandedTargetIdsTensor,
     FullLogitsTensor,
     IdsTensor,
-    ModelIdentifier,
     OneOrMoreIdSequences,
     OneOrMoreTokenSequences,
     SingleScorePerStepTensor,
+    TargetIdsTensor,
     TextInput,
+    TextSequences,
+    TokenWithId,
     VocabularyEmbeddingsTensor,
 )
 from .model_decorators import unhooked
 
 
+ModelOutput = TypeVar("ModelOutput")
+
+
 logger = logging.getLogger(__name__)
 
 
@@ -43,34 +54,33 @@ class AttributionModel(ABC, torch.nn.Module):
         "decoder_attention_mask",
     ]
 
-    def __init__(self, attribution_method: Optional[str] = None, device: str = None, **kwargs) -> None:
+    def __init__(self, **kwargs) -> None:
         super().__init__()
         if not hasattr(self, "model"):
             self.model = None
             self.model_name = None
+            self.is_encoder_decoder = True
+        self.pad_token = None
+        self.embed_scale = None
         self._device = None
         self.attribution_method = None
         self.is_hooked = False
         self._default_attributed_fn_id = "probability"
 
     @property
-    def device(self) -> str:
+    def device(self) -> Optional[str]:
         return self._device
 
     @device.setter
     def device(self, new_device: str) -> None:
-        if "cuda" in new_device and not torch.cuda.is_available():
-            raise torch.cuda.CudaError("Cannot use CUDA device, CUDA is not available.")
+        check_device(new_device)
         self._device = new_device
         if self.model:
             self.model.to(self._device)
 
-    def setup(self, device: str = None, attribution_method: str = None) -> None:
+    def setup(self, device: Optional[str] = None, attribution_method: Optional[str] = None) -> None:
         """Move the model to device and in eval mode."""
-        if device is not None:
-            self.device = device
-        else:
-            self.device = "cuda:0" if torch.cuda.is_available() else "cpu"
+        self.device = device if device is not None else get_default_device()
         if self.model:
             self.model.eval()
             self.model.zero_grad()
@@ -86,13 +96,12 @@ def set_attributed_fn(self, fn: str):
             raise ValueError(f"Unknown function: {fn}. Register custom functions with inseq.register_step_score")
         self._default_attributed_fn_id = fn
 
-    @staticmethod
-    def load(
-        model_name_or_path: ModelIdentifier,
-        attribution_method: Optional[str] = None,
-        **kwargs,
-    ):
-        return load_model(model_name_or_path, attribution_method, **kwargs)
+    @property
+    def info(self) -> Dict[Optional[str], Optional[str]]:
+        return {
+            "model_name": self.model_name,
+            "model_class": self.model.__class__.__name__ if self.model is not None else None,
+        }
 
     def get_attribution_method(
         self,
@@ -128,56 +137,13 @@ def get_attributed_fn(
             attributed_fn = STEP_SCORES_MAP[attributed_fn]
         return attributed_fn
 
-    def extract_args(
-        self,
-        attribution_method: "FeatureAttribution",
-        attributed_fn: Callable[..., SingleScorePerStepTensor],
-        step_scores: List[str],
-        **kwargs,
-    ) -> Tuple[Dict[str, Any], Dict[str, Any]]:
-        attribution_args = kwargs.pop("attribution_args", {})
-        attributed_fn_args = kwargs.pop("attributed_fn_args", {})
-        step_scores_args = kwargs.pop("step_scores_args", {})
-        extra_attribution_args, attribution_unused_args = attribution_method.get_attribution_args(**kwargs)
-        extra_attributed_fn_args, attributed_fn_unused_args = extract_signature_args(
-            kwargs, attributed_fn, exclude_args=self._DEFAULT_ATTRIBUTED_FN_ARGS, return_remaining=True
-        )
-        extra_step_scores_args = {}
-        for step_score in step_scores:
-            if step_score not in STEP_SCORES_MAP:
-                raise AttributeError(
-                    f"Step score {step_score} not found. Available step scores are: "
-                    f"{', '.join([x for x in STEP_SCORES_MAP.keys()])}. Use the inseq.register_step_score"
-                    f"function to register a custom step score."
-                )
-            extra_step_scores_args.update(
-                **extract_signature_args(
-                    kwargs,
-                    STEP_SCORES_MAP[step_score],
-                    exclude_args=self._DEFAULT_ATTRIBUTED_FN_ARGS,
-                    return_remaining=False,
-                )
-            )
-        step_scores_unused_args = {k: v for k, v in kwargs.items() if k not in extra_step_scores_args}
-        unused_args = {
-            k: v
-            for k, v in kwargs.items()
-            if k in attribution_unused_args.keys() & attributed_fn_unused_args.keys() & step_scores_unused_args.keys()
-        }
-        if unused_args:
-            logger.warning(f"Unused arguments during attribution: {unused_args}")
-        attribution_args.update(extra_attribution_args)
-        attributed_fn_args.update(extra_attributed_fn_args)
-        step_scores_args.update(extra_step_scores_args)
-        return attribution_args, attributed_fn_args, step_scores_args
-
     def attribute(
         self,
         input_texts: TextInput,
         generated_texts: Optional[TextInput] = None,
         method: Optional[str] = None,
         override_default_attribution: Optional[bool] = False,
-        attr_pos_start: Optional[int] = 1,
+        attr_pos_start: Optional[int] = None,
         attr_pos_end: Optional[int] = None,
         show_progress: bool = True,
         pretty_progress: bool = True,
@@ -185,7 +151,6 @@ def attribute(
         attribute_target: bool = False,
         step_scores: List[str] = [],
         include_eos_baseline: bool = False,
-        prepend_bos_token: bool = True,
         attributed_fn: Union[str, Callable[..., SingleScorePerStepTensor], None] = None,
         device: Optional[str] = None,
         batch_size: Optional[int] = None,
@@ -194,8 +159,10 @@ def attribute(
         """Perform attribution for one or multiple texts."""
         if not input_texts:
             raise ValueError("At least one text must be provided to perform attribution.")
+        if attribute_target and not self.is_encoder_decoder:
+            logger.warning("attribute_target parameter is set to True, but will be ignored (not an encoder-decoder).")
+        original_device = self.device
         if device is not None:
-            original_device = self.device
             self.device = device
         input_texts, generated_texts = format_input_texts(input_texts, generated_texts)
         if batch_size is not None:
@@ -206,18 +173,39 @@ def attribute(
         # If constrained decoding is not enabled, we need to generate the
         # generated texts from the input texts.
         generation_args = kwargs.pop("generation_args", {})
+        if constrained_decoding and generation_args:
+            logger.warning(
+                f"Generation arguments {generation_args} are provided, but constrained decoding is enabled. "
+                "Generation arguments will be ignored."
+            )
         if not constrained_decoding:
-            input_texts = self.encode(input_texts, return_baseline=True, include_eos_baseline=include_eos_baseline)
-            generated_texts = self.generate(input_texts, return_generation_output=False, **generation_args)
+            encoded_input = self.encode(input_texts, return_baseline=True, include_eos_baseline=include_eos_baseline)
+            generated_texts = self.generate(encoded_input, return_generation_output=False, **generation_args)
         logger.debug(f"reference_texts={generated_texts}")
         attribution_method = self.get_attribution_method(method, override_default_attribution)
         attributed_fn = self.get_attributed_fn(attributed_fn)
-        attribution_args, attributed_fn_args, step_scores_args = self.extract_args(
-            attribution_method, attributed_fn, step_scores, **kwargs
+        attribution_args, attributed_fn_args, step_scores_args = extract_args(
+            attribution_method, attributed_fn, step_scores, default_args=self._DEFAULT_ATTRIBUTED_FN_ARGS, **kwargs
         )
         if isnotebook():
             logger.debug("Pretty progress currently not supported in notebooks, falling back to tqdm.")
             pretty_progress = False
+        if not self.is_encoder_decoder:
+            assert all(
+                generated_texts[idx].startswith(input_texts[idx]) for idx in range(len(input_texts))
+            ), "Forced generations with decoder-only models must start with the input texts."
+            if constrained_decoding and len(input_texts) > 1:
+                logger.info(
+                    "Batched constrained decoding is currently not supported for decoder-only models."
+                    " Using batch size of 1."
+                )
+                batch_size = 1
+            if len(input_texts) > 1 and (attr_pos_start is not None or attr_pos_end is not None):
+                logger.info(
+                    "Custom attribution positions are currently not supported when batching generations for"
+                    " decoder-only models. Using batch size of 1."
+                )
+                batch_size = 1
         attribution_outputs = attribution_method.prepare_and_attribute(
             input_texts,
             generated_texts,
@@ -230,7 +218,6 @@ def attribute(
             attribute_target=attribute_target,
             step_scores=step_scores,
             include_eos_baseline=include_eos_baseline,
-            prepend_bos_token=prepend_bos_token,
             attributed_fn=attributed_fn,
             attribution_args=attribution_args,
             attributed_fn_args=attributed_fn_args,
@@ -243,7 +230,7 @@ def attribute(
         )
         attribution_output.info["generation_args"] = generation_args
         attribution_output.info["constrained_decoding"] = constrained_decoding
-        if device is not None:
+        if device and original_device:
             self.device = original_device
         return attribution_output
 
@@ -253,9 +240,18 @@ def embed(self, inputs: Union[TextInput, IdsTensor], as_targets: bool = False):
         ):
             batch = self.encode(inputs, as_targets)
             inputs = batch.input_ids
-        if as_targets:
-            return self.decoder_embed_ids(inputs)
-        return self.encoder_embed_ids(inputs)
+        return self.embed_ids(inputs, as_targets=as_targets)
+
+    def tokenize_with_ids(
+        self, inputs: TextInput, as_targets: bool = False, skip_special_tokens: bool = True
+    ) -> List[List[TokenWithId]]:
+        tokenized_sentences = self.convert_string_to_tokens(
+            inputs, as_targets=as_targets, skip_special_tokens=skip_special_tokens
+        )
+        ids_sentences = self.convert_tokens_to_ids(tokenized_sentences)
+        return join_token_ids(tokenized_sentences, ids_sentences)
+
+    # Framework-specific methods
 
     @unhooked
     @abstractmethod
@@ -267,20 +263,23 @@ def generate(
     ) -> Union[List[str], Tuple[List[str], Any]]:
         pass
 
-    @abstractstaticmethod
-    def output2logits(forward_output) -> FullLogitsTensor:
-        pass
-
+    @staticmethod
     @abstractmethod
-    def encode(self, texts: TextInput, as_targets: Optional[bool] = False, *args) -> BatchEncoding:
+    def output2logits(forward_output) -> FullLogitsTensor:
         pass
 
     @abstractmethod
-    def encoder_embed_ids(self, ids: IdsTensor) -> EmbeddingsTensor:
+    def encode(
+        self,
+        texts: TextInput,
+        as_targets: bool = False,
+        return_baseline: bool = False,
+        include_eos_baseline: bool = False,
+    ) -> BatchEncoding:
         pass
 
     @abstractmethod
-    def decoder_embed_ids(self, ids: IdsTensor) -> EmbeddingsTensor:
+    def embed_ids(self, ids: IdsTensor, as_targets: bool = False) -> EmbeddingsTensor:
         pass
 
     @abstractmethod
@@ -301,16 +300,21 @@ def convert_tokens_to_string(
         self,
         tokens: OneOrMoreTokenSequences,
         skip_special_tokens: Optional[bool] = True,
+        as_targets: bool = False,
     ) -> TextInput:
         pass
 
     @abstractmethod
     def convert_string_to_tokens(
-        self, text: TextInput, skip_special_tokens: Optional[bool] = True
+        self,
+        text: TextInput,
+        skip_special_tokens: bool = True,
+        as_targets: bool = False,
     ) -> OneOrMoreTokenSequences:
         pass
 
     @property
+    @abstractmethod
     def special_tokens(self) -> List[str]:
         pass
 
@@ -347,21 +351,78 @@ def remove_interpretable_embeddings(self, **kwargs) -> None:
         """
         pass
 
+    # Architecture-specific methods
+
+    @abstractmethod
+    def prepare_inputs_for_attribution(
+        self,
+        inputs: Any,
+        include_eos_baseline: bool = False,
+        use_layer_attribution: bool = False,
+    ) -> Union[DecoderOnlyBatch, EncoderDecoderBatch]:
+        pass
+
+    @staticmethod
+    @abstractmethod
+    def format_forward_args(
+        inputs: Union[DecoderOnlyBatch, EncoderDecoderBatch],
+    ) -> Dict[str, Any]:
+        pass
+
+    @staticmethod
+    @abstractmethod
+    def format_attribution_args(
+        batch: Union[DecoderOnlyBatch, EncoderDecoderBatch],
+        target_ids: TargetIdsTensor,
+        attributed_fn: Callable[..., SingleScorePerStepTensor],
+        attributed_fn_args: Dict[str, Any] = {},
+        is_layer_attribution: bool = False,
+        **kwargs,
+    ) -> Tuple[Dict[str, Any], Tuple[Union[IdsTensor, EmbeddingsTensor, None], ...]]:
+        pass
+
+    @abstractmethod
+    def get_text_sequences(self, batch: Union[DecoderOnlyBatch, EncoderDecoderBatch]) -> TextSequences:
+        pass
+
+    @abstractmethod
+    def get_forward_output(
+        self,
+        **kwargs,
+    ) -> ModelOutput:
+        pass
+
+    @staticmethod
+    @abstractmethod
+    def enrich_step_output(
+        step_output: FeatureAttributionStepOutput,
+        batch: EncoderDecoderBatch,
+        target_tokens: OneOrMoreTokenSequences,
+        target_ids: TargetIdsTensor,
+    ) -> FeatureAttributionStepOutput:
+        pass
+
+    @abstractmethod
+    def format_step_function_args(
+        self,
+        forward_output: ModelOutput,
+        target_ids: ExpandedTargetIdsTensor,
+        encoder_input_ids: Optional[IdsTensor] = None,
+        decoder_input_ids: Optional[IdsTensor] = None,
+        encoder_input_embeds: Optional[EmbeddingsTensor] = None,
+        decoder_input_embeds: Optional[EmbeddingsTensor] = None,
+        encoder_attention_mask: Optional[IdsTensor] = None,
+        decoder_attention_mask: Optional[IdsTensor] = None,
+        **kwargs,
+    ) -> Dict[str, Any]:
+        pass
 
-def load_model(
-    model_name_or_path: ModelIdentifier,
-    attribution_method: Optional[str] = None,
-    **kwargs,
-):
-    from .huggingface_model import HuggingfaceModel
-
-    from_hf = kwargs.pop("from_hf", None)
-    desc_id = ", ".join(model_name_or_path) if isinstance(model_name_or_path, tuple) else model_name_or_path
-    desc = f"Loading {desc_id}" + (
-        f" with {attribution_method} method..." if attribution_method else " without methods..."
-    )
-    with Status(desc):
-        if from_hf:
-            return HuggingfaceModel(model_name_or_path, attribution_method, **kwargs)
-        else:  # Default behavior is using Huggingface
-            return HuggingfaceModel(model_name_or_path, attribution_method, **kwargs)
+    @abstractmethod
+    def forward(
+        self,
+        attributed_fn: Callable[..., SingleScorePerStepTensor],
+        attributed_fn_argnames: Optional[List[str]] = None,
+        *args,
+        **kwargs,
+    ) -> FullLogitsTensor:
+        pass
diff --git a/inseq/models/decoder_only.py b/inseq/models/decoder_only.py
new file mode 100644
index 00000000..a7013a19
--- /dev/null
+++ b/inseq/models/decoder_only.py
@@ -0,0 +1,213 @@
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+
+import logging
+
+from ..attr.feat import join_token_ids
+from ..data import (
+    Batch,
+    BatchEmbedding,
+    BatchEncoding,
+    DecoderOnlyBatch,
+    FeatureAttributionInput,
+    FeatureAttributionStepOutput,
+)
+from ..utils import pretty_tensor
+from ..utils.typing import (
+    AttributionForwardInputs,
+    EmbeddingsTensor,
+    ExpandedTargetIdsTensor,
+    FullLogitsTensor,
+    IdsTensor,
+    OneOrMoreTokenSequences,
+    SingleScorePerStepTensor,
+    TargetIdsTensor,
+    TextSequences,
+    TokenWithId,
+)
+from .attribution_model import AttributionModel, ModelOutput
+
+
+logger = logging.getLogger(__name__)
+
+
+class DecoderOnlyAttributionModel(AttributionModel):
+    """AttributionModel class for attributing encoder-decoder models."""
+
+    def prepare_inputs_for_attribution(
+        self,
+        inputs: FeatureAttributionInput,
+        include_eos_baseline: bool = False,
+        use_layer_attribution: bool = False,
+    ) -> DecoderOnlyBatch:
+        if isinstance(inputs, Batch):
+            batch = inputs
+        else:
+            if isinstance(inputs, str) or isinstance(inputs, list):
+                # Decoder-only model do not tokenize as targets,
+                # since a single tokenizer is available.
+                encodings: BatchEncoding = self.encode(
+                    inputs,
+                    return_baseline=True,
+                    include_eos_baseline=include_eos_baseline,
+                )
+            elif isinstance(inputs, BatchEncoding):
+                encodings = inputs
+            else:
+                raise ValueError(
+                    f"targets must be either a string, a list of strings, a BatchEncoding or a Batch, "
+                    f"not {type(inputs)}"
+                )
+            baseline_embeds = None
+            if not use_layer_attribution:
+                baseline_embeds = self.embed(encodings.baseline_ids)
+            embeddings = BatchEmbedding(
+                input_embeds=self.embed(encodings.input_ids),
+                baseline_embeds=baseline_embeds,
+            )
+            batch = DecoderOnlyBatch(encodings, embeddings)
+        return batch
+
+    @staticmethod
+    def format_forward_args(
+        inputs: DecoderOnlyBatch,
+    ) -> Dict[str, Any]:
+        return {"forward_tensor": inputs.input_embeds, "attention_mask": inputs.attention_mask}
+
+    @staticmethod
+    def format_attribution_args(
+        batch: DecoderOnlyBatch,
+        target_ids: TargetIdsTensor,
+        attributed_fn: Callable[..., SingleScorePerStepTensor],
+        attributed_fn_args: Dict[str, Any] = {},
+        is_layer_attribution: bool = False,
+        **kwargs,
+    ) -> Tuple[Dict[str, Any], Tuple[Union[IdsTensor, EmbeddingsTensor, None], ...]]:
+        if is_layer_attribution:
+            inputs = (batch.input_ids,)
+            baselines = (batch.baseline_ids,)
+        else:
+            inputs = (batch.input_embeds,)
+            baselines = (batch.baseline_embeds,)
+        attribute_fn_args = {
+            "inputs": inputs,
+            "additional_forward_args": (
+                # Ids are always explicitly passed as extra arguments to enable
+                # usage in custom attribution functions.
+                batch.input_ids,
+                # Making targets 2D enables _expand_additional_forward_args
+                # in Captum to preserve the expected batch dimension for methods
+                # such as intergrated gradients.
+                target_ids.unsqueeze(-1),
+                attributed_fn,
+                batch.attention_mask,
+                # Defines how to treat source and target tensors
+                # Maps on the use_embeddings argument of forward
+                not is_layer_attribution,
+                list(attributed_fn_args.keys()),
+            )
+            + tuple(attributed_fn_args.values()),
+        }
+        return attribute_fn_args, baselines
+
+    def get_text_sequences(self, batch: DecoderOnlyBatch) -> TextSequences:
+        return TextSequences(
+            sources=None,
+            targets=self.convert_tokens_to_string(batch.input_tokens, as_targets=True),
+        )
+
+    @staticmethod
+    def enrich_step_output(
+        step_output: FeatureAttributionStepOutput,
+        batch: DecoderOnlyBatch,
+        target_tokens: OneOrMoreTokenSequences,
+        target_ids: TargetIdsTensor,
+    ) -> FeatureAttributionStepOutput:
+        r"""
+        Enriches the attribution output with token information, producing the finished
+        :class:`~inseq.data.FeatureAttributionStepOutput` object.
+
+        Args:
+            step_output (:class:`~inseq.data.FeatureAttributionStepOutput`): The output produced
+                by the attribution step, with missing batch information.
+            batch (:class:`~inseq.data.DecoderOnlyBatch`): The batch on which attribution was performed.
+            target_ids (:obj:`torch.Tensor`): Target token ids of size `(batch_size, 1)` corresponding to tokens
+                for which the attribution step was performed.
+
+        Returns:
+            :class:`~inseq.data.FeatureAttributionStepOutput`: The enriched attribution output.
+        """
+        if len(target_ids.shape) == 0:
+            target_ids = target_ids.unsqueeze(0)
+        step_output.source = None
+        step_output.target = [[TokenWithId(token[0], id)] for token, id in zip(target_tokens, target_ids.tolist())]
+        step_output.prefix = join_token_ids(batch.target_tokens, batch.input_ids.tolist())
+        return step_output
+
+    def format_step_function_args(
+        self,
+        forward_output: ModelOutput,
+        target_ids: ExpandedTargetIdsTensor,
+        decoder_input_ids: Optional[IdsTensor] = None,
+        decoder_input_embeds: Optional[EmbeddingsTensor] = None,
+        decoder_attention_mask: Optional[IdsTensor] = None,
+        **kwargs,
+    ) -> Dict[str, Any]:
+        return {
+            **kwargs,
+            **{
+                "attribution_model": self,
+                "forward_output": forward_output,
+                "encoder_input_ids": None,
+                "decoder_input_ids": decoder_input_ids,
+                "encoder_input_embeds": None,
+                "decoder_input_embeds": decoder_input_embeds,
+                "target_ids": target_ids,
+                "encoder_attention_mask": None,
+                "decoder_attention_mask": decoder_attention_mask,
+                **kwargs,
+            },
+        }
+
+    def get_forward_output(
+        self,
+        forward_tensor: AttributionForwardInputs,
+        attention_mask: Optional[IdsTensor] = None,
+        use_embeddings: bool = True,
+    ) -> ModelOutput:
+        embeds = forward_tensor if use_embeddings else None
+        ids = None if use_embeddings else forward_tensor
+        return self.model(
+            input_ids=ids,
+            inputs_embeds=embeds,
+            attention_mask=attention_mask,
+        )
+
+    def forward(
+        self,
+        forward_tensor: AttributionForwardInputs,
+        input_ids: IdsTensor,
+        target_ids: ExpandedTargetIdsTensor,
+        attributed_fn: Callable[..., SingleScorePerStepTensor],
+        attention_mask: Optional[IdsTensor] = None,
+        use_embeddings: bool = True,
+        attributed_fn_argnames: Optional[List[str]] = None,
+        *args,
+    ) -> FullLogitsTensor:
+        assert len(args) == len(attributed_fn_argnames), "Number of arguments and number of argnames must match"
+        target_ids = target_ids.squeeze(-1)
+        output = self.get_forward_output(
+            forward_tensor=forward_tensor,
+            attention_mask=attention_mask,
+            use_embeddings=use_embeddings,
+        )
+        logger.debug(f"logits: {pretty_tensor(output.logits)}")
+        step_function_args = self.format_step_function_args(
+            attribution_model=self,
+            forward_output=output,
+            decoder_input_ids=input_ids,
+            decoder_input_embeds=forward_tensor if use_embeddings else None,
+            target_ids=target_ids,
+            decoder_attention_mask=attention_mask,
+            **{k: v for k, v in zip(attributed_fn_argnames, args) if v is not None},
+        )
+        return attributed_fn(**step_function_args)
diff --git a/inseq/models/encoder_decoder.py b/inseq/models/encoder_decoder.py
new file mode 100644
index 00000000..05f1048f
--- /dev/null
+++ b/inseq/models/encoder_decoder.py
@@ -0,0 +1,294 @@
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+
+import logging
+
+from ..attr.feat import join_token_ids
+from ..data import (
+    Batch,
+    BatchEmbedding,
+    BatchEncoding,
+    EncoderDecoderBatch,
+    FeatureAttributionInput,
+    FeatureAttributionStepOutput,
+)
+from ..utils import pretty_tensor
+from ..utils.typing import (
+    AttributionForwardInputs,
+    EmbeddingsTensor,
+    ExpandedTargetIdsTensor,
+    FullLogitsTensor,
+    IdsTensor,
+    OneOrMoreTokenSequences,
+    SingleScorePerStepTensor,
+    TargetIdsTensor,
+    TextSequences,
+    TokenWithId,
+)
+from .attribution_model import AttributionModel, ModelOutput
+
+
+logger = logging.getLogger(__name__)
+
+
+class EncoderDecoderAttributionModel(AttributionModel):
+    """AttributionModel class for attributing encoder-decoder models."""
+
+    def prepare_inputs_for_attribution(
+        self,
+        inputs: Tuple[FeatureAttributionInput, FeatureAttributionInput],
+        include_eos_baseline: bool = False,
+        use_layer_attribution: bool = False,
+    ) -> EncoderDecoderBatch:
+        r"""
+        Prepares sources and target to produce an :class:`~inseq.data.EncoderDecoderBatch`.
+        There are two stages of preparation:
+
+            1. Raw text sources and target texts are encoded by the model.
+            2. The encoded sources and targets are converted to tensors for the forward pass.
+
+        This method is agnostic of the preparation stage of sources and targets. If they are both
+        raw text, they will undergo both steps. If they are already encoded, they will only be embedded.
+        If the feature attribution method works on layers, the embedding step is skipped and embeddings are
+        set to None.
+        The final result will be consistent in both cases.
+
+        Args:
+            sources (:obj:`FeatureAttributionInput`): The sources provided to the
+                :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
+            targets (:obj:`FeatureAttributionInput): The targets provided to the
+                :meth:`~inseq.attr.feat.FeatureAttribution.prepare` method.
+            include_eos_baseline (:obj:`bool`, `optional`): Whether to include the EOS token in the baseline for
+                attribution. By default the EOS token is not used for attribution. Defaults to False.
+
+        Returns:
+            :obj:`EncoderDecoderBatch`: An :class:`~inseq.data.EncoderDecoderBatch` object containing sources
+                and targets in encoded and embedded formats for all inputs.
+        """
+        sources, targets = inputs
+        if isinstance(sources, Batch):
+            source_batch = sources
+        else:
+            if isinstance(sources, str) or isinstance(sources, list):
+                source_encodings: BatchEncoding = self.encode(
+                    sources, return_baseline=True, include_eos_baseline=include_eos_baseline
+                )
+            elif isinstance(sources, BatchEncoding):
+                source_encodings = sources
+            else:
+                raise ValueError(
+                    f"sources must be either a string, a list of strings, a BatchEncoding or a Batch, "
+                    f"not {type(sources)}"
+                )
+            # Even when we are performing layer attribution, we might need the embeddings
+            # to compute step probabilities.
+            source_embeddings = BatchEmbedding(
+                input_embeds=self.embed(source_encodings.input_ids),
+                baseline_embeds=self.embed(source_encodings.baseline_ids),
+            )
+            source_batch = Batch(source_encodings, source_embeddings)
+
+        if isinstance(targets, Batch):
+            target_batch = targets
+        else:
+            if isinstance(targets, str) or isinstance(targets, list):
+                target_encodings: BatchEncoding = self.encode(
+                    targets,
+                    as_targets=True,
+                    return_baseline=True,
+                    include_eos_baseline=include_eos_baseline,
+                )
+            elif isinstance(targets, BatchEncoding):
+                target_encodings = targets
+            else:
+                raise ValueError(
+                    f"targets must be either a string, a list of strings, a BatchEncoding or a Batch, "
+                    f"not {type(targets)}"
+                )
+            baseline_embeds = None
+            if not use_layer_attribution:
+                baseline_embeds = self.embed(target_encodings.baseline_ids, as_targets=True)
+            target_embeddings = BatchEmbedding(
+                input_embeds=self.embed(target_encodings.input_ids, as_targets=True),
+                baseline_embeds=baseline_embeds,
+            )
+            target_batch = Batch(target_encodings, target_embeddings)
+        return EncoderDecoderBatch(source_batch, target_batch)
+
+    @staticmethod
+    def format_forward_args(
+        inputs: EncoderDecoderBatch,
+    ) -> Dict[str, Any]:
+        return {
+            "forward_tensor": inputs.sources.input_embeds,
+            "decoder_input_embeds": inputs.targets.input_embeds,
+            "encoder_attention_mask": inputs.sources.attention_mask,
+            "decoder_attention_mask": inputs.targets.attention_mask,
+        }
+
+    @staticmethod
+    def format_attribution_args(
+        batch: EncoderDecoderBatch,
+        target_ids: TargetIdsTensor,
+        attributed_fn: Callable[..., SingleScorePerStepTensor],
+        attribute_target: bool = False,
+        attributed_fn_args: Dict[str, Any] = {},
+        is_layer_attribution: bool = False,
+        **kwargs,
+    ) -> Tuple[Dict[str, Any], Tuple[Union[IdsTensor, EmbeddingsTensor, None], ...]]:
+        if is_layer_attribution:
+            inputs = (batch.sources.input_ids,)
+            baselines = (batch.sources.baseline_ids,)
+        else:
+            inputs = (batch.sources.input_embeds,)
+            baselines = (batch.sources.baseline_embeds,)
+        if attribute_target:
+            inputs = inputs + (batch.targets.input_embeds,)
+            baselines = baselines + (batch.targets.baseline_embeds,)
+        attribute_fn_args = {
+            "inputs": inputs,
+            "additional_forward_args": (
+                # Ids are always explicitly passed as extra arguments to enable
+                # usage in custom attribution functions.
+                batch.sources.input_ids,
+                batch.targets.input_ids,
+                # Making targets 2D enables _expand_additional_forward_args
+                # in Captum to preserve the expected batch dimension for methods
+                # such as intergrated gradients.
+                target_ids.unsqueeze(-1),
+                attributed_fn,
+                batch.sources.attention_mask,
+                batch.targets.attention_mask,
+                # Defines how to treat source and target tensors
+                # Maps on the use_embeddings argument of forward
+                not is_layer_attribution,
+                list(attributed_fn_args.keys()),
+            )
+            + tuple(attributed_fn_args.values()),
+        }
+        if not attribute_target:
+            attribute_fn_args["additional_forward_args"] = (batch.targets.input_embeds,) + attribute_fn_args[
+                "additional_forward_args"
+            ]
+        return attribute_fn_args, baselines
+
+    def get_text_sequences(self, batch: EncoderDecoderBatch) -> TextSequences:
+        return TextSequences(
+            sources=self.convert_tokens_to_string(batch.sources.input_tokens),
+            targets=self.convert_tokens_to_string(batch.targets.input_tokens, as_targets=True),
+        )
+
+    @staticmethod
+    def enrich_step_output(
+        step_output: FeatureAttributionStepOutput,
+        batch: EncoderDecoderBatch,
+        target_tokens: OneOrMoreTokenSequences,
+        target_ids: TargetIdsTensor,
+    ) -> FeatureAttributionStepOutput:
+        r"""
+        Enriches the attribution output with token information, producing the finished
+        :class:`~inseq.data.FeatureAttributionStepOutput` object.
+
+        Args:
+            step_output (:class:`~inseq.data.FeatureAttributionStepOutput`): The output produced
+                by the attribution step, with missing batch information.
+            batch (:class:`~inseq.data.EncoderDecoderBatch`): The batch on which attribution was performed.
+            target_ids (:obj:`torch.Tensor`): Target token ids of size `(batch_size, 1)` corresponding to tokens
+                for which the attribution step was performed.
+
+        Returns:
+            :class:`~inseq.data.FeatureAttributionStepOutput`: The enriched attribution output.
+        """
+        if len(target_ids.shape) == 0:
+            target_ids = target_ids.unsqueeze(0)
+        step_output.source = join_token_ids(batch.sources.input_tokens, batch.sources.input_ids.tolist())
+        step_output.target = [[TokenWithId(token[0], id)] for token, id in zip(target_tokens, target_ids.tolist())]
+        step_output.prefix = join_token_ids(batch.targets.input_tokens, batch.targets.input_ids.tolist())
+        return step_output
+
+    def format_step_function_args(
+        self,
+        forward_output: ModelOutput,
+        target_ids: ExpandedTargetIdsTensor,
+        encoder_input_ids: Optional[IdsTensor] = None,
+        decoder_input_ids: Optional[IdsTensor] = None,
+        encoder_input_embeds: Optional[EmbeddingsTensor] = None,
+        decoder_input_embeds: Optional[EmbeddingsTensor] = None,
+        encoder_attention_mask: Optional[IdsTensor] = None,
+        decoder_attention_mask: Optional[IdsTensor] = None,
+        **kwargs,
+    ) -> Dict[str, Any]:
+        return {
+            **kwargs,
+            **{
+                "attribution_model": self,
+                "forward_output": forward_output,
+                "encoder_input_ids": encoder_input_ids,
+                "decoder_input_ids": decoder_input_ids,
+                "encoder_input_embeds": encoder_input_embeds,
+                "decoder_input_embeds": decoder_input_embeds,
+                "target_ids": target_ids,
+                "encoder_attention_mask": encoder_attention_mask,
+                "decoder_attention_mask": decoder_attention_mask,
+            },
+        }
+
+    def get_forward_output(
+        self,
+        forward_tensor: AttributionForwardInputs,
+        encoder_attention_mask: Optional[IdsTensor] = None,
+        # decoder_input_ids: Optional[IdsTensor] = None,
+        decoder_input_embeds: Optional[EmbeddingsTensor] = None,
+        decoder_attention_mask: Optional[IdsTensor] = None,
+        use_embeddings: bool = True,
+    ) -> ModelOutput:
+        encoder_embeds = forward_tensor if use_embeddings else None
+        encoder_ids = None if use_embeddings else forward_tensor
+        # decoder_embeds = decoder_input_embeds if decoder_input_ids is None else None
+        # decoder_ids = decoder_input_ids if decoder_input_ids is not None else None
+        return self.model(
+            input_ids=encoder_ids,
+            inputs_embeds=encoder_embeds,
+            attention_mask=encoder_attention_mask,
+            # decoder_input_ids=decoder_input_ids,
+            decoder_inputs_embeds=decoder_input_embeds,
+            decoder_attention_mask=decoder_attention_mask,
+        )
+
+    def forward(
+        self,
+        encoder_tensors: AttributionForwardInputs,
+        decoder_input_embeds: AttributionForwardInputs,
+        encoder_input_ids: IdsTensor,
+        decoder_input_ids: IdsTensor,
+        target_ids: ExpandedTargetIdsTensor,
+        attributed_fn: Callable[..., SingleScorePerStepTensor],
+        encoder_attention_mask: Optional[IdsTensor] = None,
+        decoder_attention_mask: Optional[IdsTensor] = None,
+        use_embeddings: bool = True,
+        attributed_fn_argnames: Optional[List[str]] = None,
+        *args,
+    ) -> FullLogitsTensor:
+        assert len(args) == len(attributed_fn_argnames), "Number of arguments and number of argnames must match"
+        target_ids = target_ids.squeeze(-1)
+        output = self.get_forward_output(
+            forward_tensor=encoder_tensors,
+            encoder_attention_mask=encoder_attention_mask,
+            # decoder_input_ids=decoder_input_ids,
+            decoder_input_embeds=decoder_input_embeds,
+            decoder_attention_mask=decoder_attention_mask,
+            use_embeddings=use_embeddings,
+        )
+        logger.debug(f"logits: {pretty_tensor(output.logits)}")
+        step_function_args = self.format_step_function_args(
+            attribution_model=self,
+            forward_output=output,
+            encoder_input_ids=encoder_input_ids,
+            decoder_input_ids=decoder_input_ids,
+            encoder_input_embeds=encoder_tensors if use_embeddings else None,
+            decoder_input_embeds=decoder_input_embeds,
+            target_ids=target_ids,
+            encoder_attention_mask=encoder_attention_mask,
+            decoder_attention_mask=decoder_attention_mask,
+            **{k: v for k, v in zip(attributed_fn_argnames, args) if v is not None},
+        )
+        return attributed_fn(**step_function_args)
diff --git a/inseq/models/huggingface_model.py b/inseq/models/huggingface_model.py
index 55ece6b0..8e9ce5e8 100644
--- a/inseq/models/huggingface_model.py
+++ b/inseq/models/huggingface_model.py
@@ -1,192 +1,211 @@
 """ HuggingFace Seq2seq model """
-from typing import Callable, List, NoReturn, Optional, Tuple, Union
+from typing import Dict, List, NoReturn, Optional, Tuple, Union
 
 import logging
+from abc import abstractmethod
 
 import torch
 from torch import long
-from transformers import AutoModelForSeq2SeqLM, AutoTokenizer
-from transformers.generation_utils import BeamSampleOutput, BeamSearchOutput, GreedySearchOutput, SampleOutput
-from transformers.modeling_outputs import Seq2SeqLMOutput
+from transformers import (
+    AutoConfig,
+    AutoModelForCausalLM,
+    AutoModelForSeq2SeqLM,
+    AutoTokenizer,
+    PreTrainedModel,
+    PreTrainedTokenizer,
+)
+from transformers.modeling_outputs import CausalLMOutput, ModelOutput, Seq2SeqLMOutput
 
 from ..data import BatchEncoding
-from ..utils import optional, pretty_tensor
 from ..utils.typing import (
-    AttributionForwardInputs,
     EmbeddingsTensor,
-    ExpandedTargetIdsTensor,
     FullLogitsTensor,
     IdsTensor,
     OneOrMoreIdSequences,
     OneOrMoreTokenSequences,
-    SingleScorePerStepTensor,
     TextInput,
     VocabularyEmbeddingsTensor,
 )
 from .attribution_model import AttributionModel
+from .decoder_only import DecoderOnlyAttributionModel
+from .encoder_decoder import EncoderDecoderAttributionModel
 from .model_decorators import unhooked
 
 
 logger = logging.getLogger(__name__)
 logging.getLogger("urllib3").setLevel(logging.WARNING)
 
-GenerationOutput = Union[
-    GreedySearchOutput,
-    SampleOutput,
-    BeamSearchOutput,
-    BeamSampleOutput,
-    torch.LongTensor,
-]
+# Update if other model types are added
+SUPPORTED_AUTOCLASSES = [AutoModelForSeq2SeqLM, AutoModelForCausalLM]
 
 
 class HuggingfaceModel(AttributionModel):
-    """Performs  attribution for any seq2seq model in the HuggingFace Hub.
+    """Model wrapper for any ForCausalLM and ForConditionalGeneration model on the HuggingFace Hub used to enable
+    feature attribution. Corresponds to AutoModelForCausalLM and AutoModelForSeq2SeqLM auto classes.
 
     Attributes:
-        model (AutoModelForSeq2SeqLM): the seq2seq model on which
-            attribution is performed.
+        _autoclass (:obj:`Type[transformers.AutoModel`]): The HuggingFace model class to use for initialization.
+            Must be defined in subclasses.
+        model (:obj:`transformers.AutoModelForSeq2SeqLM` or :obj:`transformers.AutoModelForSeq2SeqLM`):
+            the model on which attribution is performed.
         tokenizer (AutoTokenizer): the tokenizer associated to the model.
         device (str): the device on which the model is run (CPU or GPU).
-        pad_id (int): the id of the pad token.
-        eos_id (int): the id of the end of sequence token.
-        bos_id (int): the id of the beginning of sequence token.
-        encoder_int_embeds (InterpretableEmbeddingBase): the interpretable embedding
-            layer for the encoder.
-        decoder_int_embeds (InterpretableEmbeddingBase): the interpretable embedding
-            layer for the decoder.
-        encoder_embed_scale (float, optional): scale factor for encoder embeddings.
-        decoder_embed_scale (float, optional): scale factor for decoder embeddings.
+        encoder_int_embeds (InterpretableEmbeddingBase): the interpretable embedding layer for the encoder, used for
+            layer attribution methods in Captum.
+        decoder_int_embeds (InterpretableEmbeddingBase): the interpretable embedding layer for the decoder, used for
+            layer attribution methods in Captum.
+        embed_scale (float, optional): scale factor for embeddings.
     """
 
+    _autoclass = None
+
     def __init__(
         self,
-        model_name_or_path: str,
+        model: Union[str, PreTrainedModel],
         attribution_method: Optional[str] = None,
-        tokenizer_name_or_path: Optional[str] = None,
-        device: str = None,
+        tokenizer: Union[str, PreTrainedTokenizer, None] = None,
+        device: Optional[str] = None,
+        model_max_length: Optional[int] = 512,
         **kwargs,
-    ) -> NoReturn:
+    ) -> None:
         """
-        Initialize the AttributionModel with a Huggingface-compatible seq2seq model.
+        Initialize the AttributionModel with a Huggingface-compatible model.
         Performs the setup for model and embeddings.
 
         Args:
-            model_name_or_path (str): the name of the model in the
+            model (:obj:`str` or :obj:`transformers.PreTrainedModel`): the name of the model in the
                 Huggingface Hub or path to folder containing local model files.
-            tokenizer_name_or_path (str, optional): the name of the tokenizer in the
-                Huggingface Hub or path to folder containing local tokenizer files.
-                Default: use model_name_or_path value.
+            tokenizer (:obj:`str` or :obj:`transformers.PreTrainedTokenizerBase`, optional): the name of the tokenizer
+                in the Huggingface Hub or path to folder containing local tokenizer files.
+                Default: use model name.
             attribution_method (str, optional): The attribution method to use.
                 Passing it here reduces overhead on attribute call, since it is already
                 initialized.
+            model_max_length (int, optional): The maximum length of the model. If not provided, will be inferred from
+                the model config.
             **kwargs: additional arguments for the model and the tokenizer.
         """
-        super().__init__(attribution_method, **kwargs)
-        if not tokenizer_name_or_path:
-            tokenizer_name_or_path = model_name_or_path
+        super().__init__(**kwargs)
+        if self._autoclass is None or self._autoclass not in SUPPORTED_AUTOCLASSES:
+            raise ValueError(
+                f"Invalid autoclass {self._autoclass}. Must be one of {[x.__name__ for x in SUPPORTED_AUTOCLASSES]}."
+            )
         model_args = kwargs.pop("model_args", {})
         model_kwargs = kwargs.pop("model_kwargs", {})
+        if isinstance(model, PreTrainedModel):
+            self.model = model
+        else:
+            self.model = self._autoclass.from_pretrained(model, *model_args, **model_kwargs)
+        self.model_name = self.model.config.name_or_path
+        self.tokenizer_name = tokenizer if isinstance(tokenizer, str) else None
+        if tokenizer is None:
+            tokenizer = model if isinstance(model, str) else self.model_name
+            if not tokenizer:
+                raise ValueError(
+                    "Unspecified tokenizer for model loaded from scratch. Use explicit identifier as tokenizer=<ID>"
+                    "during model loading."
+                )
         tokenizer_inputs = kwargs.pop("tokenizer_inputs", {})
         tokenizer_kwargs = kwargs.pop("tokenizer_kwargs", {})
-        self.model = AutoModelForSeq2SeqLM.from_pretrained(model_name_or_path, *model_args, **model_kwargs)
-        self.tokenizer = AutoTokenizer.from_pretrained(tokenizer_name_or_path, *tokenizer_inputs, **tokenizer_kwargs)
-        self.model_name = self.model.config.name_or_path
-        self.tokenizer_name = tokenizer_name_or_path
-        self.pad_id = self.model.config.pad_token_id
-        self.unk_id = self.tokenizer.unk_token_id
-        self.eos_id = self.model.config.eos_token_id
-        self.bos_id = self.model.config.decoder_start_token_id
-        self.unk_token = self.tokenizer.unk_token
-        self.pad_token = self.tokenizer.convert_ids_to_tokens(self.pad_id)
-        self.eos_token = self.tokenizer.convert_ids_to_tokens(self.eos_id)
-        self.bos_token = self.tokenizer.convert_ids_to_tokens(self.bos_id)
-        self.encoder_embed_scale = 1.0
-        self.decoder_embed_scale = 1.0
+        if isinstance(tokenizer, PreTrainedTokenizer):
+            self.tokenizer = tokenizer
+        else:
+            self.tokenizer = AutoTokenizer.from_pretrained(
+                tokenizer, *tokenizer_inputs, model_max_length=model_max_length, **tokenizer_kwargs
+            )
+        if self.model.config.pad_token_id is not None:
+            self.pad_token = self.tokenizer.convert_ids_to_tokens(self.model.config.pad_token_id)
+            self.tokenizer.pad_token = self.pad_token
+        self.eos_token_id = getattr(self.model.config, "eos_token_id", None)
+        if self.eos_token_id is None:
+            self.eos_token_id = self.tokenizer.pad_token_id
+        if self.tokenizer.unk_token_id is None:
+            self.tokenizer.unk_token_id = self.tokenizer.pad_token_id
+        self.embed_scale = 1.0
+        self.model_max_length = model_max_length
         self.encoder_int_embeds = None
         self.decoder_int_embeds = None
+        self.is_encoder_decoder = self.model.config.is_encoder_decoder
         self.configure_embeddings_scale()
         self.setup(device, attribution_method, **kwargs)
 
-    @classmethod
-    def load(cls, model_name_or_path: str, **kwargs):
-        return HuggingfaceModel(model_name_or_path, **kwargs)
+    @staticmethod
+    def load(
+        model: Union[str, PreTrainedModel],
+        attribution_method: Optional[str] = None,
+        tokenizer: Union[str, PreTrainedTokenizer, None] = None,
+        device: str = None,
+        **kwargs,
+    ) -> "HuggingfaceModel":
+        """Loads a HuggingFace model and tokenizer and wraps them in the appropriate AttributionModel."""
+        if isinstance(model, str):
+            is_encoder_decoder = AutoConfig.from_pretrained(model).is_encoder_decoder
+        else:
+            is_encoder_decoder = model.config.is_encoder_decoder
+        if is_encoder_decoder:
+            return HuggingfaceEncoderDecoderModel(model, attribution_method, tokenizer, device, **kwargs)
+        else:
+            return HuggingfaceDecoderOnlyModel(model, attribution_method, tokenizer, device, **kwargs)
 
-    def configure_embeddings_scale(self):
-        encoder = self.model.get_encoder()
-        decoder = self.model.get_decoder()
-        if hasattr(encoder, "embed_scale"):
-            self.encoder_embed_scale = encoder.embed_scale
-        if hasattr(decoder, "embed_scale"):
-            self.decoder_embed_scale = decoder.embed_scale
+    @abstractmethod
+    def configure_embeddings_scale(self) -> None:
+        """Configure the scale factor for embeddings."""
+        pass
 
-    def forward(
-        self,
-        encoder_tensors: AttributionForwardInputs,
-        decoder_input_embeds: AttributionForwardInputs,
-        encoder_input_ids: IdsTensor,
-        decoder_input_ids: IdsTensor,
-        target_ids: ExpandedTargetIdsTensor,
-        attributed_fn: Callable[..., SingleScorePerStepTensor],
-        encoder_attention_mask: Optional[IdsTensor] = None,
-        decoder_attention_mask: Optional[IdsTensor] = None,
-        use_embeddings: bool = True,
-        attributed_fn_argnames: Optional[List[str]] = None,
-        *args,
-    ) -> FullLogitsTensor:
-        assert len(args) == len(attributed_fn_argnames), "Number of arguments and number of argnames must match"
-        target_ids = target_ids.squeeze(-1)
-        encoder_embeds = encoder_tensors if use_embeddings else None
-        encoder_ids = None if use_embeddings else encoder_tensors
-        output = self.model(
-            input_ids=encoder_ids,
-            inputs_embeds=encoder_embeds,
-            attention_mask=encoder_attention_mask,
-            decoder_inputs_embeds=decoder_input_embeds,
-            decoder_attention_mask=decoder_attention_mask,
-        )
-        logger.debug(f"logits: {pretty_tensor(output.logits)}")
-        return attributed_fn(
-            attribution_model=self,
-            forward_output=output,
-            encoder_input_ids=encoder_input_ids,
-            decoder_input_ids=decoder_input_ids,
-            encoder_input_embeds=encoder_embeds,
-            decoder_input_embeds=decoder_input_embeds,
-            target_ids=target_ids,
-            encoder_attention_mask=encoder_attention_mask,
-            decoder_attention_mask=decoder_attention_mask,
-            **{k: v for k, v in zip(attributed_fn_argnames, args) if v is not None},
-        )
+    @property
+    def info(self) -> Dict[str, str]:
+        dic_info: Dict[str, str] = super().info
+        extra_info = {
+            "tokenizer_name": self.tokenizer_name,
+            "tokenizer_class": self.tokenizer.__class__.__name__,
+        }
+        dic_info.update(extra_info)
+        return dic_info
 
     @unhooked
     def generate(
         self,
         inputs: Union[TextInput, BatchEncoding],
-        return_generation_output: Optional[bool] = False,
+        return_generation_output: bool = False,
+        max_new_tokens: Optional[int] = None,
         **kwargs,
-    ) -> Union[List[str], Tuple[List[str], GenerationOutput]]:
+    ) -> Union[List[str], Tuple[List[str], ModelOutput]]:
+        """Wrapper of model.generate to handle tokenization and decoding.
+
+        Args:
+            inputs (`Union[TextInput, BatchEncoding]`):
+                Inputs to be provided to the model for generation.
+            return_generation_output (`bool`, *optional*, defaults to False):
+                If true, generation outputs are returned alongside the generated text.
+
+        Returns:
+            `Union[List[str], Tuple[List[str], ModelOutput]]`: Generated text or a tuple of generated text and
+            generation outputs.
+        """
         if isinstance(inputs, str) or (
             isinstance(inputs, list) and len(inputs) > 0 and all([isinstance(x, str) for x in inputs])
         ):
             inputs = self.encode(inputs)
+        if max_new_tokens is None:
+            max_new_tokens = self.model_max_length - inputs.input_ids.shape[-1]
         inputs = inputs.to(self.device)
         generation_out = self.model.generate(
             input_ids=inputs.input_ids,
             attention_mask=inputs.attention_mask,
             return_dict_in_generate=True,
+            max_new_tokens=max_new_tokens,
             **kwargs,
         )
         texts = self.tokenizer.batch_decode(
             generation_out.sequences,
             skip_special_tokens=True,
         )
-        texts = texts[0] if len(texts) == 1 else texts
         if return_generation_output:
             return texts, generation_out
         return texts
 
     @staticmethod
-    def output2logits(forward_output: Seq2SeqLMOutput) -> FullLogitsTensor:
+    def output2logits(forward_output: Union[Seq2SeqLMOutput, CausalLMOutput]) -> FullLogitsTensor:
         # Full logits for last position of every sentence:
         # (batch_size, tgt_seq_len, vocab_size) => (batch_size, vocab_size)
         return forward_output.logits[:, -1, :].squeeze(1)
@@ -195,7 +214,6 @@ def encode(
         self,
         texts: TextInput,
         as_targets: bool = False,
-        prepend_bos_token: bool = True,
         return_baseline: bool = False,
         include_eos_baseline: bool = False,
     ) -> BatchEncoding:
@@ -208,31 +226,33 @@ def encode(
         Returns:
             BatchEncoding: contains ids and attention masks.
         """
-        with optional(as_targets, self.tokenizer.as_target_tokenizer()):
-            max_length = self.tokenizer.max_len_single_sentence
-            # Some tokenizer have weird values for max_len_single_sentence
-            # Cap length with max_model_input_sizes instead
-            if max_length > 1e6:
-                max_length = max(v for _, v in self.tokenizer.max_model_input_sizes.items())
-            batch = self.tokenizer(
-                texts,
-                add_special_tokens=True,
-                padding=True,
-                truncation=True,
-                max_length=max_length,
-                return_tensors="pt",
-            ).to(self.device)
+        if as_targets and not self.is_encoder_decoder:
+            raise ValueError("Decoder-only models should use tokenization as source only.")
+        max_length = self.tokenizer.max_len_single_sentence
+        # Some tokenizer have weird values for max_len_single_sentence
+        # Cap length with max_model_input_sizes instead
+        if max_length > 1e6:
+            max_length = max(v for _, v in self.tokenizer.max_model_input_sizes.items())
+        batch = self.tokenizer(
+            text=texts if not as_targets else None,
+            text_target=texts if as_targets else None,
+            add_special_tokens=True,
+            padding=True,
+            truncation=True,
+            max_length=max_length,
+            return_tensors="pt",
+        ).to(self.device)
         baseline_ids = None
         if return_baseline:
             if include_eos_baseline:
-                baseline_ids = torch.ones_like(batch["input_ids"]).long() * self.unk_id
+                baseline_ids = torch.ones_like(batch["input_ids"]).long() * self.tokenizer.unk_token_id
             else:
-                baseline_ids = batch["input_ids"].ne(self.eos_id).long() * self.unk_id
+                baseline_ids = batch["input_ids"].ne(self.eos_token_id).long() * self.tokenizer.unk_token_id
         # We prepend a BOS token only when tokenizing target texts.
-        if as_targets and prepend_bos_token:
+        if as_targets and self.is_encoder_decoder:
             ones_mask = torch.ones((batch["input_ids"].shape[0], 1), device=self.device, dtype=long)
             batch["attention_mask"] = torch.cat((ones_mask, batch["attention_mask"]), dim=1)
-            bos_ids = ones_mask * self.bos_id
+            bos_ids = ones_mask * self.model.config.decoder_start_token_id
             batch["input_ids"] = torch.cat((bos_ids, batch["input_ids"]), dim=1)
             if return_baseline:
                 baseline_ids = torch.cat((bos_ids, baseline_ids), dim=1)
@@ -243,21 +263,16 @@ def encode(
             baseline_ids=baseline_ids,
         )
 
-    def encoder_embed_ids(self, ids: IdsTensor) -> EmbeddingsTensor:
-        if self.encoder_int_embeds:
+    def embed_ids(self, ids: IdsTensor, as_targets: bool = False) -> EmbeddingsTensor:
+        if as_targets and not self.is_encoder_decoder:
+            raise ValueError("Decoder-only models should use tokenization as source only.")
+        if self.encoder_int_embeds is not None and not as_targets:
             embeddings = self.encoder_int_embeds.indices_to_embeddings(ids)
-            return embeddings * self.encoder_embed_scale
-        else:
-            embeddings = self.model.get_input_embeddings()
-            return embeddings(ids) * self.encoder_embed_scale
-
-    def decoder_embed_ids(self, ids: IdsTensor) -> EmbeddingsTensor:
-        if self.decoder_int_embeds:
+        elif self.decoder_int_embeds is not None and as_targets:
             embeddings = self.decoder_int_embeds.indices_to_embeddings(ids)
-            return embeddings * self.decoder_embed_scale
         else:
-            embeddings = self.model.get_input_embeddings()
-            return embeddings(ids) * self.decoder_embed_scale
+            embeddings = self.get_embedding_layer()(ids)
+        return embeddings * self.embed_scale
 
     def convert_ids_to_tokens(
         self, ids: IdsTensor, skip_special_tokens: Optional[bool] = True
@@ -277,7 +292,7 @@ def convert_tokens_to_string(
         self,
         tokens: OneOrMoreTokenSequences,
         skip_special_tokens: bool = True,
-        as_targets: bool = True,
+        as_targets: bool = False,
     ) -> TextInput:
         if isinstance(tokens, list) and len(tokens) == 0:
             return ""
@@ -298,8 +313,10 @@ def convert_string_to_tokens(
         as_targets: bool = False,
     ) -> OneOrMoreTokenSequences:
         if isinstance(text, str):
-            with optional(as_targets, self.tokenizer.as_target_tokenizer()):
-                ids = self.tokenizer(text)["input_ids"]
+            ids = self.tokenizer(
+                text=text if not as_targets else None,
+                text_target=text if as_targets else None,
+            )["input_ids"]
             return self.tokenizer.convert_ids_to_tokens(ids, skip_special_tokens)
         return [self.convert_string_to_tokens(t, skip_special_tokens, as_targets) for t in text]
 
@@ -316,4 +333,65 @@ def vocabulary_embeddings(self) -> VocabularyEmbeddingsTensor:
         return self.get_embedding_layer().weight
 
     def get_embedding_layer(self) -> torch.nn.Module:
-        return self.model.get_encoder().embed_tokens
+        return self.model.get_input_embeddings()
+
+
+class HuggingfaceEncoderDecoderModel(HuggingfaceModel, EncoderDecoderAttributionModel):
+    """Model wrapper for any ForConditionalGeneration model on the HuggingFace Hub used to enable
+    feature attribution. Corresponds to AutoModelForSeq2SeqLM auto classes in HF transformers.
+
+    Attributes:
+        model (::obj:`transformers.AutoModelForSeq2SeqLM`):
+            the model on which attribution is performed.
+    """
+
+    _autoclass = AutoModelForSeq2SeqLM
+
+    def __init__(
+        self,
+        model: Union[str, PreTrainedModel],
+        attribution_method: Optional[str] = None,
+        tokenizer: Union[str, PreTrainedTokenizer, None] = None,
+        device: str = None,
+        **kwargs,
+    ) -> NoReturn:
+        super().__init__(model, attribution_method, tokenizer, device, **kwargs)
+
+    def configure_embeddings_scale(self):
+        encoder = self.model.get_encoder()
+        decoder = self.model.get_decoder()
+        if hasattr(encoder, "embed_scale"):
+            self.embed_scale = encoder.embed_scale
+        if hasattr(decoder, "embed_scale") and decoder.embed_scale != self.embed_scale:
+            raise ValueError("Different encoder and decoder embed scales are not supported")
+
+
+class HuggingfaceDecoderOnlyModel(HuggingfaceModel, DecoderOnlyAttributionModel):
+    """Model wrapper for any ForCausalLM or LMHead model on the HuggingFace Hub used to enable
+    feature attribution. Corresponds to AutoModelForCausalLM auto classes in HF transformers.
+
+    Attributes:
+        model (::obj:`transformers.AutoModelForCausalLM`):
+            the model on which attribution is performed.
+    """
+
+    _autoclass = AutoModelForCausalLM
+
+    def __init__(
+        self,
+        model: Union[str, PreTrainedModel],
+        attribution_method: Optional[str] = None,
+        tokenizer: Union[str, PreTrainedTokenizer, None] = None,
+        device: str = None,
+        **kwargs,
+    ) -> NoReturn:
+        super().__init__(model, attribution_method, tokenizer, device, **kwargs)
+        self.tokenizer.padding_side = "left"
+        self.tokenizer.truncation_side = "left"
+        if self.pad_token is None:
+            self.pad_token = self.tokenizer.bos_token
+            self.tokenizer.pad_token = self.tokenizer.bos_token
+
+    def configure_embeddings_scale(self):
+        if hasattr(self.model, "embed_scale"):
+            self.embed_scale = self.model.embed_scale
diff --git a/inseq/models/model_decorators.py b/inseq/models/model_decorators.py
index 80194b2e..4995a4bb 100644
--- a/inseq/models/model_decorators.py
+++ b/inseq/models/model_decorators.py
@@ -3,7 +3,7 @@
 from functools import wraps
 
 
-def unhooked(f: Callable[[Any], Any]) -> Callable[[Any], Any]:
+def unhooked(f: Callable[..., Any]) -> Callable[..., Any]:
     @wraps(f)
     def attribution_free_wrapper(self, *args, **kwargs):
         was_hooked = False
diff --git a/inseq/utils/__init__.py b/inseq/utils/__init__.py
index 48ab34dd..067ecea3 100644
--- a/inseq/utils/__init__.py
+++ b/inseq/utils/__init__.py
@@ -30,7 +30,10 @@
 from .torch_utils import (
     abs_max,
     aggregate_contiguous,
+    check_device,
     euclidean_distance,
+    get_default_device,
+    get_front_padding,
     get_sequences_from_batched_steps,
     output2ce,
     output2ent,
@@ -69,6 +72,7 @@
     "abs_max",
     "prod_fn",
     "sum_fn",
+    "get_front_padding",
     "get_sequences_from_batched_steps",
     "output2prob",
     "output2ppl",
@@ -86,4 +90,6 @@
     "is_datasets_available",
     "is_captum_available",
     "is_joblib_available",
+    "check_device",
+    "get_default_device",
 ]
diff --git a/inseq/utils/misc.py b/inseq/utils/misc.py
index 1a3bbcfe..d8788f69 100644
--- a/inseq/utils/misc.py
+++ b/inseq/utils/misc.py
@@ -21,11 +21,13 @@ def identity_fn(x, **kwargs):
 
 
 @contextmanager
-def optional(condition, context_manager):
+def optional(condition, context_manager, alternative_fn=None, **alternative_fn_kwargs):
     if condition:
         with context_manager:
             yield
     else:
+        if alternative_fn is not None:
+            alternative_fn(**alternative_fn_kwargs)
         yield
 
 
@@ -46,12 +48,11 @@ def _pretty_list_contents(l: Sequence[Any]) -> str:
 
 def _pretty_list(l: Optional[Sequence[Any]], lpad: int = 8) -> str:
     if all([isinstance(x, list) for x in l]):
-        contents = " " * lpad + "[ " + f" ],\n{' ' * lpad}[ ".join([_pretty_list_contents(subl) for subl in l]) + " ]"
+        line_sep = f" ],\n{' ' * lpad}[ "
+        contents = " " * lpad + "[ " + line_sep.join([_pretty_list_contents(subl) for subl in l]) + " ]"
     else:
         if all([hasattr(x, "to_dict") for x in l]):
-            contents = ",\n".join(
-                [f"{' ' * lpad + x.__class__.__name__}({pretty_dict(x.to_dict(), lpad + 4)}" for x in l]
-            )
+            contents = ",\n".join([f"{' ' * lpad + x.__class__.__name__}({pretty_dict(x.to_dict(), lpad)}" for x in l])
         else:
             contents = " " * lpad + _pretty_list_contents(l)
     return "[\n" + contents + f"\n{' ' * (lpad - 4)}]"
@@ -90,7 +91,7 @@ def pretty_dict(d: Dict[str, Any], lpad: int = 4) -> str:
         if isinstance(v, list) or isinstance(v, tuple):
             out_txt += pretty_list(v, lpad + 4)
         elif isinstance(v, Tensor):
-            out_txt += pretty_tensor(v)
+            out_txt += pretty_tensor(v, lpad + 4)
         elif isinstance(v, dict):
             out_txt += pretty_dict(v, lpad + 4)
         elif hasattr(v, "to_dict"):
@@ -187,6 +188,8 @@ def isnotebook():
             return False  # Other type (?)
     except NameError:
         return False  # Probably standard Python interpreter
+    except ModuleNotFoundError:
+        return False  # IPython not installed
 
 
 def format_input_texts(
diff --git a/inseq/utils/registry.py b/inseq/utils/registry.py
index 8a35a9a4..57468987 100644
--- a/inseq/utils/registry.py
+++ b/inseq/utils/registry.py
@@ -1,10 +1,15 @@
-from typing import Dict, List, Set, Type
+from __future__ import annotations
+
+from typing import TypeVar
 
 from abc import ABC
 
 
+R = TypeVar("R", bound="Registry")
+
+
 class Registry(ABC):
-    attr = "None"  # Override in child classes
+    registry_attr = "None"  # Override in child classes
 
     def __init__(self) -> None:
         if self.__class__ is Registry or self.__class__ in Registry.__subclasses__():
@@ -14,7 +19,7 @@ def __init__(self) -> None:
             )
 
     @classmethod
-    def subclasses(cls) -> Set[Type["Registry"]]:
+    def subclasses(cls: type[R]) -> set[type[R]]:
         registry = set()
         for subclass in cls.__subclasses__():
             if subclass not in registry and subclass not in Registry.__subclasses__():
@@ -23,12 +28,12 @@ def subclasses(cls) -> Set[Type["Registry"]]:
         return registry
 
     @classmethod
-    def available_classes(cls) -> Dict[str, Type["Registry"]]:
-        methods = {getattr(c, cls.attr): c for c in cls.subclasses()}
+    def available_classes(cls: type[R]) -> dict[str, type[R]]:
+        methods = {getattr(c, cls.registry_attr): c for c in cls.subclasses()}
         if cls is not Registry and cls not in Registry.__subclasses__():
-            methods[str(getattr(cls, cls.attr))] = cls
+            methods[getattr(cls, cls.registry_attr)] = cls
         return methods
 
 
-def get_available_methods(cls: Type[Registry]) -> List[str]:
+def get_available_methods(cls: type[Registry]) -> list[str]:
     return [n for n in cls.available_classes().keys()]
diff --git a/inseq/utils/torch_utils.py b/inseq/utils/torch_utils.py
index 6c0b3c01..dea56541 100644
--- a/inseq/utils/torch_utils.py
+++ b/inseq/utils/torch_utils.py
@@ -1,9 +1,13 @@
-from typing import Any, Callable, List, Optional, Sequence, Tuple, Union
+from typing import TYPE_CHECKING, Any, Callable, List, Optional, Sequence, Tuple, Union
 
 import logging
 
 import torch
 import torch.nn.functional as F
+from torch.backends.cuda import is_built as is_cuda_built
+from torch.backends.mps import is_available as is_mps_available
+from torch.backends.mps import is_built as is_mps_built
+from torch.cuda import is_available as is_cuda_available
 from torchtyping import TensorType
 
 from .typing import (
@@ -14,8 +18,16 @@
 )
 
 
+if TYPE_CHECKING:
+    from ..models import AttributionModel
+
 logger = logging.getLogger(__name__)
 
+TORCH_BACKEND_DEVICE_MAP = {
+    "cuda": (is_cuda_built, is_cuda_available),
+    "mps": (is_mps_built, is_mps_available),
+}
+
 
 @torch.no_grad()
 def remap_from_filtered(
@@ -47,6 +59,8 @@ def sum_normalize_attributions(
         concat = True
         orig_sizes = [a.shape[cat_dim] for a in attributions]
         attributions = torch.cat(attributions, dim=cat_dim)
+    else:
+        orig_sizes = [attributions.shape[cat_dim]]
     # nansum is used to handle the target side sequence attribution case
     attributions = torch.nansum(attributions, dim=-1).squeeze(0)
     attributions = F.normalize(attributions, p=2, dim=norm_dim)
@@ -54,11 +68,11 @@ def sum_normalize_attributions(
         attributions = attributions.unsqueeze(0)
     if concat:
         attributions = attributions.split(orig_sizes, dim=cat_dim)
-        return attributions[0], attributions[1] + torch.tril(torch.ones_like(attributions[1]) * float("nan"))
+        return attributions[0], attributions[1]
     return attributions
 
 
-def euclidean_distance(vec_a: torch.Tensor, vec_b: torch.Tensor) -> float:
+def euclidean_distance(vec_a: torch.Tensor, vec_b: torch.Tensor) -> torch.Tensor:
     """Compute the Euclidean distance between two points."""
     return (vec_a - vec_b).pow(2).sum(-1).sqrt()
 
@@ -153,6 +167,12 @@ def sum_fn(t: torch.Tensor) -> torch.Tensor:
     return t.sum(dim=1, keepdim=True)
 
 
+def get_front_padding(t: torch.Tensor, pad: int = 0, dim: int = 1) -> List[int]:
+    """Given a tensor of shape (batch, seq_len) of ids, return a list of length batch containing
+    the number of padding tokens at the beginning of each sequence."""
+    return (t != pad).int().argmax(dim).tolist()
+
+
 def get_sequences_from_batched_steps(
     bsteps: List[torch.Tensor], pad_dims: Optional[Sequence[int]] = None
 ) -> List[torch.Tensor]:
@@ -167,24 +187,43 @@ def get_sequences_from_batched_steps(
     if pad_dims:
         for dim in pad_dims:
             max_dim = max(bstep.shape[dim] for bstep in bsteps)
-            bsteps = [
-                torch.cat(
-                    [
-                        bstep,
-                        torch.ones(
-                            *bstep.shape[:dim],
-                            max_dim - bstep.shape[dim],
-                            *bstep.shape[dim + 1 :],  # noqa
-                            dtype=bstep.dtype,
-                            device=bstep.device,
-                        )
-                        * float("nan"),
-                    ],
-                    dim=dim,
+            expanded_bsteps = []
+            for bstep in bsteps:
+                padded_bstep = torch.ones(
+                    *bstep.shape[:dim],
+                    max_dim - bstep.shape[dim],
+                    *bstep.shape[dim + 1 :],  # noqa
+                    dtype=bstep.dtype,
+                    device=bstep.device,
                 )
-                for bstep in bsteps
-            ]
-    if len(bsteps[0].shape) > 1:
-        return [t.squeeze() for t in torch.stack(bsteps, dim=2).split(1, dim=0)]
+                padded_bstep = torch.cat([bstep, padded_bstep * float("nan")], dim=dim)
+                expanded_bsteps.append(padded_bstep)
+    else:
+        expanded_bsteps = bsteps
+    dim = 2 if len(bsteps[0].shape) > 1 else 1
+    sequences = torch.stack(expanded_bsteps, dim=dim)
+    sequences = sequences.split(1, dim=0)
+    squeezed_sequences = [seq.squeeze(0) for seq in sequences]
+    return squeezed_sequences
+
+
+def check_device(device_name: str) -> bool:
+    if device_name == "cpu":
+        return True
+    if device_name not in TORCH_BACKEND_DEVICE_MAP:
+        raise ValueError(f"Unknown device {device_name}")
+    available_fn, built_fn = TORCH_BACKEND_DEVICE_MAP[device_name]
+    if not available_fn():
+        raise ValueError(f"Cannot use {device_name} device, {device_name} is not available.")
+    if not built_fn():
+        raise ValueError(f"Current Pytorch distribution does not support {device_name} execution")
+    return True
+
+
+def get_default_device() -> str:
+    if is_cuda_available() and is_cuda_built():
+        return "cuda"
+    elif is_mps_available() and is_mps_built():
+        return "mps"
     else:
-        return [t.squeeze() for t in torch.stack(bsteps, dim=1).split(1, dim=0)]
+        return "cpu"
diff --git a/inseq/utils/typing.py b/inseq/utils/typing.py
index 5d5658f1..88e6b7e2 100644
--- a/inseq/utils/typing.py
+++ b/inseq/utils/typing.py
@@ -1,9 +1,10 @@
-from typing import Sequence, Tuple, Union
+from typing import Optional, Sequence, Tuple, Union
 
 from dataclasses import dataclass
 
 from torch import long
 from torchtyping import TensorType
+from transformers import PreTrainedModel
 
 
 TextInput = Union[str, Sequence[str]]
@@ -28,6 +29,12 @@ def __eq__(self, other: Union[str, int, "TokenWithId"]):
             return False
 
 
+@dataclass
+class TextSequences:
+    targets: TextInput
+    sources: Optional[TextInput] = None
+
+
 OneOrMoreIdSequences = Sequence[Sequence[int]]
 OneOrMoreTokenSequences = Sequence[Sequence[str]]
 OneOrMoreTokenWithIdSequences = Sequence[Sequence[TokenWithId]]
@@ -77,7 +84,8 @@ def __eq__(self, other: Union[str, int, "TokenWithId"]):
 # For Huggingface it's a string identifier e.g. "t5-base", "Helsinki-NLP/opus-mt-en-it"
 # For Fairseq it's a tuple of strings containing repo and model name
 # e.g. ("pytorch/fairseq", "transformer.wmt14.en-fr")
-ModelIdentifier = Union[str, Tuple[str, str]]
+ModelIdentifier = str  # Union[str, Tuple[str, str]]
+ModelClass = PreTrainedModel
 
 AttributionForwardInputs = Union[IdsTensor, EmbeddingsTensor]
 AttributionForwardInputsPair = Union[
diff --git a/inseq/utils/viz_utils.py b/inseq/utils/viz_utils.py
index 65988b8c..9de41d1a 100644
--- a/inseq/utils/viz_utils.py
+++ b/inseq/utils/viz_utils.py
@@ -21,6 +21,7 @@
 import matplotlib.pyplot as plt
 import numpy as np
 from matplotlib.colors import Colormap, LinearSegmentedColormap
+from numpy.typing import NDArray
 
 from .misc import ordinal_str
 from .typing import TokenWithId
@@ -43,7 +44,7 @@ def get_color(
     score: float,
     min_value: Union[float, int],
     max_value: Union[float, int],
-    cmap: Union[str, Colormap, None] = None,
+    cmap: Colormap,
     return_alpha: bool = True,
     return_string: bool = True,
 ):
@@ -68,20 +69,22 @@ def sanitize_html(txt: Union[str, TokenWithId]) -> str:
 
 
 def get_colors(
-    scores: np.array,
+    scores: NDArray,
     min_value: Union[float, int],
     max_value: Union[float, int],
     cmap: Union[str, Colormap, None] = None,
     return_alpha: bool = True,
     return_strings: bool = True,
 ):
-    if cmap is None:
-        cmap = plt.get_cmap(cmap if isinstance(cmap, str) else "coolwarm", 200)
+    if isinstance(cmap, Colormap):
+        out_cmap = cmap
+    else:
+        out_cmap: Colormap = plt.get_cmap(cmap if isinstance(cmap, str) else "coolwarm", 200)
     input_colors = []
-    for row_index in range(scores.shape[0]):
+    for row_idx in range(scores.shape[0]):
         input_colors_row = []
-        for col_index in range(scores.shape[1]):
-            color = get_color(scores[row_index, col_index], min_value, max_value, cmap, return_alpha, return_strings)
+        for col_idx in range(scores.shape[1]):
+            color = get_color(scores[row_idx, col_idx], min_value, max_value, out_cmap, return_alpha, return_strings)
             input_colors_row.append(color)
         input_colors.append(input_colors_row)
     return input_colors
diff --git a/poetry.lock b/poetry.lock
index 3005d99f..8b37caeb 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -16,15 +16,15 @@ multidict = ">=4.5,<7.0"
 yarl = ">=1.0,<2.0"
 
 [package.extras]
-speedups = ["aiodns", "brotli", "cchardet"]
+speedups = ["Brotli", "aiodns", "cchardet"]
 
 [[package]]
 name = "aiosignal"
-version = "1.2.0"
+version = "1.3.1"
 description = "aiosignal: a list of registered asynchronous callbacks"
 category = "main"
 optional = true
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
 frozenlist = ">=1.1.0"
@@ -42,12 +42,12 @@ name = "appnope"
 version = "0.1.3"
 description = "Disable App Nap on macOS >= 10.9"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [[package]]
 name = "astroid"
-version = "2.12.12"
+version = "2.12.13"
 description = "An abstract syntax tree for Python with inference support."
 category = "dev"
 optional = false
@@ -63,17 +63,17 @@ wrapt = [
 
 [[package]]
 name = "asttokens"
-version = "2.1.0"
+version = "2.2.0"
 description = "Annotate AST trees with source code positions"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [package.dependencies]
 six = "*"
 
 [package.extras]
-test = ["astroid (<=2.5.3)", "pytest"]
+test = ["astroid", "pytest"]
 
 [[package]]
 name = "async-timeout"
@@ -83,14 +83,6 @@ category = "main"
 optional = true
 python-versions = ">=3.6"
 
-[[package]]
-name = "atomicwrites"
-version = "1.4.1"
-description = "Atomic file writes."
-category = "dev"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-
 [[package]]
 name = "attrs"
 version = "22.1.0"
@@ -100,14 +92,14 @@ optional = false
 python-versions = ">=3.5"
 
 [package.extras]
-dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit", "cloudpickle"]
-docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"]
-tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "zope.interface", "cloudpickle"]
-tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "mypy (>=0.900,!=0.940)", "pytest-mypy-plugins", "cloudpickle"]
+dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
+docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
+tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
+tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
 
 [[package]]
 name = "babel"
-version = "2.10.3"
+version = "2.11.0"
 description = "Internationalization utilities"
 category = "dev"
 optional = false
@@ -121,7 +113,7 @@ name = "backcall"
 version = "0.2.0"
 description = "Specifications for callback functions passed in to an API"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [[package]]
@@ -139,9 +131,9 @@ PyYAML = ">=5.3.1"
 stevedore = ">=1.20.0"
 
 [package.extras]
-test = ["coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml", "beautifulsoup4 (>=4.8.0)", "pylint (==1.9.4)"]
+test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)", "toml"]
 toml = ["toml"]
-yaml = ["pyyaml"]
+yaml = ["PyYAML"]
 
 [[package]]
 name = "black"
@@ -179,10 +171,10 @@ numpy = "*"
 torch = ">=1.6"
 
 [package.extras]
-dev = ["flask", "ipython", "ipywidgets", "jupyter", "flask-compress", "pytest", "pytest-cov", "black (==21.4b2)", "flake8", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-katex", "mypy (>=0.760)", "usort (==0.6.4)", "ufmt", "scikit-learn"]
-insights = ["flask", "ipython", "ipywidgets", "jupyter", "flask-compress"]
+dev = ["black (==21.4b2)", "flake8", "flask", "flask-compress", "ipython", "ipywidgets", "jupyter", "mypy (>=0.760)", "pytest", "pytest-cov", "scikit-learn", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-katex", "ufmt", "usort (==0.6.4)"]
+insights = ["flask", "flask-compress", "ipython", "ipywidgets", "jupyter"]
 test = ["pytest", "pytest-cov"]
-tutorials = ["flask", "ipython", "ipywidgets", "jupyter", "flask-compress", "torchtext", "torchvision"]
+tutorials = ["flask", "flask-compress", "ipython", "ipywidgets", "jupyter", "torchtext", "torchvision"]
 
 [[package]]
 name = "certifi"
@@ -197,7 +189,7 @@ name = "cffi"
 version = "1.15.1"
 description = "Foreign Function Interface for Python calling C code."
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [package.dependencies]
@@ -220,7 +212,7 @@ optional = false
 python-versions = ">=3.6.0"
 
 [package.extras]
-unicode_backport = ["unicodedata2"]
+unicode-backport = ["unicodedata2"]
 
 [[package]]
 name = "click"
@@ -241,6 +233,20 @@ category = "main"
 optional = false
 python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
 
+[[package]]
+name = "comm"
+version = "0.1.1"
+description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc."
+category = "main"
+optional = true
+python-versions = ">=3.6"
+
+[package.dependencies]
+traitlets = ">5.3"
+
+[package.extras]
+test = ["pytest"]
+
 [[package]]
 name = "commonmark"
 version = "0.9.1"
@@ -254,7 +260,7 @@ test = ["flake8 (==3.7.8)", "hypothesis (==3.55.3)"]
 
 [[package]]
 name = "contourpy"
-version = "1.0.5"
+version = "1.0.6"
 description = "Python library for calculating contours of 2D quadrilateral grids"
 category = "main"
 optional = false
@@ -264,11 +270,25 @@ python-versions = ">=3.7"
 numpy = ">=1.16"
 
 [package.extras]
-test-no-codebase = ["pillow", "matplotlib", "pytest"]
+bokeh = ["bokeh", "selenium"]
+docs = ["docutils (<0.18)", "sphinx (<=5.2.0)", "sphinx-rtd-theme"]
+test = ["Pillow", "flake8", "isort", "matplotlib", "pytest"]
 test-minimal = ["pytest"]
-test = ["isort", "flake8", "pillow", "matplotlib", "pytest"]
-docs = ["sphinx-rtd-theme", "sphinx", "docutils (<0.18)"]
-bokeh = ["selenium", "bokeh"]
+test-no-codebase = ["Pillow", "matplotlib", "pytest"]
+
+[[package]]
+name = "coverage"
+version = "6.5.0"
+description = "Code coverage measurement for Python"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""}
+
+[package.extras]
+toml = ["tomli"]
 
 [[package]]
 name = "cycler"
@@ -288,7 +308,7 @@ python-versions = ">=3.6,<4.0"
 
 [[package]]
 name = "datasets"
-version = "2.6.1"
+version = "2.7.1"
 description = "HuggingFace community-driven open-source library of datasets"
 category = "main"
 optional = true
@@ -296,7 +316,7 @@ python-versions = ">=3.7.0"
 
 [package.dependencies]
 aiohttp = "*"
-dill = "<0.3.6"
+dill = "<0.3.7"
 fsspec = {version = ">=2021.11.1", extras = ["http"]}
 huggingface-hub = ">=0.2.0,<1.0.0"
 multiprocess = "*"
@@ -315,22 +335,22 @@ xxhash = "*"
 apache-beam = ["apache-beam (>=2.26.0)"]
 audio = ["librosa"]
 benchmarks = ["numpy (==1.18.5)", "tensorflow (==2.3.0)", "torch (==1.7.1)", "transformers (==3.0.2)"]
-dev = ["absl-py", "pytest", "pytest-datadir", "pytest-xdist", "apache-beam (>=2.26.0)", "elasticsearch (<8.0.0)", "aiobotocore (>=2.0.1)", "boto3 (>=1.19.8)", "botocore (>=1.22.8)", "faiss-cpu (>=1.6.4)", "fsspec", "lz4", "moto[s3,server] (==2.0.4)", "py7zr", "rarfile (>=4.0)", "s3fs (>=2021.11.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "torch", "torchaudio (<0.12.0)", "soundfile", "transformers", "zstandard", "bert-score (>=0.3.6)", "jiwer", "langdetect", "mauve-text", "nltk", "rouge-score", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "sqlalchemy", "tldextract", "toml (>=0.10.1)", "requests-file (>=1.5.1)", "tldextract (>=3.1.0)", "texttable (>=1.6.3)", "Werkzeug (>=1.0.1)", "six (>=1.15.0,<1.16.0)", "Pillow (>=6.2.1)", "librosa", "black (>=22.0,<23.0)", "flake8 (>=3.8.3)", "isort (>=5.0.0)", "pyyaml (>=5.3.1)"]
+dev = ["Pillow (>=6.2.1)", "Werkzeug (>=1.0.1)", "absl-py", "aiobotocore (>=2.0.1)", "apache-beam (>=2.26.0)", "bert-score (>=0.3.6)", "black (>=22.0,<23.0)", "boto3 (>=1.19.8)", "botocore (>=1.22.8)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "flake8 (>=3.8.3)", "fsspec[s3]", "isort (>=5.0.0)", "jiwer", "langdetect", "librosa", "lz4", "mauve-text", "moto[s3,server] (==2.0.4)", "nltk", "py7zr", "pytest", "pytest-datadir", "pytest-xdist", "pyyaml (>=5.3.1)", "rarfile (>=4.0)", "requests-file (>=1.5.1)", "rouge-score", "s3fs (>=2021.11.1)", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "six (>=1.15.0,<1.16.0)", "soundfile", "spacy (>=3.0.0)", "sqlalchemy", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "texttable (>=1.6.3)", "tldextract", "tldextract (>=3.1.0)", "toml (>=0.10.1)", "torch", "torchaudio (<0.12.0)", "transformers", "typer (<0.5.0)", "zstandard"]
 docs = ["s3fs"]
 quality = ["black (>=22.0,<23.0)", "flake8 (>=3.8.3)", "isort (>=5.0.0)", "pyyaml (>=5.3.1)"]
-s3 = ["fsspec", "boto3", "botocore", "s3fs"]
-tensorflow = ["tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)"]
-tensorflow_gpu = ["tensorflow-gpu (>=2.2.0,!=2.6.0,!=2.6.1)"]
-tests = ["absl-py", "pytest", "pytest-datadir", "pytest-xdist", "apache-beam (>=2.26.0)", "elasticsearch (<8.0.0)", "aiobotocore (>=2.0.1)", "boto3 (>=1.19.8)", "botocore (>=1.22.8)", "faiss-cpu (>=1.6.4)", "fsspec", "lz4", "moto[s3,server] (==2.0.4)", "py7zr", "rarfile (>=4.0)", "s3fs (>=2021.11.1)", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "torch", "torchaudio (<0.12.0)", "soundfile", "transformers", "zstandard", "bert-score (>=0.3.6)", "jiwer", "langdetect", "mauve-text", "nltk", "rouge-score", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "sqlalchemy", "tldextract", "toml (>=0.10.1)", "requests-file (>=1.5.1)", "tldextract (>=3.1.0)", "texttable (>=1.6.3)", "Werkzeug (>=1.0.1)", "six (>=1.15.0,<1.16.0)", "Pillow (>=6.2.1)", "librosa"]
+s3 = ["boto3", "botocore", "fsspec", "s3fs"]
+tensorflow = ["tensorflow (>=2.2.0,!=2.6.0,!=2.6.1)", "tensorflow-macos"]
+tensorflow-gpu = ["tensorflow-gpu (>=2.2.0,!=2.6.0,!=2.6.1)"]
+tests = ["Pillow (>=6.2.1)", "Werkzeug (>=1.0.1)", "absl-py", "aiobotocore (>=2.0.1)", "apache-beam (>=2.26.0)", "bert-score (>=0.3.6)", "boto3 (>=1.19.8)", "botocore (>=1.22.8)", "elasticsearch (<8.0.0)", "faiss-cpu (>=1.6.4)", "fsspec[s3]", "jiwer", "langdetect", "librosa", "lz4", "mauve-text", "moto[s3,server] (==2.0.4)", "nltk", "py7zr", "pytest", "pytest-datadir", "pytest-xdist", "rarfile (>=4.0)", "requests-file (>=1.5.1)", "rouge-score", "s3fs (>=2021.11.1)", "sacrebleu", "sacremoses", "scikit-learn", "scipy", "sentencepiece", "seqeval", "six (>=1.15.0,<1.16.0)", "soundfile", "spacy (>=3.0.0)", "sqlalchemy", "tensorflow (>=2.3,!=2.6.0,!=2.6.1)", "tensorflow-macos", "texttable (>=1.6.3)", "tldextract", "tldextract (>=3.1.0)", "toml (>=0.10.1)", "torch", "torchaudio (<0.12.0)", "transformers", "typer (<0.5.0)", "zstandard"]
 torch = ["torch"]
 vision = ["Pillow (>=6.2.1)"]
 
 [[package]]
 name = "debugpy"
-version = "1.6.3"
+version = "1.6.4"
 description = "An implementation of the Debug Adapter Protocol for Python"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [[package]]
@@ -338,16 +358,16 @@ name = "decorator"
 version = "5.1.1"
 description = "Decorators for Humans"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.5"
 
 [[package]]
 name = "dill"
-version = "0.3.5.1"
+version = "0.3.6"
 description = "serialize all of python"
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
+python-versions = ">=3.7"
 
 [package.extras]
 graph = ["objgraph (>=1.7.2)"]
@@ -381,27 +401,38 @@ packaging = "*"
 toml = "*"
 
 [package.extras]
-pipenv = ["pipenv"]
 conda = ["pyyaml"]
+pipenv = ["pipenv"]
 
 [[package]]
 name = "entrypoints"
 version = "0.4"
 description = "Discover and load entry points from installed packages."
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.6"
 
+[[package]]
+name = "exceptiongroup"
+version = "1.0.4"
+description = "Backport of PEP 654 (exception groups)"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+test = ["pytest (>=6)"]
+
 [[package]]
 name = "executing"
 version = "1.2.0"
 description = "Get the currently executing AST node of a frame, and other information"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [package.extras]
-tests = ["asttokens", "pytest", "littleutils", "rich"]
+tests = ["asttokens", "littleutils", "pytest", "rich"]
 
 [[package]]
 name = "filelock"
@@ -417,16 +448,16 @@ testing = ["covdefaults (>=2.2)", "coverage (>=6.4.2)", "pytest (>=7.1.2)", "pyt
 
 [[package]]
 name = "flake8"
-version = "4.0.1"
+version = "6.0.0"
 description = "the modular source code checker: pep8 pyflakes and co"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.8.1"
 
 [package.dependencies]
-mccabe = ">=0.6.0,<0.7.0"
-pycodestyle = ">=2.8.0,<2.9.0"
-pyflakes = ">=2.4.0,<2.5.0"
+mccabe = ">=0.7.0,<0.8.0"
+pycodestyle = ">=2.10.0,<2.11.0"
+pyflakes = ">=3.0.0,<3.1.0"
 
 [[package]]
 name = "fonttools"
@@ -437,9 +468,9 @@ optional = false
 python-versions = ">=3.7"
 
 [package.extras]
-all = ["fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "zopfli (>=0.1.4)", "lz4 (>=1.7.4.2)", "matplotlib", "sympy", "skia-pathops (>=0.5.0)", "uharfbuzz (>=0.23.0)", "brotlicffi (>=0.8.0)", "scipy", "brotli (>=1.0.1)", "munkres", "unicodedata2 (>=14.0.0)", "xattr"]
+all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0,<5)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=14.0.0)", "xattr", "zopfli (>=0.1.4)"]
 graphite = ["lz4 (>=1.7.4.2)"]
-interpolatable = ["scipy", "munkres"]
+interpolatable = ["munkres", "scipy"]
 lxml = ["lxml (>=4.0,<5)"]
 pathops = ["skia-pathops (>=0.5.0)"]
 plot = ["matplotlib"]
@@ -448,11 +479,11 @@ symfont = ["sympy"]
 type1 = ["xattr"]
 ufo = ["fs (>=2.2.0,<3)"]
 unicode = ["unicodedata2 (>=14.0.0)"]
-woff = ["zopfli (>=0.1.4)", "brotlicffi (>=0.8.0)", "brotli (>=1.0.1)"]
+woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
 
 [[package]]
 name = "frozenlist"
-version = "1.3.1"
+version = "1.3.3"
 description = "A list-like structure which implements collections.abc.MutableSequence"
 category = "main"
 optional = true
@@ -460,7 +491,7 @@ python-versions = ">=3.7"
 
 [[package]]
 name = "fsspec"
-version = "2022.10.0"
+version = "2022.11.0"
 description = "File-system specification"
 category = "main"
 optional = true
@@ -475,7 +506,7 @@ abfs = ["adlfs"]
 adl = ["adlfs"]
 arrow = ["pyarrow (>=1)"]
 dask = ["dask", "distributed"]
-dropbox = ["dropboxdrivefs", "requests", "dropbox"]
+dropbox = ["dropbox", "dropboxdrivefs", "requests"]
 entrypoints = ["importlib-metadata"]
 fuse = ["fusepy"]
 gcs = ["gcsfs"]
@@ -484,7 +515,7 @@ github = ["requests"]
 gs = ["gcsfs"]
 gui = ["panel"]
 hdfs = ["pyarrow (>=1)"]
-http = ["requests", "aiohttp (!=4.0.0a0,!=4.0.0a1)"]
+http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)", "requests"]
 libarchive = ["libarchive-c"]
 oci = ["ocifs"]
 s3 = ["s3fs"]
@@ -495,11 +526,11 @@ tqdm = ["tqdm"]
 
 [[package]]
 name = "gitdb"
-version = "4.0.9"
+version = "4.0.10"
 description = "Git Object Database"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
 smmap = ">=3.0.1,<6"
@@ -517,7 +548,7 @@ gitdb = ">=4.0.1,<5"
 
 [[package]]
 name = "huggingface-hub"
-version = "0.10.1"
+version = "0.11.1"
 description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub"
 category = "main"
 optional = false
@@ -532,18 +563,19 @@ tqdm = "*"
 typing-extensions = ">=3.7.4.3"
 
 [package.extras]
-all = ["InquirerPy (==0.3.4)", "isort (>=5.5.4)", "jedi", "jinja2", "pytest", "pytest-cov", "soundfile", "black (==22.3)", "flake8 (>=3.8.3)", "flake8-bugbear", "mypy"]
+all = ["InquirerPy (==0.3.4)", "Jinja2", "black (==22.3)", "flake8 (>=3.8.3)", "flake8-bugbear", "isort (>=5.5.4)", "jedi", "mypy (==0.982)", "pytest", "pytest-cov", "pytest-env", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3"]
 cli = ["InquirerPy (==0.3.4)"]
-dev = ["InquirerPy (==0.3.4)", "isort (>=5.5.4)", "jedi", "jinja2", "pytest", "pytest-cov", "soundfile", "black (==22.3)", "flake8 (>=3.8.3)", "flake8-bugbear", "mypy"]
-fastai = ["toml", "fastai (>=2.4)", "fastcore (>=1.3.27)"]
-quality = ["black (==22.3)", "flake8 (>=3.8.3)", "flake8-bugbear", "isort (>=5.5.4)", "mypy"]
-tensorflow = ["tensorflow", "pydot", "graphviz"]
-testing = ["InquirerPy (==0.3.4)", "isort (>=5.5.4)", "jedi", "jinja2", "pytest", "pytest-cov", "soundfile"]
+dev = ["InquirerPy (==0.3.4)", "Jinja2", "black (==22.3)", "flake8 (>=3.8.3)", "flake8-bugbear", "isort (>=5.5.4)", "jedi", "mypy (==0.982)", "pytest", "pytest-cov", "pytest-env", "soundfile", "types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3"]
+fastai = ["fastai (>=2.4)", "fastcore (>=1.3.27)", "toml"]
+quality = ["black (==22.3)", "flake8 (>=3.8.3)", "flake8-bugbear", "isort (>=5.5.4)", "mypy (==0.982)"]
+tensorflow = ["graphviz", "pydot", "tensorflow"]
+testing = ["InquirerPy (==0.3.4)", "Jinja2", "isort (>=5.5.4)", "jedi", "pytest", "pytest-cov", "pytest-env", "soundfile"]
 torch = ["torch"]
+typing = ["types-PyYAML", "types-requests", "types-simplejson", "types-toml", "types-tqdm", "types-urllib3"]
 
 [[package]]
 name = "identify"
-version = "2.5.8"
+version = "2.5.9"
 description = "File identification library for Python"
 category = "dev"
 optional = false
@@ -570,9 +602,9 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "importlib-metadata"
-version = "5.0.0"
+version = "5.1.0"
 description = "Read metadata from Python packages"
-category = "main"
+category = "dev"
 optional = false
 python-versions = ">=3.7"
 
@@ -580,9 +612,9 @@ python-versions = ">=3.7"
 zipp = ">=0.5"
 
 [package.extras]
-docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
 perf = ["ipython"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
+testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
 
 [[package]]
 name = "iniconfig"
@@ -594,14 +626,15 @@ python-versions = "*"
 
 [[package]]
 name = "ipykernel"
-version = "6.16.2"
+version = "6.18.2"
 description = "IPython Kernel for Jupyter"
 category = "main"
-optional = false
-python-versions = ">=3.7"
+optional = true
+python-versions = ">=3.8"
 
 [package.dependencies]
 appnope = {version = "*", markers = "platform_system == \"Darwin\""}
+comm = ">=0.1"
 debugpy = ">=1.0"
 ipython = ">=7.23.1"
 jupyter-client = ">=6.1.12"
@@ -614,15 +647,16 @@ tornado = ">=6.1"
 traitlets = ">=5.1.0"
 
 [package.extras]
+cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"]
 docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt"]
-test = ["flaky", "ipyparallel", "pre-commit", "pytest-cov", "pytest-timeout", "pytest (>=7.0)"]
+test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio", "pytest-cov", "pytest-timeout"]
 
 [[package]]
 name = "ipython"
-version = "8.6.0"
+version = "8.7.0"
 description = "IPython: Productive Interactive Computing"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.8"
 
 [package.dependencies]
@@ -634,15 +668,15 @@ jedi = ">=0.16"
 matplotlib-inline = "*"
 pexpect = {version = ">4.3", markers = "sys_platform != \"win32\""}
 pickleshare = "*"
-prompt-toolkit = ">3.0.1,<3.1.0"
+prompt-toolkit = ">=3.0.11,<3.1.0"
 pygments = ">=2.4.0"
 stack-data = "*"
 traitlets = ">=5"
 
 [package.extras]
-all = ["black", "ipykernel", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "docrepr", "matplotlib", "stack-data", "pytest (<7)", "typing-extensions", "pytest (<7.1)", "pytest-asyncio", "testpath", "nbconvert", "nbformat", "ipywidgets", "notebook", "ipyparallel", "qtconsole", "curio", "matplotlib (!=3.2.0)", "numpy (>=1.20)", "pandas", "trio"]
+all = ["black", "curio", "docrepr", "ipykernel", "ipyparallel", "ipywidgets", "matplotlib", "matplotlib (!=3.2.0)", "nbconvert", "nbformat", "notebook", "numpy (>=1.20)", "pandas", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "qtconsole", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "trio", "typing-extensions"]
 black = ["black"]
-doc = ["ipykernel", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "docrepr", "matplotlib", "stack-data", "pytest (<7)", "typing-extensions", "pytest (<7.1)", "pytest-asyncio", "testpath"]
+doc = ["docrepr", "ipykernel", "matplotlib", "pytest (<7)", "pytest (<7.1)", "pytest-asyncio", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "stack-data", "testpath", "typing-extensions"]
 kernel = ["ipykernel"]
 nbconvert = ["nbconvert"]
 nbformat = ["nbformat"]
@@ -650,14 +684,14 @@ notebook = ["ipywidgets", "notebook"]
 parallel = ["ipyparallel"]
 qtconsole = ["qtconsole"]
 test = ["pytest (<7.1)", "pytest-asyncio", "testpath"]
-test_extra = ["pytest (<7.1)", "pytest-asyncio", "testpath", "curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.20)", "pandas", "trio"]
+test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.20)", "pandas", "pytest (<7.1)", "pytest-asyncio", "testpath", "trio"]
 
 [[package]]
 name = "ipywidgets"
 version = "8.0.2"
 description = "Jupyter interactive widgets"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [package.dependencies]
@@ -682,25 +716,26 @@ python-versions = ">=3.6.1,<4.0"
 colorama = {version = ">=0.4.3,<0.5.0", optional = true, markers = "extra == \"colors\""}
 
 [package.extras]
-pipfile_deprecated_finder = ["pipreqs", "requirementslib"]
-requirements_deprecated_finder = ["pipreqs", "pip-api"]
 colors = ["colorama (>=0.4.3,<0.5.0)"]
+pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
 plugins = ["setuptools"]
+requirements-deprecated-finder = ["pip-api", "pipreqs"]
 
 [[package]]
 name = "jedi"
-version = "0.18.1"
+version = "0.18.2"
 description = "An autocompletion tool for Python that can be used for text editors."
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.6"
 
 [package.dependencies]
 parso = ">=0.8.0,<0.9.0"
 
 [package.extras]
+docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"]
 qa = ["flake8 (==3.8.3)", "mypy (==0.782)"]
-testing = ["Django (<3.1)", "colorama", "docopt", "pytest (<7.0.0)"]
+testing = ["Django (<3.1)", "attrs", "colorama", "docopt", "pytest (<7.0.0)"]
 
 [[package]]
 name = "jinja2"
@@ -721,12 +756,12 @@ name = "joblib"
 version = "1.2.0"
 description = "Lightweight pipelining with Python functions"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [[package]]
 name = "json-tricks"
-version = "3.15.5"
+version = "3.16.1"
 description = "Extra features for Python's JSON: comments, order, numpy, pandas, datetimes, and many more! Simple but customizable."
 category = "main"
 optional = false
@@ -734,10 +769,10 @@ python-versions = "*"
 
 [[package]]
 name = "jupyter-client"
-version = "7.4.4"
+version = "7.4.7"
 description = "Jupyter protocol implementation and client libraries"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [package.dependencies]
@@ -750,22 +785,24 @@ tornado = ">=6.2"
 traitlets = "*"
 
 [package.extras]
-doc = ["ipykernel", "myst-parser", "sphinx-rtd-theme", "sphinx (>=1.3.6)", "sphinxcontrib-github-alt"]
+doc = ["ipykernel", "myst-parser", "sphinx (>=1.3.6)", "sphinx-rtd-theme", "sphinxcontrib-github-alt"]
 test = ["codecov", "coverage", "ipykernel (>=6.12)", "ipython", "mypy", "pre-commit", "pytest", "pytest-asyncio (>=0.18)", "pytest-cov", "pytest-timeout"]
 
 [[package]]
 name = "jupyter-core"
-version = "4.11.2"
+version = "5.1.0"
 description = "Jupyter core package. A base package on which Jupyter projects rely."
 category = "main"
-optional = false
-python-versions = ">=3.7"
+optional = true
+python-versions = ">=3.8"
 
 [package.dependencies]
+platformdirs = ">=2.5"
 pywin32 = {version = ">=1.0", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""}
-traitlets = "*"
+traitlets = ">=5.3"
 
 [package.extras]
+docs = ["myst-parser", "sphinxcontrib-github-alt", "traitlets"]
 test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"]
 
 [[package]]
@@ -773,7 +810,7 @@ name = "jupyterlab-widgets"
 version = "3.0.3"
 description = "Jupyter interactive widgets for JupyterLab"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [[package]]
@@ -816,7 +853,7 @@ python-versions = ">=3.7"
 
 [[package]]
 name = "matplotlib"
-version = "3.6.1"
+version = "3.6.2"
 description = "Python plotting package"
 category = "main"
 optional = false
@@ -839,7 +876,7 @@ name = "matplotlib-inline"
 version = "0.1.6"
 description = "Inline Matplotlib backend for Jupyter"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.5"
 
 [package.dependencies]
@@ -847,11 +884,11 @@ traitlets = "*"
 
 [[package]]
 name = "mccabe"
-version = "0.6.1"
+version = "0.7.0"
 description = "McCabe checker, plugin for flake8"
 category = "dev"
 optional = false
-python-versions = "*"
+python-versions = ">=3.6"
 
 [[package]]
 name = "multidict"
@@ -863,31 +900,14 @@ python-versions = ">=3.7"
 
 [[package]]
 name = "multiprocess"
-version = "0.70.13"
+version = "0.70.14"
 description = "better multiprocessing and multithreading in python"
 category = "main"
 optional = true
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
-
-[package.dependencies]
-dill = ">=0.3.5.1"
-
-[[package]]
-name = "mypy"
-version = "0.910"
-description = "Optional static typing for Python"
-category = "dev"
-optional = false
-python-versions = ">=3.5"
+python-versions = ">=3.7"
 
 [package.dependencies]
-mypy-extensions = ">=0.4.3,<0.5.0"
-toml = "*"
-typing-extensions = ">=3.7.4"
-
-[package.extras]
-dmypy = ["psutil (>=4.0)"]
-python2 = ["typed-ast (>=1.4.0,<1.5.0)"]
+dill = ">=0.3.6"
 
 [[package]]
 name = "mypy-extensions"
@@ -902,7 +922,7 @@ name = "nest-asyncio"
 version = "1.5.6"
 description = "Patch asyncio to allow nested event loops"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.5"
 
 [[package]]
@@ -913,9 +933,12 @@ category = "dev"
 optional = false
 python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*"
 
+[package.dependencies]
+setuptools = "*"
+
 [[package]]
 name = "numpy"
-version = "1.23.4"
+version = "1.23.5"
 description = "NumPy is the fundamental package for array computing with Python."
 category = "main"
 optional = false
@@ -929,6 +952,10 @@ category = "main"
 optional = false
 python-versions = ">=3"
 
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
 [[package]]
 name = "nvidia-cuda-nvrtc-cu11"
 version = "11.7.99"
@@ -937,6 +964,10 @@ category = "main"
 optional = false
 python-versions = ">=3"
 
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
 [[package]]
 name = "nvidia-cuda-runtime-cu11"
 version = "11.7.99"
@@ -945,6 +976,10 @@ category = "main"
 optional = false
 python-versions = ">=3"
 
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
 [[package]]
 name = "nvidia-cudnn-cu11"
 version = "8.5.0.96"
@@ -953,6 +988,10 @@ category = "main"
 optional = false
 python-versions = ">=3"
 
+[package.dependencies]
+setuptools = "*"
+wheel = "*"
+
 [[package]]
 name = "packaging"
 version = "21.3"
@@ -966,7 +1005,7 @@ pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
 
 [[package]]
 name = "pandas"
-version = "1.5.1"
+version = "1.5.2"
 description = "Powerful data structures for data analysis, time series, and statistics"
 category = "main"
 optional = true
@@ -974,21 +1013,22 @@ python-versions = ">=3.8"
 
 [package.dependencies]
 numpy = [
-    {version = ">=1.21.0", markers = "python_version >= \"3.10\""},
     {version = ">=1.20.3", markers = "python_version < \"3.10\""},
+    {version = ">=1.21.0", markers = "python_version >= \"3.10\""},
+    {version = ">=1.23.2", markers = "python_version >= \"3.11\""},
 ]
 python-dateutil = ">=2.8.1"
 pytz = ">=2020.1"
 
 [package.extras]
-test = ["pytest-xdist (>=1.31)", "pytest (>=6.0)", "hypothesis (>=5.5.3)"]
+test = ["hypothesis (>=5.5.3)", "pytest (>=6.0)", "pytest-xdist (>=1.31)"]
 
 [[package]]
 name = "parso"
 version = "0.8.3"
 description = "A Python Parser"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.6"
 
 [package.extras]
@@ -1005,7 +1045,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [[package]]
 name = "pathspec"
-version = "0.10.1"
+version = "0.10.2"
 description = "Utility library for gitignore style pattern matching of file paths."
 category = "dev"
 optional = false
@@ -1024,7 +1064,7 @@ name = "pexpect"
 version = "4.8.0"
 description = "Pexpect allows easy control of interactive console applications."
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [package.dependencies]
@@ -1035,7 +1075,7 @@ name = "pickleshare"
 version = "0.7.5"
 description = "Tiny 'shelve'-like database with concurrency support"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [[package]]
@@ -1052,15 +1092,15 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa
 
 [[package]]
 name = "platformdirs"
-version = "2.5.2"
-description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
-category = "dev"
+version = "2.5.4"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "main"
 optional = false
 python-versions = ">=3.7"
 
 [package.extras]
-docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"]
-test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"]
+docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"]
+test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
 
 [[package]]
 name = "pluggy"
@@ -1087,7 +1127,7 @@ pastel = ">=0.2.1,<0.3.0"
 tomli = ">=1.2.2"
 
 [package.extras]
-poetry_plugin = ["poetry (>=1.0,<2.0)"]
+poetry-plugin = ["poetry (>=1.0,<2.0)"]
 
 [[package]]
 name = "pre-commit"
@@ -1107,10 +1147,10 @@ virtualenv = ">=20.0.8"
 
 [[package]]
 name = "prompt-toolkit"
-version = "3.0.31"
+version = "3.0.33"
 description = "Library for building powerful interactive command lines in Python"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.6.2"
 
 [package.dependencies]
@@ -1126,21 +1166,21 @@ python-versions = ">=3.7"
 
 [[package]]
 name = "psutil"
-version = "5.9.3"
+version = "5.9.4"
 description = "Cross-platform lib for process and system monitoring in Python."
 category = "main"
-optional = false
+optional = true
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
 [package.extras]
-test = ["ipaddress", "mock", "enum34", "pywin32", "wmi"]
+test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"]
 
 [[package]]
 name = "ptyprocess"
 version = "0.7.0"
 description = "Run a subprocess in a pseudo terminal"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [[package]]
@@ -1148,7 +1188,7 @@ name = "pure-eval"
 version = "0.2.2"
 description = "Safely evaluate AST nodes without side effects"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [package.extras]
@@ -1159,12 +1199,12 @@ name = "py"
 version = "1.11.0"
 description = "library with cross-python path, ini-parsing, io, code, log facilities"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
 
 [[package]]
 name = "pyarrow"
-version = "10.0.0"
+version = "10.0.1"
 description = "Python library for Apache Arrow"
 category = "main"
 optional = true
@@ -1175,41 +1215,27 @@ numpy = ">=1.16.6"
 
 [[package]]
 name = "pycodestyle"
-version = "2.8.0"
+version = "2.10.0"
 description = "Python style guide checker"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+python-versions = ">=3.6"
 
 [[package]]
 name = "pycparser"
 version = "2.21"
 description = "C parser in Python"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
 
-[[package]]
-name = "pydocstyle"
-version = "6.1.1"
-description = "Python docstring style checker"
-category = "dev"
-optional = false
-python-versions = ">=3.6"
-
-[package.dependencies]
-snowballstemmer = "*"
-
-[package.extras]
-toml = ["toml"]
-
 [[package]]
 name = "pyflakes"
-version = "2.4.0"
+version = "3.0.1"
 description = "passive checker of Python programs"
 category = "dev"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+python-versions = ">=3.6"
 
 [[package]]
 name = "pygments"
@@ -1224,14 +1250,14 @@ plugins = ["importlib-metadata"]
 
 [[package]]
 name = "pylint"
-version = "2.15.5"
+version = "2.15.7"
 description = "python code static checker"
 category = "dev"
 optional = false
 python-versions = ">=3.7.2"
 
 [package.dependencies]
-astroid = ">=2.12.12,<=2.14.0-dev0"
+astroid = ">=2.12.13,<=2.14.0-dev0"
 colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""}
 dill = ">=0.2"
 isort = ">=4.2.5,<6"
@@ -1254,28 +1280,42 @@ optional = false
 python-versions = ">=3.6.8"
 
 [package.extras]
-diagrams = ["railroad-diagrams", "jinja2"]
+diagrams = ["jinja2", "railroad-diagrams"]
 
 [[package]]
 name = "pytest"
-version = "6.2.5"
+version = "7.2.0"
 description = "pytest: simple powerful testing with Python"
 category = "dev"
 optional = false
-python-versions = ">=3.6"
+python-versions = ">=3.7"
 
 [package.dependencies]
-atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""}
 attrs = ">=19.2.0"
 colorama = {version = "*", markers = "sys_platform == \"win32\""}
+exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
 iniconfig = "*"
 packaging = "*"
 pluggy = ">=0.12,<2.0"
-py = ">=1.8.2"
-toml = "*"
+tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
 
 [package.extras]
-testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"]
+testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
+
+[[package]]
+name = "pytest-cov"
+version = "4.0.0"
+description = "Pytest plugin for measuring coverage."
+category = "dev"
+optional = false
+python-versions = ">=3.6"
+
+[package.dependencies]
+coverage = {version = ">=5.2.1", extras = ["toml"]}
+pytest = ">=4.6"
+
+[package.extras]
+testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"]
 
 [[package]]
 name = "python-dateutil"
@@ -1290,7 +1330,7 @@ six = ">=1.5"
 
 [[package]]
 name = "pytz"
-version = "2022.5"
+version = "2022.6"
 description = "World timezone definitions, modern and historical"
 category = "main"
 optional = false
@@ -1309,10 +1349,10 @@ tokenize-rt = "<5"
 
 [[package]]
 name = "pywin32"
-version = "304"
+version = "305"
 description = "Python for Window Extensions"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [[package]]
@@ -1328,7 +1368,7 @@ name = "pyzmq"
 version = "24.0.1"
 description = "Python bindings for 0MQ"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.6"
 
 [package.dependencies]
@@ -1350,7 +1390,7 @@ sphinx = ">=1.3.1"
 
 [[package]]
 name = "regex"
-version = "2022.9.13"
+version = "2022.10.31"
 description = "Alternative regular expression module, to replace re."
 category = "main"
 optional = false
@@ -1372,7 +1412,7 @@ urllib3 = ">=1.21.1,<1.27"
 
 [package.extras]
 socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use_chardet_on_py3 = ["chardet (>=3.0.2,<6)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
 
 [[package]]
 name = "responses"
@@ -1387,7 +1427,7 @@ requests = ">=2.0,<3.0"
 urllib3 = ">=1.25.10"
 
 [package.extras]
-tests = ["pytest (>=4.6)", "coverage (>=6.0.0)", "pytest-cov", "pytest-localserver", "flake8", "types-mock", "types-requests", "mypy"]
+tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=4.6)", "pytest-cov", "pytest-localserver", "types-mock", "types-requests"]
 
 [[package]]
 name = "rich"
@@ -1406,18 +1446,47 @@ pygments = ">=2.6.0,<3.0.0"
 jupyter = ["ipywidgets (>=7.5.1,<8.0.0)"]
 
 [[package]]
-name = "safety"
-version = "1.10.3"
-description = "Checks installed dependencies for known vulnerabilities."
+name = "ruamel-yaml"
+version = "0.17.21"
+description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order"
+category = "dev"
+optional = false
+python-versions = ">=3"
+
+[package.dependencies]
+"ruamel.yaml.clib" = {version = ">=0.2.6", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.11\""}
+
+[package.extras]
+docs = ["ryd"]
+jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
+
+[[package]]
+name = "ruamel-yaml-clib"
+version = "0.2.7"
+description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml"
 category = "dev"
 optional = false
 python-versions = ">=3.5"
 
+[[package]]
+name = "safety"
+version = "2.3.3"
+description = "Checks installed dependencies for known vulnerabilities and licenses."
+category = "dev"
+optional = false
+python-versions = "*"
+
 [package.dependencies]
-Click = ">=6.0"
-dparse = ">=0.5.1"
-packaging = "*"
+Click = ">=8.0.2"
+dparse = ">=0.6.2"
+packaging = ">=21.0"
 requests = "*"
+"ruamel.yaml" = ">=0.17.21"
+setuptools = ">=19.3"
+
+[package.extras]
+github = ["jinja2 (>=3.1.0)", "pygithub (>=1.43.3)"]
+gitlab = ["python-gitlab (>=1.3.0)"]
 
 [[package]]
 name = "scikit-learn"
@@ -1434,10 +1503,10 @@ scipy = ">=1.3.2"
 threadpoolctl = ">=2.0.0"
 
 [package.extras]
-benchmark = ["matplotlib (>=3.1.2)", "pandas (>=1.0.5)", "memory-profiler (>=0.57.0)"]
-docs = ["matplotlib (>=3.1.2)", "scikit-image (>=0.16.2)", "pandas (>=1.0.5)", "seaborn (>=0.9.0)", "memory-profiler (>=0.57.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "numpydoc (>=1.2.0)", "Pillow (>=7.1.2)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"]
-examples = ["matplotlib (>=3.1.2)", "scikit-image (>=0.16.2)", "pandas (>=1.0.5)", "seaborn (>=0.9.0)"]
-tests = ["matplotlib (>=3.1.2)", "scikit-image (>=0.16.2)", "pandas (>=1.0.5)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "flake8 (>=3.8.2)", "black (>=22.3.0)", "mypy (>=0.961)", "pyamg (>=4.0.0)", "numpydoc (>=1.2.0)"]
+benchmark = ["matplotlib (>=3.1.2)", "memory-profiler (>=0.57.0)", "pandas (>=1.0.5)"]
+docs = ["Pillow (>=7.1.2)", "matplotlib (>=3.1.2)", "memory-profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)", "sphinx (>=4.0.1)", "sphinx-gallery (>=0.7.0)", "sphinx-prompt (>=1.3.0)", "sphinxext-opengraph (>=0.4.2)"]
+examples = ["matplotlib (>=3.1.2)", "pandas (>=1.0.5)", "scikit-image (>=0.16.2)", "seaborn (>=0.9.0)"]
+tests = ["black (>=22.3.0)", "flake8 (>=3.8.2)", "matplotlib (>=3.1.2)", "mypy (>=0.961)", "numpydoc (>=1.2.0)", "pandas (>=1.0.5)", "pyamg (>=4.0.0)", "pytest (>=5.0.1)", "pytest-cov (>=2.9.0)", "scikit-image (>=0.16.2)"]
 
 [[package]]
 name = "scipy"
@@ -1451,9 +1520,9 @@ python-versions = ">=3.8"
 numpy = ">=1.18.5,<1.26.0"
 
 [package.extras]
-test = ["pytest", "pytest-cov", "pytest-xdist", "asv", "mpmath", "gmpy2", "threadpoolctl", "scikit-umfpack"]
-doc = ["sphinx (!=4.1.0)", "pydata-sphinx-theme (==0.9.0)", "sphinx-panels (>=0.5.2)", "matplotlib (>2)", "numpydoc", "sphinx-tabs"]
-dev = ["mypy", "typing-extensions", "pycodestyle", "flake8"]
+dev = ["flake8", "mypy", "pycodestyle", "typing_extensions"]
+doc = ["matplotlib (>2)", "numpydoc", "pydata-sphinx-theme (==0.9.0)", "sphinx (!=4.1.0)", "sphinx-panels (>=0.5.2)", "sphinx-tabs"]
+test = ["asv", "gmpy2", "mpmath", "pytest", "pytest-cov", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
 
 [[package]]
 name = "sentencepiece"
@@ -1463,6 +1532,19 @@ category = "main"
 optional = false
 python-versions = "*"
 
+[[package]]
+name = "setuptools"
+version = "65.6.3"
+description = "Easily download, build, install, upgrade, and uninstall Python packages"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
+testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
+testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
+
 [[package]]
 name = "setuptools-scm"
 version = "7.0.5"
@@ -1473,6 +1555,7 @@ python-versions = ">=3.7"
 
 [package.dependencies]
 packaging = ">=20.0"
+setuptools = "*"
 tomli = ">=1.0.0"
 typing-extensions = "*"
 
@@ -1533,8 +1616,8 @@ sphinxcontrib-serializinghtml = ">=1.1.5"
 
 [package.extras]
 docs = ["sphinxcontrib-websupport"]
-lint = ["flake8 (>=3.5.0)", "flake8-comprehensions", "flake8-bugbear", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "docutils-stubs", "types-typed-ast", "types-requests"]
-test = ["pytest (>=4.6)", "html5lib", "typed-ast", "cython"]
+lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-bugbear", "flake8-comprehensions", "flake8-simplify", "isort", "mypy (>=0.981)", "sphinx-lint", "types-requests", "types-typed-ast"]
+test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"]
 
 [[package]]
 name = "sphinx-copybutton"
@@ -1548,12 +1631,12 @@ python-versions = ">=3.6"
 sphinx = ">=1.8"
 
 [package.extras]
-code_style = ["pre-commit (==2.12.1)"]
-rtd = ["sphinx", "ipython", "sphinx-book-theme"]
+code-style = ["pre-commit (==2.12.1)"]
+rtd = ["ipython", "sphinx", "sphinx-book-theme"]
 
 [[package]]
 name = "sphinx-gitstamp"
-version = "0.3.2"
+version = "0.3.3"
 description = "git timestamp generator for Sphinx"
 category = "dev"
 optional = false
@@ -1577,18 +1660,18 @@ markdown = ">=3.4"
 
 [[package]]
 name = "sphinx-rtd-theme"
-version = "1.0.0"
+version = "1.1.1"
 description = "Read the Docs theme for Sphinx"
 category = "dev"
 optional = false
-python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
+python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7"
 
 [package.dependencies]
 docutils = "<0.18"
-sphinx = ">=1.6"
+sphinx = ">=1.6,<6"
 
 [package.extras]
-dev = ["transifex-client", "sphinxcontrib-httpdomain", "bump2version"]
+dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"]
 
 [[package]]
 name = "sphinxcontrib-applehelp"
@@ -1599,7 +1682,7 @@ optional = false
 python-versions = ">=3.5"
 
 [package.extras]
-lint = ["flake8", "mypy", "docutils-stubs"]
+lint = ["docutils-stubs", "flake8", "mypy"]
 test = ["pytest"]
 
 [[package]]
@@ -1611,7 +1694,7 @@ optional = false
 python-versions = ">=3.5"
 
 [package.extras]
-lint = ["flake8", "mypy", "docutils-stubs"]
+lint = ["docutils-stubs", "flake8", "mypy"]
 test = ["pytest"]
 
 [[package]]
@@ -1623,8 +1706,8 @@ optional = false
 python-versions = ">=3.6"
 
 [package.extras]
-lint = ["flake8", "mypy", "docutils-stubs"]
-test = ["pytest", "html5lib"]
+lint = ["docutils-stubs", "flake8", "mypy"]
+test = ["html5lib", "pytest"]
 
 [[package]]
 name = "sphinxcontrib-jsmath"
@@ -1635,7 +1718,7 @@ optional = false
 python-versions = ">=3.5"
 
 [package.extras]
-test = ["pytest", "flake8", "mypy"]
+test = ["flake8", "mypy", "pytest"]
 
 [[package]]
 name = "sphinxcontrib-qthelp"
@@ -1646,7 +1729,7 @@ optional = false
 python-versions = ">=3.5"
 
 [package.extras]
-lint = ["flake8", "mypy", "docutils-stubs"]
+lint = ["docutils-stubs", "flake8", "mypy"]
 test = ["pytest"]
 
 [[package]]
@@ -1658,7 +1741,7 @@ optional = false
 python-versions = ">=3.5"
 
 [package.extras]
-lint = ["flake8", "mypy", "docutils-stubs"]
+lint = ["docutils-stubs", "flake8", "mypy"]
 test = ["pytest"]
 
 [[package]]
@@ -1685,10 +1768,10 @@ sphinx = ">=2.0"
 
 [[package]]
 name = "stack-data"
-version = "0.6.0"
+version = "0.6.2"
 description = "Extract data from python stack frames and tracebacks for informative displays"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
 [package.dependencies]
@@ -1697,11 +1780,11 @@ executing = ">=1.2.0"
 pure-eval = "*"
 
 [package.extras]
-tests = ["pytest", "typeguard", "pygments", "littleutils", "cython"]
+tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"]
 
 [[package]]
 name = "stevedore"
-version = "4.1.0"
+version = "4.1.1"
 description = "Manage dynamic plugins for Python applications"
 category = "dev"
 optional = false
@@ -1728,16 +1811,16 @@ python-versions = ">=3.6.1"
 
 [[package]]
 name = "tokenizers"
-version = "0.13.1"
+version = "0.13.2"
 description = "Fast and Customizable Tokenizers"
 category = "main"
 optional = false
 python-versions = "*"
 
 [package.extras]
-dev = ["pytest", "requests", "numpy", "datasets"]
-docs = ["sphinx", "sphinx-rtd-theme", "setuptools-rust"]
-testing = ["pytest", "requests", "numpy", "datasets"]
+dev = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"]
+docs = ["setuptools-rust", "sphinx", "sphinx-rtd-theme"]
+testing = ["black (==22.3)", "datasets", "numpy", "pytest", "requests"]
 
 [[package]]
 name = "toml"
@@ -1798,7 +1881,7 @@ name = "tornado"
 version = "6.2"
 description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed."
 category = "main"
-optional = false
+optional = true
 python-versions = ">= 3.7"
 
 [[package]]
@@ -1820,10 +1903,10 @@ telegram = ["requests"]
 
 [[package]]
 name = "traitlets"
-version = "5.5.0"
-description = ""
+version = "5.6.0"
+description = "Traitlets Python configuration system"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [package.extras]
@@ -1832,7 +1915,7 @@ test = ["pre-commit", "pytest"]
 
 [[package]]
 name = "transformers"
-version = "4.23.1"
+version = "4.24.0"
 description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow"
 category = "main"
 optional = false
@@ -1841,7 +1924,6 @@ python-versions = ">=3.7.0"
 [package.dependencies]
 filelock = "*"
 huggingface-hub = ">=0.10.0,<1.0"
-importlib-metadata = {version = "*", optional = true, markers = "extra == \"torchhub\""}
 numpy = ">=1.17"
 packaging = ">=20.0"
 protobuf = {version = "<=3.20.2", optional = true, markers = "extra == \"sentencepiece\""}
@@ -1855,45 +1937,45 @@ tqdm = ">=4.27"
 
 [package.extras]
 accelerate = ["accelerate (>=0.10.0)"]
-all = ["tensorflow (>=2.4)", "onnxconverter-common", "tf2onnx", "tensorflow-text", "torch (>=1.7,!=1.12.0)", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "flax (>=0.4.1)", "optax (>=0.0.8)", "sentencepiece (>=0.1.91,!=0.1.92)", "protobuf (<=3.20.2)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torchaudio", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer", "pillow", "optuna", "ray", "sigopt", "timm", "codecarbon (==1.2.0)", "accelerate (>=0.10.0)"]
-audio = ["librosa", "pyctcdecode (>=0.3.0)", "phonemizer"]
+all = ["Pillow", "accelerate (>=0.10.0)", "codecarbon (==1.2.0)", "flax (>=0.4.1)", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "kenlm", "librosa", "onnxconverter-common", "optax (>=0.0.8)", "optuna", "phonemizer", "protobuf (<=3.20.2)", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.4)", "tensorflow-text", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.7,!=1.12.0)", "torchaudio"]
+audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"]
 codecarbon = ["codecarbon (==1.2.0)"]
-deepspeed = ["deepspeed (>=0.6.5)", "accelerate (>=0.10.0)"]
-deepspeed-testing = ["deepspeed (>=0.6.5)", "accelerate (>=0.10.0)", "pytest", "pytest-xdist", "timeout-decorator", "parameterized", "psutil", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "pytest-timeout", "black (==22.3)", "sacrebleu (>=1.4.12,<2.0.0)", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "nltk", "GitPython (<3.1.19)", "hf-doc-builder (>=0.3.0)", "protobuf (<=3.20.2)", "sacremoses", "rjieba", "safetensors (>=0.2.1)", "beautifulsoup4", "faiss-cpu", "cookiecutter (==1.7.3)", "optuna"]
-dev = ["tensorflow (>=2.4)", "onnxconverter-common", "tf2onnx", "tensorflow-text", "torch (>=1.7,!=1.12.0)", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "flax (>=0.4.1)", "optax (>=0.0.8)", "sentencepiece (>=0.1.91,!=0.1.92)", "protobuf (<=3.20.2)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torchaudio", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer", "pillow", "optuna", "ray", "sigopt", "timm", "codecarbon (==1.2.0)", "accelerate (>=0.10.0)", "pytest", "pytest-xdist", "timeout-decorator", "parameterized", "psutil", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "pytest-timeout", "black (==22.3)", "sacrebleu (>=1.4.12,<2.0.0)", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "nltk", "GitPython (<3.1.19)", "hf-doc-builder (>=0.3.0)", "sacremoses", "rjieba", "safetensors (>=0.2.1)", "beautifulsoup4", "faiss-cpu", "cookiecutter (==1.7.3)", "isort (>=5.5.4)", "flake8 (>=3.8.3)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "unidic-lite (>=1.0.7)", "unidic (>=1.0.2)", "sudachipy (>=0.6.6)", "sudachidict-core (>=20220729)", "pyknp (>=0.6.1)", "hf-doc-builder", "scikit-learn"]
-dev-tensorflow = ["pytest", "pytest-xdist", "timeout-decorator", "parameterized", "psutil", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "pytest-timeout", "black (==22.3)", "sacrebleu (>=1.4.12,<2.0.0)", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "nltk", "GitPython (<3.1.19)", "hf-doc-builder (>=0.3.0)", "protobuf (<=3.20.2)", "sacremoses", "rjieba", "safetensors (>=0.2.1)", "beautifulsoup4", "faiss-cpu", "cookiecutter (==1.7.3)", "tensorflow (>=2.4)", "onnxconverter-common", "tf2onnx", "tensorflow-text", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "pillow", "isort (>=5.5.4)", "flake8 (>=3.8.3)", "hf-doc-builder", "scikit-learn", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer"]
-dev-torch = ["pytest", "pytest-xdist", "timeout-decorator", "parameterized", "psutil", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "pytest-timeout", "black (==22.3)", "sacrebleu (>=1.4.12,<2.0.0)", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "nltk", "GitPython (<3.1.19)", "hf-doc-builder (>=0.3.0)", "protobuf (<=3.20.2)", "sacremoses", "rjieba", "safetensors (>=0.2.1)", "beautifulsoup4", "faiss-cpu", "cookiecutter (==1.7.3)", "torch (>=1.7,!=1.12.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torchaudio", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer", "pillow", "optuna", "ray", "sigopt", "timm", "codecarbon (==1.2.0)", "isort (>=5.5.4)", "flake8 (>=3.8.3)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "unidic-lite (>=1.0.7)", "unidic (>=1.0.2)", "sudachipy (>=0.6.6)", "sudachidict-core (>=20220729)", "pyknp (>=0.6.1)", "hf-doc-builder", "scikit-learn", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"]
-docs = ["tensorflow (>=2.4)", "onnxconverter-common", "tf2onnx", "tensorflow-text", "torch (>=1.7,!=1.12.0)", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "flax (>=0.4.1)", "optax (>=0.0.8)", "sentencepiece (>=0.1.91,!=0.1.92)", "protobuf (<=3.20.2)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torchaudio", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer", "pillow", "optuna", "ray", "sigopt", "timm", "codecarbon (==1.2.0)", "accelerate (>=0.10.0)", "hf-doc-builder"]
-docs_specific = ["hf-doc-builder"]
+deepspeed = ["accelerate (>=0.10.0)", "deepspeed (>=0.6.5)"]
+deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.10.0)", "beautifulsoup4", "black (==22.3)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.6.5)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "optuna", "parameterized", "protobuf (<=3.20.2)", "psutil", "pytest", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "safetensors (>=0.2.1)", "timeout-decorator"]
+dev = ["GitPython (<3.1.19)", "Pillow", "accelerate (>=0.10.0)", "beautifulsoup4", "black (==22.3)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flake8 (>=3.8.3)", "flax (>=0.4.1)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "kenlm", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8)", "optuna", "parameterized", "phonemizer", "protobuf (<=3.20.2)", "psutil", "pyctcdecode (>=0.4.0)", "pyknp (>=0.6.1)", "pytest", "pytest-timeout", "pytest-xdist", "ray[tune]", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "safetensors (>=0.2.1)", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorflow (>=2.4)", "tensorflow-text", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.7,!=1.12.0)", "torchaudio", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)"]
+dev-tensorflow = ["GitPython (<3.1.19)", "Pillow", "beautifulsoup4", "black (==22.3)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flake8 (>=3.8.3)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf (<=3.20.2)", "psutil", "pyctcdecode (>=0.4.0)", "pytest", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "safetensors (>=0.2.1)", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorflow (>=2.4)", "tensorflow-text", "tf2onnx", "timeout-decorator", "tokenizers (>=0.11.1,!=0.11.3,<0.14)"]
+dev-torch = ["GitPython (<3.1.19)", "Pillow", "beautifulsoup4", "black (==22.3)", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flake8 (>=3.8.3)", "fugashi (>=1.0)", "hf-doc-builder", "hf-doc-builder (>=0.3.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf (<=3.20.2)", "psutil", "pyctcdecode (>=0.4.0)", "pyknp (>=0.6.1)", "pytest", "pytest-timeout", "pytest-xdist", "ray[tune]", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "safetensors (>=0.2.1)", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "timeout-decorator", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.7,!=1.12.0)", "torchaudio", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)"]
+docs = ["Pillow", "accelerate (>=0.10.0)", "codecarbon (==1.2.0)", "flax (>=0.4.1)", "hf-doc-builder", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "kenlm", "librosa", "onnxconverter-common", "optax (>=0.0.8)", "optuna", "phonemizer", "protobuf (<=3.20.2)", "pyctcdecode (>=0.4.0)", "ray[tune]", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>=2.4)", "tensorflow-text", "tf2onnx", "timm", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.7,!=1.12.0)", "torchaudio"]
+docs-specific = ["hf-doc-builder"]
 fairscale = ["fairscale (>0.3)"]
-flax = ["jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "flax (>=0.4.1)", "optax (>=0.0.8)"]
-flax-speech = ["librosa", "pyctcdecode (>=0.3.0)", "phonemizer"]
+flax = ["flax (>=0.4.1)", "jax (>=0.2.8,!=0.3.2,<=0.3.6)", "jaxlib (>=0.1.65,<=0.3.6)", "optax (>=0.0.8)"]
+flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"]
 ftfy = ["ftfy"]
-integrations = ["optuna", "ray", "sigopt"]
-ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "unidic-lite (>=1.0.7)", "unidic (>=1.0.2)", "sudachipy (>=0.6.6)", "sudachidict-core (>=20220729)", "pyknp (>=0.6.1)"]
+integrations = ["optuna", "ray[tune]", "sigopt"]
+ja = ["fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "pyknp (>=0.6.1)", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)"]
 modelcreation = ["cookiecutter (==1.7.3)"]
-onnx = ["onnxconverter-common", "tf2onnx", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"]
+onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"]
 onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"]
 optuna = ["optuna"]
-quality = ["black (==22.3)", "datasets (!=2.5.0)", "isort (>=5.5.4)", "flake8 (>=3.8.3)", "GitPython (<3.1.19)", "hf-doc-builder (>=0.3.0)"]
-ray = ["ray"]
-retrieval = ["faiss-cpu", "datasets (!=2.5.0)"]
+quality = ["GitPython (<3.1.19)", "black (==22.3)", "datasets (!=2.5.0)", "flake8 (>=3.8.3)", "hf-doc-builder (>=0.3.0)", "isort (>=5.5.4)"]
+ray = ["ray[tune]"]
+retrieval = ["datasets (!=2.5.0)", "faiss-cpu"]
 sagemaker = ["sagemaker (>=2.31.0)"]
-sentencepiece = ["sentencepiece (>=0.1.91,!=0.1.92)", "protobuf (<=3.20.2)"]
-serving = ["pydantic", "uvicorn", "fastapi", "starlette"]
+sentencepiece = ["protobuf (<=3.20.2)", "sentencepiece (>=0.1.91,!=0.1.92)"]
+serving = ["fastapi", "pydantic", "starlette", "uvicorn"]
 sigopt = ["sigopt"]
 sklearn = ["scikit-learn"]
-speech = ["torchaudio", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer"]
-testing = ["pytest", "pytest-xdist", "timeout-decorator", "parameterized", "psutil", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "pytest-timeout", "black (==22.3)", "sacrebleu (>=1.4.12,<2.0.0)", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "nltk", "GitPython (<3.1.19)", "hf-doc-builder (>=0.3.0)", "protobuf (<=3.20.2)", "sacremoses", "rjieba", "safetensors (>=0.2.1)", "beautifulsoup4", "faiss-cpu", "cookiecutter (==1.7.3)"]
-tf = ["tensorflow (>=2.4)", "onnxconverter-common", "tf2onnx", "tensorflow-text"]
-tf-cpu = ["tensorflow-cpu (>=2.3)", "onnxconverter-common", "tf2onnx", "tensorflow-text"]
-tf-speech = ["librosa", "pyctcdecode (>=0.3.0)", "phonemizer"]
+speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"]
+testing = ["GitPython (<3.1.19)", "beautifulsoup4", "black (==22.3)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "hf-doc-builder (>=0.3.0)", "nltk", "parameterized", "protobuf (<=3.20.2)", "psutil", "pytest", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "safetensors (>=0.2.1)", "timeout-decorator"]
+tf = ["onnxconverter-common", "tensorflow (>=2.4)", "tensorflow-text", "tf2onnx"]
+tf-cpu = ["onnxconverter-common", "tensorflow-cpu (>=2.3)", "tensorflow-text", "tf2onnx"]
+tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"]
 timm = ["timm"]
 tokenizers = ["tokenizers (>=0.11.1,!=0.11.3,<0.14)"]
 torch = ["torch (>=1.7,!=1.12.0)"]
-torch-speech = ["torchaudio", "librosa", "pyctcdecode (>=0.3.0)", "phonemizer"]
-torchhub = ["filelock", "huggingface-hub (>=0.10.0,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf (<=3.20.2)", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "torch (>=1.7,!=1.12.0)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "tqdm (>=4.27)"]
-vision = ["pillow"]
+torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"]
+torchhub = ["filelock", "huggingface-hub (>=0.10.0,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf (<=3.20.2)", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.11.1,!=0.11.3,<0.14)", "torch (>=1.7,!=1.12.0)", "tqdm (>=4.27)"]
+vision = ["Pillow"]
 
 [[package]]
 name = "typeguard"
@@ -1904,8 +1986,8 @@ optional = false
 python-versions = ">=3.5.3"
 
 [package.extras]
-doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"]
-test = ["pytest", "typing-extensions", "mypy"]
+doc = ["sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
+test = ["mypy", "pytest", "typing-extensions"]
 
 [[package]]
 name = "typing-extensions"
@@ -1917,20 +1999,20 @@ python-versions = ">=3.7"
 
 [[package]]
 name = "urllib3"
-version = "1.26.12"
+version = "1.26.13"
 description = "HTTP library with thread-safe connection pooling, file post, and more."
 category = "main"
 optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
 
 [package.extras]
-brotli = ["brotlicffi (>=0.8.0)", "brotli (>=1.0.9)", "brotlipy (>=0.6.0)"]
-secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "urllib3-secure-extra", "ipaddress"]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
 socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
 
 [[package]]
 name = "virtualenv"
-version = "20.16.6"
+version = "20.17.0"
 description = "Virtual Python Environment builder"
 category = "dev"
 optional = false
@@ -1950,15 +2032,26 @@ name = "wcwidth"
 version = "0.2.5"
 description = "Measures the displayed width of unicode strings in a terminal"
 category = "main"
-optional = false
+optional = true
 python-versions = "*"
 
+[[package]]
+name = "wheel"
+version = "0.38.4"
+description = "A built-package format for Python"
+category = "main"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+test = ["pytest (>=3.0.0)"]
+
 [[package]]
 name = "widgetsnbextension"
 version = "4.0.3"
 description = "Jupyter interactive widgets for Jupyter Notebook"
 category = "main"
-optional = false
+optional = true
 python-versions = ">=3.7"
 
 [[package]]
@@ -1991,31 +2084,119 @@ multidict = ">=4.0"
 
 [[package]]
 name = "zipp"
-version = "3.10.0"
+version = "3.11.0"
 description = "Backport of pathlib-compatible object wrapper for zip files"
-category = "main"
+category = "dev"
 optional = false
 python-versions = ">=3.7"
 
 [package.extras]
-docs = ["sphinx (>=3.5)", "jaraco.packaging (>=9)", "rst.linker (>=1.9)", "furo", "jaraco.tidelift (>=1.4)"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "flake8 (<5)", "pytest-cov", "pytest-enabler (>=1.3)", "jaraco.itertools", "func-timeout", "jaraco.functools", "more-itertools", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
+docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
+testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
 
 [extras]
-all = ["scikit-learn", "datasets"]
 datasets = ["datasets"]
-scikit-learn = ["scikit-learn"]
+notebook = ["ipykernel", "ipywidgets"]
+sklearn = ["scikit-learn", "joblib"]
 
 [metadata]
 lock-version = "1.1"
-python-versions = ">=3.8,<3.12"
-content-hash = "6e9fc766672ffd104e6c3220f41eccf6b406de2aeaad67231d8012207444131b"
+python-versions = ">=3.8.1,<3.12"
+content-hash = "54bfc26dbe9039b6b6b5d718ad84eaaa6fb4c37bdaf60e8bba7df0f33b65dd28"
 
 [metadata.files]
-aiohttp = []
+aiohttp = [
+    {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ba71c9b4dcbb16212f334126cc3d8beb6af377f6703d9dc2d9fb3874fd667ee9"},
+    {file = "aiohttp-3.8.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d24b8bb40d5c61ef2d9b6a8f4528c2f17f1c5d2d31fed62ec860f6006142e83e"},
+    {file = "aiohttp-3.8.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f88df3a83cf9df566f171adba39d5bd52814ac0b94778d2448652fc77f9eb491"},
+    {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97decbb3372d4b69e4d4c8117f44632551c692bb1361b356a02b97b69e18a62"},
+    {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309aa21c1d54b8ef0723181d430347d7452daaff93e8e2363db8e75c72c2fb2d"},
+    {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad5383a67514e8e76906a06741febd9126fc7c7ff0f599d6fcce3e82b80d026f"},
+    {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20acae4f268317bb975671e375493dbdbc67cddb5f6c71eebdb85b34444ac46b"},
+    {file = "aiohttp-3.8.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:05a3c31c6d7cd08c149e50dc7aa2568317f5844acd745621983380597f027a18"},
+    {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d6f76310355e9fae637c3162936e9504b4767d5c52ca268331e2756e54fd4ca5"},
+    {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:256deb4b29fe5e47893fa32e1de2d73c3afe7407738bd3c63829874661d4822d"},
+    {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:5c59fcd80b9049b49acd29bd3598cada4afc8d8d69bd4160cd613246912535d7"},
+    {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:059a91e88f2c00fe40aed9031b3606c3f311414f86a90d696dd982e7aec48142"},
+    {file = "aiohttp-3.8.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2feebbb6074cdbd1ac276dbd737b40e890a1361b3cc30b74ac2f5e24aab41f7b"},
+    {file = "aiohttp-3.8.3-cp310-cp310-win32.whl", hash = "sha256:5bf651afd22d5f0c4be16cf39d0482ea494f5c88f03e75e5fef3a85177fecdeb"},
+    {file = "aiohttp-3.8.3-cp310-cp310-win_amd64.whl", hash = "sha256:653acc3880459f82a65e27bd6526e47ddf19e643457d36a2250b85b41a564715"},
+    {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:86fc24e58ecb32aee09f864cb11bb91bc4c1086615001647dbfc4dc8c32f4008"},
+    {file = "aiohttp-3.8.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75e14eac916f024305db517e00a9252714fce0abcb10ad327fb6dcdc0d060f1d"},
+    {file = "aiohttp-3.8.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d1fde0f44029e02d02d3993ad55ce93ead9bb9b15c6b7ccd580f90bd7e3de476"},
+    {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ab94426ddb1ecc6a0b601d832d5d9d421820989b8caa929114811369673235c"},
+    {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89d2e02167fa95172c017732ed7725bc8523c598757f08d13c5acca308e1a061"},
+    {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9a2c72fc95d59b881cf38a4b2be9381b9527f9d328771e90f72ac76f31ad8"},
+    {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c7149272fb5834fc186328e2c1fa01dda3e1fa940ce18fded6d412e8f2cf76d"},
+    {file = "aiohttp-3.8.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:512bd5ab136b8dc0ffe3fdf2dfb0c4b4f49c8577f6cae55dca862cd37a4564e2"},
+    {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:7018ecc5fe97027214556afbc7c502fbd718d0740e87eb1217b17efd05b3d276"},
+    {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:88c70ed9da9963d5496d38320160e8eb7e5f1886f9290475a881db12f351ab5d"},
+    {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:da22885266bbfb3f78218dc40205fed2671909fbd0720aedba39b4515c038091"},
+    {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:e65bc19919c910127c06759a63747ebe14f386cda573d95bcc62b427ca1afc73"},
+    {file = "aiohttp-3.8.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:08c78317e950e0762c2983f4dd58dc5e6c9ff75c8a0efeae299d363d439c8e34"},
+    {file = "aiohttp-3.8.3-cp311-cp311-win32.whl", hash = "sha256:45d88b016c849d74ebc6f2b6e8bc17cabf26e7e40c0661ddd8fae4c00f015697"},
+    {file = "aiohttp-3.8.3-cp311-cp311-win_amd64.whl", hash = "sha256:96372fc29471646b9b106ee918c8eeb4cca423fcbf9a34daa1b93767a88a2290"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c971bf3786b5fad82ce5ad570dc6ee420f5b12527157929e830f51c55dc8af77"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ff25f48fc8e623d95eca0670b8cc1469a83783c924a602e0fbd47363bb54aaca"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e381581b37db1db7597b62a2e6b8b57c3deec95d93b6d6407c5b61ddc98aca6d"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db19d60d846283ee275d0416e2a23493f4e6b6028825b51290ac05afc87a6f97"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:25892c92bee6d9449ffac82c2fe257f3a6f297792cdb18ad784737d61e7a9a85"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398701865e7a9565d49189f6c90868efaca21be65c725fc87fc305906be915da"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:4a4fbc769ea9b6bd97f4ad0b430a6807f92f0e5eb020f1e42ece59f3ecfc4585"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:b29bfd650ed8e148f9c515474a6ef0ba1090b7a8faeee26b74a8ff3b33617502"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:1e56b9cafcd6531bab5d9b2e890bb4937f4165109fe98e2b98ef0dcfcb06ee9d"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:ec40170327d4a404b0d91855d41bfe1fe4b699222b2b93e3d833a27330a87a6d"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:2df5f139233060578d8c2c975128fb231a89ca0a462b35d4b5fcf7c501ebdbe1"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-win32.whl", hash = "sha256:f973157ffeab5459eefe7b97a804987876dd0a55570b8fa56b4e1954bf11329b"},
+    {file = "aiohttp-3.8.3-cp36-cp36m-win_amd64.whl", hash = "sha256:437399385f2abcd634865705bdc180c8314124b98299d54fe1d4c8990f2f9494"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:09e28f572b21642128ef31f4e8372adb6888846f32fecb288c8b0457597ba61a"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f3553510abdbec67c043ca85727396ceed1272eef029b050677046d3387be8d"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e168a7560b7c61342ae0412997b069753f27ac4862ec7867eff74f0fe4ea2ad9"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db4c979b0b3e0fa7e9e69ecd11b2b3174c6963cebadeecfb7ad24532ffcdd11a"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e164e0a98e92d06da343d17d4e9c4da4654f4a4588a20d6c73548a29f176abe2"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8a78079d9a39ca9ca99a8b0ac2fdc0c4d25fc80c8a8a82e5c8211509c523363"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:21b30885a63c3f4ff5b77a5d6caf008b037cb521a5f33eab445dc566f6d092cc"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4b0f30372cef3fdc262f33d06e7b411cd59058ce9174ef159ad938c4a34a89da"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:8135fa153a20d82ffb64f70a1b5c2738684afa197839b34cc3e3c72fa88d302c"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:ad61a9639792fd790523ba072c0555cd6be5a0baf03a49a5dd8cfcf20d56df48"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:978b046ca728073070e9abc074b6299ebf3501e8dee5e26efacb13cec2b2dea0"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-win32.whl", hash = "sha256:0d2c6d8c6872df4a6ec37d2ede71eff62395b9e337b4e18efd2177de883a5033"},
+    {file = "aiohttp-3.8.3-cp37-cp37m-win_amd64.whl", hash = "sha256:21d69797eb951f155026651f7e9362877334508d39c2fc37bd04ff55b2007091"},
+    {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ca9af5f8f5812d475c5259393f52d712f6d5f0d7fdad9acdb1107dd9e3cb7eb"},
+    {file = "aiohttp-3.8.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d90043c1882067f1bd26196d5d2db9aa6d268def3293ed5fb317e13c9413ea4"},
+    {file = "aiohttp-3.8.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d737fc67b9a970f3234754974531dc9afeea11c70791dcb7db53b0cf81b79784"},
+    {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebf909ea0a3fc9596e40d55d8000702a85e27fd578ff41a5500f68f20fd32e6c"},
+    {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5835f258ca9f7c455493a57ee707b76d2d9634d84d5d7f62e77be984ea80b849"},
+    {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da37dcfbf4b7f45d80ee386a5f81122501ec75672f475da34784196690762f4b"},
+    {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87f44875f2804bc0511a69ce44a9595d5944837a62caecc8490bbdb0e18b1342"},
+    {file = "aiohttp-3.8.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:527b3b87b24844ea7865284aabfab08eb0faf599b385b03c2aa91fc6edd6e4b6"},
+    {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5ba88df9aa5e2f806650fcbeedbe4f6e8736e92fc0e73b0400538fd25a4dd96"},
+    {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e7b8813be97cab8cb52b1375f41f8e6804f6507fe4660152e8ca5c48f0436017"},
+    {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:2dea10edfa1a54098703cb7acaa665c07b4e7568472a47f4e64e6319d3821ccf"},
+    {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:713d22cd9643ba9025d33c4af43943c7a1eb8547729228de18d3e02e278472b6"},
+    {file = "aiohttp-3.8.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2d252771fc85e0cf8da0b823157962d70639e63cb9b578b1dec9868dd1f4f937"},
+    {file = "aiohttp-3.8.3-cp38-cp38-win32.whl", hash = "sha256:66bd5f950344fb2b3dbdd421aaa4e84f4411a1a13fca3aeb2bcbe667f80c9f76"},
+    {file = "aiohttp-3.8.3-cp38-cp38-win_amd64.whl", hash = "sha256:84b14f36e85295fe69c6b9789b51a0903b774046d5f7df538176516c3e422446"},
+    {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:16c121ba0b1ec2b44b73e3a8a171c4f999b33929cd2397124a8c7fcfc8cd9e06"},
+    {file = "aiohttp-3.8.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8d6aaa4e7155afaf994d7924eb290abbe81a6905b303d8cb61310a2aba1c68ba"},
+    {file = "aiohttp-3.8.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43046a319664a04b146f81b40e1545d4c8ac7b7dd04c47e40bf09f65f2437346"},
+    {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:599418aaaf88a6d02a8c515e656f6faf3d10618d3dd95866eb4436520096c84b"},
+    {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:92a2964319d359f494f16011e23434f6f8ef0434acd3cf154a6b7bec511e2fb7"},
+    {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73a4131962e6d91109bca6536416aa067cf6c4efb871975df734f8d2fd821b37"},
+    {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:598adde339d2cf7d67beaccda3f2ce7c57b3b412702f29c946708f69cf8222aa"},
+    {file = "aiohttp-3.8.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75880ed07be39beff1881d81e4a907cafb802f306efd6d2d15f2b3c69935f6fb"},
+    {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0239da9fbafd9ff82fd67c16704a7d1bccf0d107a300e790587ad05547681c8"},
+    {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:4e3a23ec214e95c9fe85a58470b660efe6534b83e6cbe38b3ed52b053d7cb6ad"},
+    {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:47841407cc89a4b80b0c52276f3cc8138bbbfba4b179ee3acbd7d77ae33f7ac4"},
+    {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:54d107c89a3ebcd13228278d68f1436d3f33f2dd2af5415e3feaeb1156e1a62c"},
+    {file = "aiohttp-3.8.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c37c5cce780349d4d51739ae682dec63573847a2a8dcb44381b174c3d9c8d403"},
+    {file = "aiohttp-3.8.3-cp39-cp39-win32.whl", hash = "sha256:f178d2aadf0166be4df834c4953da2d7eef24719e8aec9a65289483eeea9d618"},
+    {file = "aiohttp-3.8.3-cp39-cp39-win_amd64.whl", hash = "sha256:88e5be56c231981428f4f506c68b6a46fa25c4123a2e86d156c58a8369d31ab7"},
+    {file = "aiohttp-3.8.3.tar.gz", hash = "sha256:3828fb41b7203176b82fe5d699e0d845435f2374750a44b480ea6b930f6be269"},
+]
 aiosignal = [
-    {file = "aiosignal-1.2.0-py3-none-any.whl", hash = "sha256:26e62109036cd181df6e6ad646f91f0dcfd05fe16d0cb924138ff2ab75d64e3a"},
-    {file = "aiosignal-1.2.0.tar.gz", hash = "sha256:78ed67db6c7b7ced4f98e495e572106d5c432a93e1ddd1bf475e1dc05f5b7df2"},
+    {file = "aiosignal-1.3.1-py3-none-any.whl", hash = "sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17"},
+    {file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
 ]
 alabaster = [
     {file = "alabaster-0.7.12-py2.py3-none-any.whl", hash = "sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359"},
@@ -2025,15 +2206,26 @@ appnope = [
     {file = "appnope-0.1.3-py2.py3-none-any.whl", hash = "sha256:265a455292d0bd8a72453494fa24df5a11eb18373a60c7c0430889f22548605e"},
     {file = "appnope-0.1.3.tar.gz", hash = "sha256:02bd91c4de869fbb1e1c50aafc4098827a7a54ab2f39d9dcba6c9547ed920e24"},
 ]
-astroid = []
-asttokens = []
+astroid = [
+    {file = "astroid-2.12.13-py3-none-any.whl", hash = "sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907"},
+    {file = "astroid-2.12.13.tar.gz", hash = "sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7"},
+]
+asttokens = [
+    {file = "asttokens-2.2.0-py2.py3-none-any.whl", hash = "sha256:c56caef774a929923696f09ceea0eadcb95c94b30e8ee4f9fc4f5867096caaeb"},
+    {file = "asttokens-2.2.0.tar.gz", hash = "sha256:e27b1f115daebfafd4d1826fc75f9a72f0b74bd3ae4ee4d9380406d74d35e52c"},
+]
 async-timeout = [
     {file = "async-timeout-4.0.2.tar.gz", hash = "sha256:2163e1640ddb52b7a8c80d0a67a08587e5d245cc9c553a74a847056bc2976b15"},
     {file = "async_timeout-4.0.2-py3-none-any.whl", hash = "sha256:8ca1e4fcf50d07413d66d1a5e416e42cfdf5851c981d679a09851a6853383b3c"},
 ]
-atomicwrites = []
-attrs = []
-babel = []
+attrs = [
+    {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
+    {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
+]
+babel = [
+    {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"},
+    {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"},
+]
 backcall = [
     {file = "backcall-0.2.0-py2.py3-none-any.whl", hash = "sha256:fbbce6a29f263178a1f7915c1940bde0ec2b2a967566fe1c65c1dfb7422bd255"},
     {file = "backcall-0.2.0.tar.gz", hash = "sha256:5cbdbf27be5e7cfadb448baf0aa95508f91f2bbc6c6437cd9cd06e2a4c215e1e"},
@@ -2042,28 +2234,250 @@ bandit = [
     {file = "bandit-1.7.4-py3-none-any.whl", hash = "sha256:412d3f259dab4077d0e7f0c11f50f650cc7d10db905d98f6520a95a18049658a"},
     {file = "bandit-1.7.4.tar.gz", hash = "sha256:2d63a8c573417bae338962d4b9b06fbc6080f74ecd955a092849e1e65c717bd2"},
 ]
-black = []
+black = [
+    {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"},
+    {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"},
+    {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"},
+    {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"},
+    {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"},
+    {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"},
+    {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"},
+    {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"},
+    {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"},
+    {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"},
+    {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"},
+    {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"},
+    {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"},
+    {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"},
+    {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"},
+    {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"},
+    {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"},
+    {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"},
+    {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"},
+    {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"},
+    {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"},
+]
 captum = [
     {file = "captum-0.5.0-py3-none-any.whl", hash = "sha256:b27996b4f7f0606d035ca210b723104ab209be55ca44bb65f46e036bcdf788e0"},
     {file = "captum-0.5.0.tar.gz", hash = "sha256:84af2c8793d34c440a351793b5ca705b8542745e2dc8bc24afb1d9b86f3bf6ec"},
 ]
-certifi = []
-cffi = []
+certifi = [
+    {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"},
+    {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"},
+]
+cffi = [
+    {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"},
+]
 cfgv = [
     {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"},
     {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"},
 ]
-charset-normalizer = []
+charset-normalizer = [
+    {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
+    {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
+]
 click = [
     {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
     {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
 ]
-colorama = []
+colorama = [
+    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
+    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
+]
+comm = [
+    {file = "comm-0.1.1-py3-none-any.whl", hash = "sha256:788a4ec961956c1cb2b0ba3c21f2458ff5757bb2f552032b140787af88d670a3"},
+    {file = "comm-0.1.1.tar.gz", hash = "sha256:f395ea64f4f261f35ffc2fbf80a62ec071375dac48cd3ea56092711e74dd063e"},
+]
 commonmark = [
     {file = "commonmark-0.9.1-py2.py3-none-any.whl", hash = "sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9"},
     {file = "commonmark-0.9.1.tar.gz", hash = "sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60"},
 ]
-contourpy = []
+contourpy = [
+    {file = "contourpy-1.0.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:613c665529899b5d9fade7e5d1760111a0b011231277a0d36c49f0d3d6914bd6"},
+    {file = "contourpy-1.0.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:78ced51807ccb2f45d4ea73aca339756d75d021069604c2fccd05390dc3c28eb"},
+    {file = "contourpy-1.0.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b3b1bd7577c530eaf9d2bc52d1a93fef50ac516a8b1062c3d1b9bcec9ebe329b"},
+    {file = "contourpy-1.0.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8834c14b8c3dd849005e06703469db9bf96ba2d66a3f88ecc539c9a8982e0ee"},
+    {file = "contourpy-1.0.6-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f4052a8a4926d4468416fc7d4b2a7b2a3e35f25b39f4061a7e2a3a2748c4fc48"},
+    {file = "contourpy-1.0.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c0e1308307a75e07d1f1b5f0f56b5af84538a5e9027109a7bcf6cb47c434e72"},
+    {file = "contourpy-1.0.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9fc4e7973ed0e1fe689435842a6e6b330eb7ccc696080dda9a97b1a1b78e41db"},
+    {file = "contourpy-1.0.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:08e8d09d96219ace6cb596506fb9b64ea5f270b2fb9121158b976d88871fcfd1"},
+    {file = "contourpy-1.0.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f33da6b5d19ad1bb5e7ad38bb8ba5c426d2178928bc2b2c44e8823ea0ecb6ff3"},
+    {file = "contourpy-1.0.6-cp310-cp310-win32.whl", hash = "sha256:12a7dc8439544ed05c6553bf026d5e8fa7fad48d63958a95d61698df0e00092b"},
+    {file = "contourpy-1.0.6-cp310-cp310-win_amd64.whl", hash = "sha256:eadad75bf91897f922e0fb3dca1b322a58b1726a953f98c2e5f0606bd8408621"},
+    {file = "contourpy-1.0.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:913bac9d064cff033cf3719e855d4f1db9f1c179e0ecf3ba9fdef21c21c6a16a"},
+    {file = "contourpy-1.0.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46deb310a276cc5c1fd27958e358cce68b1e8a515fa5a574c670a504c3a3fe30"},
+    {file = "contourpy-1.0.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b64f747e92af7da3b85631a55d68c45a2d728b4036b03cdaba4bd94bcc85bd6f"},
+    {file = "contourpy-1.0.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50627bf76abb6ba291ad08db583161939c2c5fab38c38181b7833423ab9c7de3"},
+    {file = "contourpy-1.0.6-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:358f6364e4873f4d73360b35da30066f40387dd3c427a3e5432c6b28dd24a8fa"},
+    {file = "contourpy-1.0.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c78bfbc1a7bff053baf7e508449d2765964d67735c909b583204e3240a2aca45"},
+    {file = "contourpy-1.0.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e43255a83835a129ef98f75d13d643844d8c646b258bebd11e4a0975203e018f"},
+    {file = "contourpy-1.0.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:375d81366afd547b8558c4720337218345148bc2fcffa3a9870cab82b29667f2"},
+    {file = "contourpy-1.0.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b98c820608e2dca6442e786817f646d11057c09a23b68d2b3737e6dcb6e4a49b"},
+    {file = "contourpy-1.0.6-cp311-cp311-win32.whl", hash = "sha256:0e4854cc02006ad6684ce092bdadab6f0912d131f91c2450ce6dbdea78ee3c0b"},
+    {file = "contourpy-1.0.6-cp311-cp311-win_amd64.whl", hash = "sha256:d2eff2af97ea0b61381828b1ad6cd249bbd41d280e53aea5cccd7b2b31b8225c"},
+    {file = "contourpy-1.0.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5b117d29433fc8393b18a696d794961464e37afb34a6eeb8b2c37b5f4128a83e"},
+    {file = "contourpy-1.0.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:341330ed19074f956cb20877ad8d2ae50e458884bfa6a6df3ae28487cc76c768"},
+    {file = "contourpy-1.0.6-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:371f6570a81dfdddbb837ba432293a63b4babb942a9eb7aaa699997adfb53278"},
+    {file = "contourpy-1.0.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9447c45df407d3ecb717d837af3b70cfef432138530712263730783b3d016512"},
+    {file = "contourpy-1.0.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:730c27978a0003b47b359935478b7d63fd8386dbb2dcd36c1e8de88cbfc1e9de"},
+    {file = "contourpy-1.0.6-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:da1ef35fd79be2926ba80fbb36327463e3656c02526e9b5b4c2b366588b74d9a"},
+    {file = "contourpy-1.0.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd2bc0c8f2e8de7dd89a7f1c10b8844e291bca17d359373203ef2e6100819edd"},
+    {file = "contourpy-1.0.6-cp37-cp37m-win32.whl", hash = "sha256:3a1917d3941dd58732c449c810fa7ce46cc305ce9325a11261d740118b85e6f3"},
+    {file = "contourpy-1.0.6-cp37-cp37m-win_amd64.whl", hash = "sha256:06ca79e1efbbe2df795822df2fa173d1a2b38b6e0f047a0ec7903fbca1d1847e"},
+    {file = "contourpy-1.0.6-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e626cefff8491bce356221c22af5a3ea528b0b41fbabc719c00ae233819ea0bf"},
+    {file = "contourpy-1.0.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:dbe6fe7a1166b1ddd7b6d887ea6fa8389d3f28b5ed3f73a8f40ece1fc5a3d340"},
+    {file = "contourpy-1.0.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e13b31d1b4b68db60b3b29f8e337908f328c7f05b9add4b1b5c74e0691180109"},
+    {file = "contourpy-1.0.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a79d239fc22c3b8d9d3de492aa0c245533f4f4c7608e5749af866949c0f1b1b9"},
+    {file = "contourpy-1.0.6-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e8e686a6db92a46111a1ee0ee6f7fbfae4048f0019de207149f43ac1812cf95"},
+    {file = "contourpy-1.0.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2bd02f1a7adff3a1f33e431eb96ab6d7987b039d2946a9b39fe6fb16a1036"},
+    {file = "contourpy-1.0.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:03d1b9c6b44a9e30d554654c72be89af94fab7510b4b9f62356c64c81cec8b7d"},
+    {file = "contourpy-1.0.6-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b48d94386f1994db7c70c76b5808c12e23ed7a4ee13693c2fc5ab109d60243c0"},
+    {file = "contourpy-1.0.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:208bc904889c910d95aafcf7be9e677726df9ef71e216780170dbb7e37d118fa"},
+    {file = "contourpy-1.0.6-cp38-cp38-win32.whl", hash = "sha256:444fb776f58f4906d8d354eb6f6ce59d0a60f7b6a720da6c1ccb839db7c80eb9"},
+    {file = "contourpy-1.0.6-cp38-cp38-win_amd64.whl", hash = "sha256:9bc407a6af672da20da74823443707e38ece8b93a04009dca25856c2d9adadb1"},
+    {file = "contourpy-1.0.6-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:aa4674cf3fa2bd9c322982644967f01eed0c91bb890f624e0e0daf7a5c3383e9"},
+    {file = "contourpy-1.0.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6f56515e7c6fae4529b731f6c117752247bef9cdad2b12fc5ddf8ca6a50965a5"},
+    {file = "contourpy-1.0.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:344cb3badf6fc7316ad51835f56ac387bdf86c8e1b670904f18f437d70da4183"},
+    {file = "contourpy-1.0.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b1e66346acfb17694d46175a0cea7d9036f12ed0c31dfe86f0f405eedde2bdd"},
+    {file = "contourpy-1.0.6-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8468b40528fa1e15181cccec4198623b55dcd58306f8815a793803f51f6c474a"},
+    {file = "contourpy-1.0.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dedf4c64185a216c35eb488e6f433297c660321275734401760dafaeb0ad5c2"},
+    {file = "contourpy-1.0.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:494efed2c761f0f37262815f9e3c4bb9917c5c69806abdee1d1cb6611a7174a0"},
+    {file = "contourpy-1.0.6-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:75a2e638042118118ab39d337da4c7908c1af74a8464cad59f19fbc5bbafec9b"},
+    {file = "contourpy-1.0.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a628bba09ba72e472bf7b31018b6281fd4cc903f0888049a3724afba13b6e0b8"},
+    {file = "contourpy-1.0.6-cp39-cp39-win32.whl", hash = "sha256:e1739496c2f0108013629aa095cc32a8c6363444361960c07493818d0dea2da4"},
+    {file = "contourpy-1.0.6-cp39-cp39-win_amd64.whl", hash = "sha256:a457ee72d9032e86730f62c5eeddf402e732fdf5ca8b13b41772aa8ae13a4563"},
+    {file = "contourpy-1.0.6-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d912f0154a20a80ea449daada904a7eb6941c83281a9fab95de50529bfc3a1da"},
+    {file = "contourpy-1.0.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4081918147fc4c29fad328d5066cfc751da100a1098398742f9f364be63803fc"},
+    {file = "contourpy-1.0.6-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0537cc1195245bbe24f2913d1f9211b8f04eb203de9044630abd3664c6cc339c"},
+    {file = "contourpy-1.0.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcd556c8fc37a342dd636d7eef150b1399f823a4462f8c968e11e1ebeabee769"},
+    {file = "contourpy-1.0.6-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:f6ca38dd8d988eca8f07305125dec6f54ac1c518f1aaddcc14d08c01aebb6efc"},
+    {file = "contourpy-1.0.6-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c1baa49ab9fedbf19d40d93163b7d3e735d9cd8d5efe4cce9907902a6dad391f"},
+    {file = "contourpy-1.0.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:211dfe2bd43bf5791d23afbe23a7952e8ac8b67591d24be3638cabb648b3a6eb"},
+    {file = "contourpy-1.0.6-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c38c6536c2d71ca2f7e418acaf5bca30a3af7f2a2fa106083c7d738337848dbe"},
+    {file = "contourpy-1.0.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b1ee48a130da4dd0eb8055bbab34abf3f6262957832fd575e0cab4979a15a41"},
+    {file = "contourpy-1.0.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5641927cc5ae66155d0c80195dc35726eae060e7defc18b7ab27600f39dd1fe7"},
+    {file = "contourpy-1.0.6-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:7ee394502026d68652c2824348a40bf50f31351a668977b51437131a90d777ea"},
+    {file = "contourpy-1.0.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b97454ed5b1368b66ed414c754cba15b9750ce69938fc6153679787402e4cdf"},
+    {file = "contourpy-1.0.6-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0236875c5a0784215b49d00ebbe80c5b6b5d5244b3655a36dda88105334dea17"},
+    {file = "contourpy-1.0.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:84c593aeff7a0171f639da92cb86d24954bbb61f8a1b530f74eb750a14685832"},
+    {file = "contourpy-1.0.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:9b0e7fe7f949fb719b206548e5cde2518ffb29936afa4303d8a1c4db43dcb675"},
+    {file = "contourpy-1.0.6.tar.gz", hash = "sha256:6e459ebb8bb5ee4c22c19cc000174f8059981971a33ce11e17dddf6aca97a142"},
+]
+coverage = [
+    {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"},
+    {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"},
+    {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"},
+    {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"},
+    {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"},
+    {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"},
+    {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"},
+    {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"},
+    {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"},
+    {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"},
+    {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"},
+    {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"},
+    {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"},
+    {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"},
+    {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"},
+    {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"},
+    {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"},
+    {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"},
+    {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"},
+    {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"},
+    {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"},
+    {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"},
+    {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"},
+    {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"},
+    {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"},
+    {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"},
+    {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"},
+    {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"},
+    {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"},
+    {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"},
+    {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"},
+    {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"},
+    {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"},
+    {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"},
+    {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"},
+    {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"},
+    {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"},
+    {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"},
+    {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"},
+    {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"},
+    {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"},
+    {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"},
+    {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"},
+    {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"},
+    {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"},
+    {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"},
+    {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"},
+    {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"},
+    {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"},
+    {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"},
+]
 cycler = [
     {file = "cycler-0.11.0-py3-none-any.whl", hash = "sha256:3a27e95f763a428a739d2add979fa7494c912a32c17c4c38c4d5f082cad165a3"},
     {file = "cycler-0.11.0.tar.gz", hash = "sha256:9c87405839a19696e837b3b818fed3f5f69f16f1eec1a1ad77e043dcea9c772f"},
@@ -2072,75 +2486,325 @@ darglint = [
     {file = "darglint-1.8.1-py3-none-any.whl", hash = "sha256:5ae11c259c17b0701618a20c3da343a3eb98b3bc4b5a83d31cdd94f5ebdced8d"},
     {file = "darglint-1.8.1.tar.gz", hash = "sha256:080d5106df149b199822e7ee7deb9c012b49891538f14a11be681044f0bb20da"},
 ]
-datasets = []
-debugpy = []
+datasets = [
+    {file = "datasets-2.7.1-py3-none-any.whl", hash = "sha256:3d0d2e860cec7c4e77c40de64533d46853f939b6e2311cba4f483f000afae868"},
+    {file = "datasets-2.7.1.tar.gz", hash = "sha256:1c79a982d9d9c75fbbaea5b177c2b4c56894289b647fa2845ae2ebd8ac638a0f"},
+]
+debugpy = [
+    {file = "debugpy-1.6.4-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:6ae238943482c78867ac707c09122688efb700372b617ffd364261e5e41f7a2f"},
+    {file = "debugpy-1.6.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2a39e7da178e1f22f4bc04b57f085e785ed1bcf424aaf318835a1a7129eefe35"},
+    {file = "debugpy-1.6.4-cp310-cp310-win32.whl", hash = "sha256:143f79d0798a9acea21cd1d111badb789f19d414aec95fa6389cfea9485ddfb1"},
+    {file = "debugpy-1.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:563f148f94434365ec0ce94739c749aabf60bf67339e68a9446499f3582d62f3"},
+    {file = "debugpy-1.6.4-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:1caee68f7e254267df908576c0d0938f8f88af16383f172cb9f0602e24c30c01"},
+    {file = "debugpy-1.6.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40e2a83d31a16b83666f19fa06d97b2cc311af88e6266590579737949971a17e"},
+    {file = "debugpy-1.6.4-cp37-cp37m-win32.whl", hash = "sha256:82229790442856962aec4767b98ba2559fe0998f897e9f21fb10b4fd24b6c436"},
+    {file = "debugpy-1.6.4-cp37-cp37m-win_amd64.whl", hash = "sha256:67edf033f9e512958f7b472975ff9d9b7ff64bf4440f6f6ae44afdc66b89e6b6"},
+    {file = "debugpy-1.6.4-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:4ab5e938925e5d973f567d6ef32751b17d10f3be3a8c4d73c52f53e727f69bf1"},
+    {file = "debugpy-1.6.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8df268e9f72fc06efc2e75e8dc8e2b881d6a397356faec26efb2ee70b6863b7"},
+    {file = "debugpy-1.6.4-cp38-cp38-win32.whl", hash = "sha256:86bd25f38f8b6c5d430a5e2931eebbd5f580c640f4819fcd236d0498790c7204"},
+    {file = "debugpy-1.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:62ba4179b372a62abf9c89b56997d70a4100c6dea6c2a4e0e4be5f45920b3253"},
+    {file = "debugpy-1.6.4-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d2968e589bda4e485a9c61f113754a28e48d88c5152ed8e0b2564a1fadbe50a5"},
+    {file = "debugpy-1.6.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e62b8034ede98932b92268669318848a0d42133d857087a3b9cec03bb844c615"},
+    {file = "debugpy-1.6.4-cp39-cp39-win32.whl", hash = "sha256:3d9c31baf64bf959a593996c108e911c5a9aa1693a296840e5469473f064bcec"},
+    {file = "debugpy-1.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:ea4bf208054e6d41749f17612066da861dff10102729d32c85b47f155223cf2b"},
+    {file = "debugpy-1.6.4-py2.py3-none-any.whl", hash = "sha256:e886a1296cd20a10172e94788009ce74b759e54229ebd64a43fa5c2b4e62cd76"},
+    {file = "debugpy-1.6.4.zip", hash = "sha256:d5ab9bd3f4e7faf3765fd52c7c43c074104ab1e109621dc73219099ed1a5399d"},
+]
 decorator = [
     {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
     {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
 ]
 dill = [
-    {file = "dill-0.3.5.1-py2.py3-none-any.whl", hash = "sha256:33501d03270bbe410c72639b350e941882a8b0fd55357580fbc873fba0c59302"},
-    {file = "dill-0.3.5.1.tar.gz", hash = "sha256:d75e41f3eff1eee599d738e76ba8f4ad98ea229db8b085318aa2b3333a208c86"},
+    {file = "dill-0.3.6-py3-none-any.whl", hash = "sha256:a07ffd2351b8c678dfc4a856a3005f8067aea51d6ba6c700796a4d9e280f39f0"},
+    {file = "dill-0.3.6.tar.gz", hash = "sha256:e5db55f3687856d8fbdab002ed78544e1c4559a130302693d839dfe8f93f2373"},
+]
+distlib = [
+    {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"},
+    {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"},
 ]
-distlib = []
 docutils = [
     {file = "docutils-0.17.1-py2.py3-none-any.whl", hash = "sha256:cf316c8370a737a022b72b56874f6602acf974a37a9fba42ec2876387549fc61"},
     {file = "docutils-0.17.1.tar.gz", hash = "sha256:686577d2e4c32380bb50cbb22f575ed742d58168cee37e99117a854bcd88f125"},
 ]
-dparse = []
+dparse = [
+    {file = "dparse-0.6.2-py3-none-any.whl", hash = "sha256:8097076f1dd26c377f30d4745e6ec18fef42f3bf493933b842ac5bafad8c345f"},
+    {file = "dparse-0.6.2.tar.gz", hash = "sha256:d45255bda21f998bc7ddf2afd5e62505ba6134756ba2d42a84c56b0826614dfe"},
+]
 entrypoints = [
     {file = "entrypoints-0.4-py3-none-any.whl", hash = "sha256:f174b5ff827504fd3cd97cc3f8649f3693f51538c7e4bdf3ef002c8429d42f9f"},
     {file = "entrypoints-0.4.tar.gz", hash = "sha256:b706eddaa9218a19ebcd67b56818f05bb27589b1ca9e8d797b74affad4ccacd4"},
 ]
-executing = []
-filelock = []
+exceptiongroup = [
+    {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"},
+    {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"},
+]
+executing = [
+    {file = "executing-1.2.0-py2.py3-none-any.whl", hash = "sha256:0314a69e37426e3608aada02473b4161d4caf5a4b244d1d0c48072b8fee7bacc"},
+    {file = "executing-1.2.0.tar.gz", hash = "sha256:19da64c18d2d851112f09c287f8d3dbbdf725ab0e569077efb6cdcbd3497c107"},
+]
+filelock = [
+    {file = "filelock-3.8.0-py3-none-any.whl", hash = "sha256:617eb4e5eedc82fc5f47b6d61e4d11cb837c56cb4544e39081099fa17ad109d4"},
+    {file = "filelock-3.8.0.tar.gz", hash = "sha256:55447caa666f2198c5b6b13a26d2084d26fa5b115c00d065664b2124680c4edc"},
+]
 flake8 = [
-    {file = "flake8-4.0.1-py2.py3-none-any.whl", hash = "sha256:479b1304f72536a55948cb40a32dce8bb0ffe3501e26eaf292c7e60eb5e0428d"},
-    {file = "flake8-4.0.1.tar.gz", hash = "sha256:806e034dda44114815e23c16ef92f95c91e4c71100ff52813adf7132a6ad870d"},
+    {file = "flake8-6.0.0-py2.py3-none-any.whl", hash = "sha256:3833794e27ff64ea4e9cf5d410082a8b97ff1a06c16aa3d2027339cd0f1195c7"},
+    {file = "flake8-6.0.0.tar.gz", hash = "sha256:c61007e76655af75e6785a931f452915b371dc48f56efd765247c8fe68f2b181"},
+]
+fonttools = [
+    {file = "fonttools-4.38.0-py3-none-any.whl", hash = "sha256:820466f43c8be8c3009aef8b87e785014133508f0de64ec469e4efb643ae54fb"},
+    {file = "fonttools-4.38.0.zip", hash = "sha256:2bb244009f9bf3fa100fc3ead6aeb99febe5985fa20afbfbaa2f8946c2fbdaf1"},
+]
+frozenlist = [
+    {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff8bf625fe85e119553b5383ba0fb6aa3d0ec2ae980295aaefa552374926b3f4"},
+    {file = "frozenlist-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dfbac4c2dfcc082fcf8d942d1e49b6aa0766c19d3358bd86e2000bf0fa4a9cf0"},
+    {file = "frozenlist-1.3.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1c63e8d377d039ac769cd0926558bb7068a1f7abb0f003e3717ee003ad85530"},
+    {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7fdfc24dcfce5b48109867c13b4cb15e4660e7bd7661741a391f821f23dfdca7"},
+    {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2c926450857408e42f0bbc295e84395722ce74bae69a3b2aa2a65fe22cb14b99"},
+    {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1841e200fdafc3d51f974d9d377c079a0694a8f06de2e67b48150328d66d5483"},
+    {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f470c92737afa7d4c3aacc001e335062d582053d4dbe73cda126f2d7031068dd"},
+    {file = "frozenlist-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:783263a4eaad7c49983fe4b2e7b53fa9770c136c270d2d4bbb6d2192bf4d9caf"},
+    {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:924620eef691990dfb56dc4709f280f40baee568c794b5c1885800c3ecc69816"},
+    {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:ae4dc05c465a08a866b7a1baf360747078b362e6a6dbeb0c57f234db0ef88ae0"},
+    {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:bed331fe18f58d844d39ceb398b77d6ac0b010d571cba8267c2e7165806b00ce"},
+    {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:02c9ac843e3390826a265e331105efeab489ffaf4dd86384595ee8ce6d35ae7f"},
+    {file = "frozenlist-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9545a33965d0d377b0bc823dcabf26980e77f1b6a7caa368a365a9497fb09420"},
+    {file = "frozenlist-1.3.3-cp310-cp310-win32.whl", hash = "sha256:d5cd3ab21acbdb414bb6c31958d7b06b85eeb40f66463c264a9b343a4e238642"},
+    {file = "frozenlist-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:b756072364347cb6aa5b60f9bc18e94b2f79632de3b0190253ad770c5df17db1"},
+    {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b4395e2f8d83fbe0c627b2b696acce67868793d7d9750e90e39592b3626691b7"},
+    {file = "frozenlist-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:14143ae966a6229350021384870458e4777d1eae4c28d1a7aa47f24d030e6678"},
+    {file = "frozenlist-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5d8860749e813a6f65bad8285a0520607c9500caa23fea6ee407e63debcdbef6"},
+    {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23d16d9f477bb55b6154654e0e74557040575d9d19fe78a161bd33d7d76808e8"},
+    {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb82dbba47a8318e75f679690190c10a5e1f447fbf9df41cbc4c3afd726d88cb"},
+    {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9309869032abb23d196cb4e4db574232abe8b8be1339026f489eeb34a4acfd91"},
+    {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a97b4fe50b5890d36300820abd305694cb865ddb7885049587a5678215782a6b"},
+    {file = "frozenlist-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c188512b43542b1e91cadc3c6c915a82a5eb95929134faf7fd109f14f9892ce4"},
+    {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:303e04d422e9b911a09ad499b0368dc551e8c3cd15293c99160c7f1f07b59a48"},
+    {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:0771aed7f596c7d73444c847a1c16288937ef988dc04fb9f7be4b2aa91db609d"},
+    {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:66080ec69883597e4d026f2f71a231a1ee9887835902dbe6b6467d5a89216cf6"},
+    {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:41fe21dc74ad3a779c3d73a2786bdf622ea81234bdd4faf90b8b03cad0c2c0b4"},
+    {file = "frozenlist-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f20380df709d91525e4bee04746ba612a4df0972c1b8f8e1e8af997e678c7b81"},
+    {file = "frozenlist-1.3.3-cp311-cp311-win32.whl", hash = "sha256:f30f1928162e189091cf4d9da2eac617bfe78ef907a761614ff577ef4edfb3c8"},
+    {file = "frozenlist-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a6394d7dadd3cfe3f4b3b186e54d5d8504d44f2d58dcc89d693698e8b7132b32"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8df3de3a9ab8325f94f646609a66cbeeede263910c5c0de0101079ad541af332"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0693c609e9742c66ba4870bcee1ad5ff35462d5ffec18710b4ac89337ff16e27"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd4210baef299717db0a600d7a3cac81d46ef0e007f88c9335db79f8979c0d3d"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:394c9c242113bfb4b9aa36e2b80a05ffa163a30691c7b5a29eba82e937895d5e"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6327eb8e419f7d9c38f333cde41b9ae348bec26d840927332f17e887a8dcb70d"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e24900aa13212e75e5b366cb9065e78bbf3893d4baab6052d1aca10d46d944c"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3843f84a6c465a36559161e6c59dce2f2ac10943040c2fd021cfb70d58c4ad56"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:84610c1502b2461255b4c9b7d5e9c48052601a8957cd0aea6ec7a7a1e1fb9420"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:c21b9aa40e08e4f63a2f92ff3748e6b6c84d717d033c7b3438dd3123ee18f70e"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:efce6ae830831ab6a22b9b4091d411698145cb9b8fc869e1397ccf4b4b6455cb"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:40de71985e9042ca00b7953c4f41eabc3dc514a2d1ff534027f091bc74416401"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:180c00c66bde6146a860cbb81b54ee0df350d2daf13ca85b275123bbf85de18a"},
+    {file = "frozenlist-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9bbbcedd75acdfecf2159663b87f1bb5cfc80e7cd99f7ddd9d66eb98b14a8411"},
+    {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:034a5c08d36649591be1cbb10e09da9f531034acfe29275fc5454a3b101ce41a"},
+    {file = "frozenlist-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ba64dc2b3b7b158c6660d49cdb1d872d1d0bf4e42043ad8d5006099479a194e5"},
+    {file = "frozenlist-1.3.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:47df36a9fe24054b950bbc2db630d508cca3aa27ed0566c0baf661225e52c18e"},
+    {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:008a054b75d77c995ea26629ab3a0c0d7281341f2fa7e1e85fa6153ae29ae99c"},
+    {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:841ea19b43d438a80b4de62ac6ab21cfe6827bb8a9dc62b896acc88eaf9cecba"},
+    {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e235688f42b36be2b6b06fc37ac2126a73b75fb8d6bc66dd632aa35286238703"},
+    {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca713d4af15bae6e5d79b15c10c8522859a9a89d3b361a50b817c98c2fb402a2"},
+    {file = "frozenlist-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ac5995f2b408017b0be26d4a1d7c61bce106ff3d9e3324374d66b5964325448"},
+    {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a4ae8135b11652b08a8baf07631d3ebfe65a4c87909dbef5fa0cdde440444ee4"},
+    {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:4ea42116ceb6bb16dbb7d526e242cb6747b08b7710d9782aa3d6732bd8d27649"},
+    {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:810860bb4bdce7557bc0febb84bbd88198b9dbc2022d8eebe5b3590b2ad6c842"},
+    {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:ee78feb9d293c323b59a6f2dd441b63339a30edf35abcb51187d2fc26e696d13"},
+    {file = "frozenlist-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0af2e7c87d35b38732e810befb9d797a99279cbb85374d42ea61c1e9d23094b3"},
+    {file = "frozenlist-1.3.3-cp38-cp38-win32.whl", hash = "sha256:899c5e1928eec13fd6f6d8dc51be23f0d09c5281e40d9cf4273d188d9feeaf9b"},
+    {file = "frozenlist-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:7f44e24fa70f6fbc74aeec3e971f60a14dde85da364aa87f15d1be94ae75aeef"},
+    {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2b07ae0c1edaa0a36339ec6cce700f51b14a3fc6545fdd32930d2c83917332cf"},
+    {file = "frozenlist-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:ebb86518203e12e96af765ee89034a1dbb0c3c65052d1b0c19bbbd6af8a145e1"},
+    {file = "frozenlist-1.3.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5cf820485f1b4c91e0417ea0afd41ce5cf5965011b3c22c400f6d144296ccbc0"},
+    {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c11e43016b9024240212d2a65043b70ed8dfd3b52678a1271972702d990ac6d"},
+    {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8fa3c6e3305aa1146b59a09b32b2e04074945ffcfb2f0931836d103a2c38f936"},
+    {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:352bd4c8c72d508778cf05ab491f6ef36149f4d0cb3c56b1b4302852255d05d5"},
+    {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65a5e4d3aa679610ac6e3569e865425b23b372277f89b5ef06cf2cdaf1ebf22b"},
+    {file = "frozenlist-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1e2c1185858d7e10ff045c496bbf90ae752c28b365fef2c09cf0fa309291669"},
+    {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f163d2fd041c630fed01bc48d28c3ed4a3b003c00acd396900e11ee5316b56bb"},
+    {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:05cdb16d09a0832eedf770cb7bd1fe57d8cf4eaf5aced29c4e41e3f20b30a784"},
+    {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:8bae29d60768bfa8fb92244b74502b18fae55a80eac13c88eb0b496d4268fd2d"},
+    {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:eedab4c310c0299961ac285591acd53dc6723a1ebd90a57207c71f6e0c2153ab"},
+    {file = "frozenlist-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3bbdf44855ed8f0fbcd102ef05ec3012d6a4fd7c7562403f76ce6a52aeffb2b1"},
+    {file = "frozenlist-1.3.3-cp39-cp39-win32.whl", hash = "sha256:efa568b885bca461f7c7b9e032655c0c143d305bf01c30caf6db2854a4532b38"},
+    {file = "frozenlist-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfe33efc9cb900a4c46f91a5ceba26d6df370ffddd9ca386eb1d4f0ad97b9ea9"},
+    {file = "frozenlist-1.3.3.tar.gz", hash = "sha256:58bcc55721e8a90b88332d6cd441261ebb22342e238296bb330968952fbb3a6a"},
+]
+fsspec = [
+    {file = "fsspec-2022.11.0-py3-none-any.whl", hash = "sha256:d6e462003e3dcdcb8c7aa84c73a228f8227e72453cd22570e2363e8844edfe7b"},
+    {file = "fsspec-2022.11.0.tar.gz", hash = "sha256:259d5fd5c8e756ff2ea72f42e7613c32667dc2049a4ac3d84364a7ca034acb8b"},
 ]
-fonttools = []
-frozenlist = []
-fsspec = []
 gitdb = [
-    {file = "gitdb-4.0.9-py3-none-any.whl", hash = "sha256:8033ad4e853066ba6ca92050b9df2f89301b8fc8bf7e9324d412a63f8bf1a8fd"},
-    {file = "gitdb-4.0.9.tar.gz", hash = "sha256:bac2fd45c0a1c9cf619e63a90d62bdc63892ef92387424b855792a6cabe789aa"},
-]
-gitpython = []
-huggingface-hub = []
-identify = []
-idna = []
-imagesize = []
-importlib-metadata = []
+    {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"},
+    {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"},
+]
+gitpython = [
+    {file = "GitPython-3.1.29-py3-none-any.whl", hash = "sha256:41eea0deec2deea139b459ac03656f0dd28fc4a3387240ec1d3c259a2c47850f"},
+    {file = "GitPython-3.1.29.tar.gz", hash = "sha256:cc36bfc4a3f913e66805a28e84703e419d9c264c1077e537b54f0e1af85dbefd"},
+]
+huggingface-hub = [
+    {file = "huggingface_hub-0.11.1-py3-none-any.whl", hash = "sha256:11eed7aab4fa4d1fb532f2aea3379ef4998d9f6bc24a330834dfedd3dac7f441"},
+    {file = "huggingface_hub-0.11.1.tar.gz", hash = "sha256:8b9ebf9bbb1782f6f0419ec490973a6487c6c4ed84293a8a325d34c4f898f53f"},
+]
+identify = [
+    {file = "identify-2.5.9-py2.py3-none-any.whl", hash = "sha256:a390fb696e164dbddb047a0db26e57972ae52fbd037ae68797e5ae2f4492485d"},
+    {file = "identify-2.5.9.tar.gz", hash = "sha256:906036344ca769539610436e40a684e170c3648b552194980bb7b617a8daeb9f"},
+]
+idna = [
+    {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
+    {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+]
+imagesize = [
+    {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"},
+    {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"},
+]
+importlib-metadata = [
+    {file = "importlib_metadata-5.1.0-py3-none-any.whl", hash = "sha256:d84d17e21670ec07990e1044a99efe8d615d860fd176fc29ef5c306068fda313"},
+    {file = "importlib_metadata-5.1.0.tar.gz", hash = "sha256:d5059f9f1e8e41f80e9c56c2ee58811450c31984dfa625329ffd7c0dad88a73b"},
+]
 iniconfig = [
     {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
     {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
 ]
-ipykernel = []
-ipython = []
-ipywidgets = []
+ipykernel = [
+    {file = "ipykernel-6.18.2-py3-none-any.whl", hash = "sha256:4ae64026a3cca0e1843d0fccce6690d7fda2b05267e4609547185797de999823"},
+    {file = "ipykernel-6.18.2.tar.gz", hash = "sha256:53714bb8b2207fda4a9fac645460c38612e04b63be34b4ba70febbebc8cfc4a0"},
+]
+ipython = [
+    {file = "ipython-8.7.0-py3-none-any.whl", hash = "sha256:352042ddcb019f7c04e48171b4dd78e4c4bb67bf97030d170e154aac42b656d9"},
+    {file = "ipython-8.7.0.tar.gz", hash = "sha256:882899fe78d5417a0aa07f995db298fa28b58faeba2112d2e3a4c95fe14bb738"},
+]
+ipywidgets = [
+    {file = "ipywidgets-8.0.2-py3-none-any.whl", hash = "sha256:1dc3dd4ee19ded045ea7c86eb273033d238d8e43f9e7872c52d092683f263891"},
+    {file = "ipywidgets-8.0.2.tar.gz", hash = "sha256:08cb75c6e0a96836147cbfdc55580ae04d13e05d26ffbc377b4e1c68baa28b1f"},
+]
 isort = [
     {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
     {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
 ]
 jedi = [
-    {file = "jedi-0.18.1-py2.py3-none-any.whl", hash = "sha256:637c9635fcf47945ceb91cd7f320234a7be540ded6f3e99a50cb6febdfd1ba8d"},
-    {file = "jedi-0.18.1.tar.gz", hash = "sha256:74137626a64a99c8eb6ae5832d99b3bdd7d29a3850fe2aa80a4126b2a7d949ab"},
+    {file = "jedi-0.18.2-py2.py3-none-any.whl", hash = "sha256:203c1fd9d969ab8f2119ec0a3342e0b49910045abe6af0a3ae83a5764d54639e"},
+    {file = "jedi-0.18.2.tar.gz", hash = "sha256:bae794c30d07f6d910d32a7048af09b5a39ed740918da923c6b780790ebac612"},
 ]
 jinja2 = [
     {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
     {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
 ]
-joblib = []
+joblib = [
+    {file = "joblib-1.2.0-py3-none-any.whl", hash = "sha256:091138ed78f800342968c523bdde947e7a305b8594b910a0fea2ab83c3c6d385"},
+    {file = "joblib-1.2.0.tar.gz", hash = "sha256:e1cee4a79e4af22881164f218d4311f60074197fb707e082e803b61f6d137018"},
+]
 json-tricks = [
-    {file = "json_tricks-3.15.5-py2.py3-none-any.whl", hash = "sha256:3432a602773b36ff0fe5b94a74f5de8612c843a256724e15c32f9f669844b6ef"},
-    {file = "json_tricks-3.15.5.tar.gz", hash = "sha256:bdf7d8677bccea722984be7f68946a981e4f50c21901e292d71b9c0c60a4ace3"},
-]
-jupyter-client = []
-jupyter-core = []
-jupyterlab-widgets = []
-kiwisolver = []
-lazy-object-proxy = []
-markdown = []
+    {file = "json_tricks-3.16.1-py2.py3-none-any.whl", hash = "sha256:05e6d3a431b5be5a1f70275580549724c242ce2e5bd7e54114a63250aba42f31"},
+    {file = "json_tricks-3.16.1.tar.gz", hash = "sha256:c18f3eb750e41b7d452221f8ef83e13dc69dbc92d7ae52c31675916c15e0a7fd"},
+]
+jupyter-client = [
+    {file = "jupyter_client-7.4.7-py3-none-any.whl", hash = "sha256:df56ae23b8e1da1b66f89dee1368e948b24a7f780fa822c5735187589fc4c157"},
+    {file = "jupyter_client-7.4.7.tar.gz", hash = "sha256:330f6b627e0b4bf2f54a3a0dd9e4a22d2b649c8518168afedce2c96a1ceb2860"},
+]
+jupyter-core = [
+    {file = "jupyter_core-5.1.0-py3-none-any.whl", hash = "sha256:f5740d99606958544396914b08e67b668f45e7eff99ab47a7f4bcead419c02f4"},
+    {file = "jupyter_core-5.1.0.tar.gz", hash = "sha256:a5ae7c09c55c0b26f692ec69323ba2b62e8d7295354d20f6cd57b749de4a05bf"},
+]
+jupyterlab-widgets = [
+    {file = "jupyterlab_widgets-3.0.3-py3-none-any.whl", hash = "sha256:6aa1bc0045470d54d76b9c0b7609a8f8f0087573bae25700a370c11f82cb38c8"},
+    {file = "jupyterlab_widgets-3.0.3.tar.gz", hash = "sha256:c767181399b4ca8b647befe2d913b1260f51bf9d8ef9b7a14632d4c1a7b536bd"},
+]
+kiwisolver = [
+    {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"},
+    {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"},
+    {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"},
+    {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"},
+    {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"},
+    {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"},
+    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"},
+    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"},
+    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"},
+    {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"},
+    {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"},
+    {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"},
+    {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"},
+    {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"},
+    {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"},
+    {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"},
+    {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"},
+    {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"},
+    {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"},
+    {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"},
+    {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"},
+]
+lazy-object-proxy = [
+    {file = "lazy-object-proxy-1.8.0.tar.gz", hash = "sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156"},
+    {file = "lazy_object_proxy-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe"},
+    {file = "lazy_object_proxy-1.8.0-cp310-cp310-win32.whl", hash = "sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25"},
+    {file = "lazy_object_proxy-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b"},
+    {file = "lazy_object_proxy-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7"},
+    {file = "lazy_object_proxy-1.8.0-cp311-cp311-win32.whl", hash = "sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e"},
+    {file = "lazy_object_proxy-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d"},
+    {file = "lazy_object_proxy-1.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c"},
+    {file = "lazy_object_proxy-1.8.0-cp37-cp37m-win32.whl", hash = "sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd"},
+    {file = "lazy_object_proxy-1.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858"},
+    {file = "lazy_object_proxy-1.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada"},
+    {file = "lazy_object_proxy-1.8.0-cp38-cp38-win32.whl", hash = "sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f"},
+    {file = "lazy_object_proxy-1.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c"},
+    {file = "lazy_object_proxy-1.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288"},
+    {file = "lazy_object_proxy-1.8.0-cp39-cp39-win32.whl", hash = "sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f"},
+    {file = "lazy_object_proxy-1.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0"},
+    {file = "lazy_object_proxy-1.8.0-pp37-pypy37_pp73-any.whl", hash = "sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891"},
+    {file = "lazy_object_proxy-1.8.0-pp38-pypy38_pp73-any.whl", hash = "sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec"},
+    {file = "lazy_object_proxy-1.8.0-pp39-pypy39_pp73-any.whl", hash = "sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8"},
+]
+markdown = [
+    {file = "Markdown-3.4.1-py3-none-any.whl", hash = "sha256:08fb8465cffd03d10b9dd34a5c3fea908e20391a2a90b88d66362cb05beed186"},
+    {file = "Markdown-3.4.1.tar.gz", hash = "sha256:3b809086bb6efad416156e00a0da66fe47618a5d6918dd688f53f40c8e4cfeff"},
+]
 markupsafe = [
     {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"},
     {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"},
@@ -2183,11 +2847,56 @@ markupsafe = [
     {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"},
     {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"},
 ]
-matplotlib = []
-matplotlib-inline = []
+matplotlib = [
+    {file = "matplotlib-3.6.2-cp310-cp310-macosx_10_12_universal2.whl", hash = "sha256:8d0068e40837c1d0df6e3abf1cdc9a34a6d2611d90e29610fa1d2455aeb4e2e5"},
+    {file = "matplotlib-3.6.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:252957e208c23db72ca9918cb33e160c7833faebf295aaedb43f5b083832a267"},
+    {file = "matplotlib-3.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d50e8c1e571ee39b5dfbc295c11ad65988879f68009dd281a6e1edbc2ff6c18c"},
+    {file = "matplotlib-3.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d840adcad7354be6f2ec28d0706528b0026e4c3934cc6566b84eac18633eab1b"},
+    {file = "matplotlib-3.6.2-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78ec3c3412cf277e6252764ee4acbdbec6920cc87ad65862272aaa0e24381eee"},
+    {file = "matplotlib-3.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9347cc6822f38db2b1d1ce992f375289670e595a2d1c15961aacbe0977407dfc"},
+    {file = "matplotlib-3.6.2-cp310-cp310-win32.whl", hash = "sha256:e0bbee6c2a5bf2a0017a9b5e397babb88f230e6f07c3cdff4a4c4bc75ed7c617"},
+    {file = "matplotlib-3.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:8a0ae37576ed444fe853709bdceb2be4c7df6f7acae17b8378765bd28e61b3ae"},
+    {file = "matplotlib-3.6.2-cp311-cp311-macosx_10_12_universal2.whl", hash = "sha256:5ecfc6559132116dedfc482d0ad9df8a89dc5909eebffd22f3deb684132d002f"},
+    {file = "matplotlib-3.6.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9f335e5625feb90e323d7e3868ec337f7b9ad88b5d633f876e3b778813021dab"},
+    {file = "matplotlib-3.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2604c6450f9dd2c42e223b1f5dca9643a23cfecc9fde4a94bb38e0d2693b136"},
+    {file = "matplotlib-3.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5afe0a7ea0e3a7a257907060bee6724a6002b7eec55d0db16fd32409795f3e1"},
+    {file = "matplotlib-3.6.2-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca0e7a658fbafcddcaefaa07ba8dae9384be2343468a8e011061791588d839fa"},
+    {file = "matplotlib-3.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32d29c8c26362169c80c5718ce367e8c64f4dd068a424e7110df1dd2ed7bd428"},
+    {file = "matplotlib-3.6.2-cp311-cp311-win32.whl", hash = "sha256:5024b8ed83d7f8809982d095d8ab0b179bebc07616a9713f86d30cf4944acb73"},
+    {file = "matplotlib-3.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:52c2bdd7cd0bf9d5ccdf9c1816568fd4ccd51a4d82419cc5480f548981b47dd0"},
+    {file = "matplotlib-3.6.2-cp38-cp38-macosx_10_12_universal2.whl", hash = "sha256:8a8dbe2cb7f33ff54b16bb5c500673502a35f18ac1ed48625e997d40c922f9cc"},
+    {file = "matplotlib-3.6.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:380d48c15ec41102a2b70858ab1dedfa33eb77b2c0982cb65a200ae67a48e9cb"},
+    {file = "matplotlib-3.6.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0844523dfaaff566e39dbfa74e6f6dc42e92f7a365ce80929c5030b84caa563a"},
+    {file = "matplotlib-3.6.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7f716b6af94dc1b6b97c46401774472f0867e44595990fe80a8ba390f7a0a028"},
+    {file = "matplotlib-3.6.2-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74153008bd24366cf099d1f1e83808d179d618c4e32edb0d489d526523a94d9f"},
+    {file = "matplotlib-3.6.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f41e57ad63d336fe50d3a67bb8eaa26c09f6dda6a59f76777a99b8ccd8e26aec"},
+    {file = "matplotlib-3.6.2-cp38-cp38-win32.whl", hash = "sha256:d0e9ac04065a814d4cf2c6791a2ad563f739ae3ae830d716d54245c2b96fead6"},
+    {file = "matplotlib-3.6.2-cp38-cp38-win_amd64.whl", hash = "sha256:8a9d899953c722b9afd7e88dbefd8fb276c686c3116a43c577cfabf636180558"},
+    {file = "matplotlib-3.6.2-cp39-cp39-macosx_10_12_universal2.whl", hash = "sha256:f04f97797df35e442ed09f529ad1235d1f1c0f30878e2fe09a2676b71a8801e0"},
+    {file = "matplotlib-3.6.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:3964934731fd7a289a91d315919cf757f293969a4244941ab10513d2351b4e83"},
+    {file = "matplotlib-3.6.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:168093410b99f647ba61361b208f7b0d64dde1172b5b1796d765cd243cadb501"},
+    {file = "matplotlib-3.6.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e16dcaecffd55b955aa5e2b8a804379789c15987e8ebd2f32f01398a81e975b"},
+    {file = "matplotlib-3.6.2-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83dc89c5fd728fdb03b76f122f43b4dcee8c61f1489e232d9ad0f58020523e1c"},
+    {file = "matplotlib-3.6.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:795ad83940732b45d39b82571f87af0081c120feff2b12e748d96bb191169e33"},
+    {file = "matplotlib-3.6.2-cp39-cp39-win32.whl", hash = "sha256:19d61ee6414c44a04addbe33005ab1f87539d9f395e25afcbe9a3c50ce77c65c"},
+    {file = "matplotlib-3.6.2-cp39-cp39-win_amd64.whl", hash = "sha256:5ba73aa3aca35d2981e0b31230d58abb7b5d7ca104e543ae49709208d8ce706a"},
+    {file = "matplotlib-3.6.2-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:1836f366272b1557a613f8265db220eb8dd883202bbbabe01bad5a4eadfd0c95"},
+    {file = "matplotlib-3.6.2-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0eda9d1b43f265da91fb9ae10d6922b5a986e2234470a524e6b18f14095b20d2"},
+    {file = "matplotlib-3.6.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec9be0f4826cdb3a3a517509dcc5f87f370251b76362051ab59e42b6b765f8c4"},
+    {file = "matplotlib-3.6.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3cef89888a466228fc4e4b2954e740ce8e9afde7c4315fdd18caa1b8de58ca17"},
+    {file = "matplotlib-3.6.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:54fa9fe27f5466b86126ff38123261188bed568c1019e4716af01f97a12fe812"},
+    {file = "matplotlib-3.6.2-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e68be81cd8c22b029924b6d0ee814c337c0e706b8d88495a617319e5dd5441c3"},
+    {file = "matplotlib-3.6.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0ca2c60d3966dfd6608f5f8c49b8a0fcf76de6654f2eda55fc6ef038d5a6f27"},
+    {file = "matplotlib-3.6.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:4426c74761790bff46e3d906c14c7aab727543293eed5a924300a952e1a3a3c1"},
+    {file = "matplotlib-3.6.2.tar.gz", hash = "sha256:b03fd10a1709d0101c054883b550f7c4c5e974f751e2680318759af005964990"},
+]
+matplotlib-inline = [
+    {file = "matplotlib-inline-0.1.6.tar.gz", hash = "sha256:f887e5f10ba98e8d2b150ddcf4702c1e5f8b3a20005eb0f74bfdbd360ee6f304"},
+    {file = "matplotlib_inline-0.1.6-py3-none-any.whl", hash = "sha256:f1f41aab5328aa5aaea9b16d083b128102f8712542f819fe7e6a420ff581b311"},
+]
 mccabe = [
-    {file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
-    {file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
+    {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
+    {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
 ]
 multidict = [
     {file = "multidict-6.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b9e95a740109c6047602f4db4da9949e6c5945cefbad34a1299775ddc9a62e2"},
@@ -2251,69 +2960,113 @@ multidict = [
     {file = "multidict-6.0.2.tar.gz", hash = "sha256:5ff3bd75f38e4c43f1f470f2df7a4d430b821c4ce22be384e1459cb57d6bb013"},
 ]
 multiprocess = [
-    {file = "multiprocess-0.70.13-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:b9a3be43ecee6776a9e7223af96914a0164f306affcf4624b213885172236b77"},
-    {file = "multiprocess-0.70.13-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:7e6a689da3490412caa7b3e27c3385d8aaa49135f3a353ace94ca47e4c926d37"},
-    {file = "multiprocess-0.70.13-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:17cb4229aa43e6973679d67c66a454cbf8b6b0d038425cba3220ea5a06d61b58"},
-    {file = "multiprocess-0.70.13-cp27-cp27m-win32.whl", hash = "sha256:99bb68dd0d5b3d30fe104721bee26e4637667112d5951b51feb81479fd560876"},
-    {file = "multiprocess-0.70.13-cp27-cp27m-win_amd64.whl", hash = "sha256:6cdde49defcb933062df382ebc9b5299beebcd157a98b3a65291c1c94a2edc41"},
-    {file = "multiprocess-0.70.13-pp27-pypy_73-macosx_10_7_x86_64.whl", hash = "sha256:92003c247436f8699b7692e95346a238446710f078500eb364bc23bb0503dd4f"},
-    {file = "multiprocess-0.70.13-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:3ec1c8015e19182bfa01b5887a9c25805c48df3c71863f48fe83803147cde5d6"},
-    {file = "multiprocess-0.70.13-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b7415f61bddfffdade73396904551be8124a4a363322aa9c72d42e349c5fca39"},
-    {file = "multiprocess-0.70.13-pp37-pypy37_pp73-manylinux_2_24_i686.whl", hash = "sha256:5436d1cd9f901f7ddc4f20b6fd0b462c87dcc00d941cc13eeb2401fc5bd00e42"},
-    {file = "multiprocess-0.70.13-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:34e9703bd5b9fee5455c93a74e44dbabe55481c214d03be1e65f037be9d0c520"},
-    {file = "multiprocess-0.70.13-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:af0a48440aa8f793d8bb100f20102c12f192de5a608638819a998f2cc59e1fcd"},
-    {file = "multiprocess-0.70.13-pp38-pypy38_pp73-manylinux_2_24_i686.whl", hash = "sha256:c4a97216e8319039c69a266252cc68a392b96f9e67e3ed02ad88be9e6f2d2969"},
-    {file = "multiprocess-0.70.13-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:48315eefe02c35dd7560da3fa8af66d9f4a61b9dc8f7c40801c5f972ab4604b1"},
-    {file = "multiprocess-0.70.13-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5a6dca5f29f0224c855d0d5cad963476175cfc8de112d3eebe85914cb735f130"},
-    {file = "multiprocess-0.70.13-pp39-pypy39_pp73-manylinux_2_24_i686.whl", hash = "sha256:5974bdad390ba466cc130288d2ef1048fdafedd01cf4641fc024f6088af70bfe"},
-    {file = "multiprocess-0.70.13-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:01c1137d2f18d0cd262d0fdb7294b1fe9fc3e8dc8b126e506085434ae8eb3677"},
-    {file = "multiprocess-0.70.13-py310-none-any.whl", hash = "sha256:0f4faf4811019efdb2f91db09240f893ee40cbfcb06978f3b8ed8c248e73babe"},
-    {file = "multiprocess-0.70.13-py37-none-any.whl", hash = "sha256:62e556a0c31ec7176e28aa331663ac26c276ee3536b5e9bb5e850681e7a00f11"},
-    {file = "multiprocess-0.70.13-py38-none-any.whl", hash = "sha256:7be9e320a41d2d0d0eddacfe693cfb07b4cb9c0d3d10007f4304255c15215778"},
-    {file = "multiprocess-0.70.13-py39-none-any.whl", hash = "sha256:00ef48461d43d1e30f8f4b2e1b287ecaaffec325a37053beb5503e0d69e5a3cd"},
-    {file = "multiprocess-0.70.13.tar.gz", hash = "sha256:2e096dd618a84d15aa369a9cf6695815e5539f853dc8fa4f4b9153b11b1d0b32"},
-]
-mypy = [
-    {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"},
-    {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"},
-    {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"},
-    {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"},
-    {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"},
-    {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"},
-    {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"},
-    {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"},
-    {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"},
-    {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"},
-    {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"},
-    {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"},
-    {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"},
-    {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"},
-    {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"},
-    {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"},
-    {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"},
-    {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"},
-    {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"},
-    {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"},
-    {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"},
-    {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"},
-    {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"},
+    {file = "multiprocess-0.70.14-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:560a27540daef4ce8b24ed3cc2496a3c670df66c96d02461a4da67473685adf3"},
+    {file = "multiprocess-0.70.14-pp37-pypy37_pp73-manylinux_2_24_i686.whl", hash = "sha256:bfbbfa36f400b81d1978c940616bc77776424e5e34cb0c94974b178d727cfcd5"},
+    {file = "multiprocess-0.70.14-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:89fed99553a04ec4f9067031f83a886d7fdec5952005551a896a4b6a59575bb9"},
+    {file = "multiprocess-0.70.14-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:40a5e3685462079e5fdee7c6789e3ef270595e1755199f0d50685e72523e1d2a"},
+    {file = "multiprocess-0.70.14-pp38-pypy38_pp73-manylinux_2_24_i686.whl", hash = "sha256:44936b2978d3f2648727b3eaeab6d7fa0bedf072dc5207bf35a96d5ee7c004cf"},
+    {file = "multiprocess-0.70.14-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:e628503187b5d494bf29ffc52d3e1e57bb770ce7ce05d67c4bbdb3a0c7d3b05f"},
+    {file = "multiprocess-0.70.14-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d5da0fc84aacb0e4bd69c41b31edbf71b39fe2fb32a54eaedcaea241050855c"},
+    {file = "multiprocess-0.70.14-pp39-pypy39_pp73-manylinux_2_24_i686.whl", hash = "sha256:6a7b03a5b98e911a7785b9116805bd782815c5e2bd6c91c6a320f26fd3e7b7ad"},
+    {file = "multiprocess-0.70.14-pp39-pypy39_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:cea5bdedd10aace3c660fedeac8b087136b4366d4ee49a30f1ebf7409bce00ae"},
+    {file = "multiprocess-0.70.14-py310-none-any.whl", hash = "sha256:7dc1f2f6a1d34894c8a9a013fbc807971e336e7cc3f3ff233e61b9dc679b3b5c"},
+    {file = "multiprocess-0.70.14-py37-none-any.whl", hash = "sha256:93a8208ca0926d05cdbb5b9250a604c401bed677579e96c14da3090beb798193"},
+    {file = "multiprocess-0.70.14-py38-none-any.whl", hash = "sha256:6725bc79666bbd29a73ca148a0fb5f4ea22eed4a8f22fce58296492a02d18a7b"},
+    {file = "multiprocess-0.70.14-py39-none-any.whl", hash = "sha256:63cee628b74a2c0631ef15da5534c8aedbc10c38910b9c8b18dcd327528d1ec7"},
+    {file = "multiprocess-0.70.14.tar.gz", hash = "sha256:3eddafc12f2260d27ae03fe6069b12570ab4764ab59a75e81624fac453fbf46a"},
 ]
 mypy-extensions = [
     {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
     {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
 ]
-nest-asyncio = []
-nodeenv = []
-numpy = []
-nvidia-cublas-cu11 = []
-nvidia-cuda-nvrtc-cu11 = []
-nvidia-cuda-runtime-cu11 = []
-nvidia-cudnn-cu11 = []
+nest-asyncio = [
+    {file = "nest_asyncio-1.5.6-py3-none-any.whl", hash = "sha256:b9a953fb40dceaa587d109609098db21900182b16440652454a146cffb06e8b8"},
+    {file = "nest_asyncio-1.5.6.tar.gz", hash = "sha256:d267cc1ff794403f7df692964d1d2a3fa9418ffea2a3f6859a439ff482fef290"},
+]
+nodeenv = [
+    {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"},
+    {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"},
+]
+numpy = [
+    {file = "numpy-1.23.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9c88793f78fca17da0145455f0d7826bcb9f37da4764af27ac945488116efe63"},
+    {file = "numpy-1.23.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e9f4c4e51567b616be64e05d517c79a8a22f3606499941d97bb76f2ca59f982d"},
+    {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7903ba8ab592b82014713c491f6c5d3a1cde5b4a3bf116404e08f5b52f6daf43"},
+    {file = "numpy-1.23.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e05b1c973a9f858c74367553e236f287e749465f773328c8ef31abe18f691e1"},
+    {file = "numpy-1.23.5-cp310-cp310-win32.whl", hash = "sha256:522e26bbf6377e4d76403826ed689c295b0b238f46c28a7251ab94716da0b280"},
+    {file = "numpy-1.23.5-cp310-cp310-win_amd64.whl", hash = "sha256:dbee87b469018961d1ad79b1a5d50c0ae850000b639bcb1b694e9981083243b6"},
+    {file = "numpy-1.23.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ce571367b6dfe60af04e04a1834ca2dc5f46004ac1cc756fb95319f64c095a96"},
+    {file = "numpy-1.23.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56e454c7833e94ec9769fa0f86e6ff8e42ee38ce0ce1fa4cbb747ea7e06d56aa"},
+    {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5039f55555e1eab31124a5768898c9e22c25a65c1e0037f4d7c495a45778c9f2"},
+    {file = "numpy-1.23.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58f545efd1108e647604a1b5aa809591ccd2540f468a880bedb97247e72db387"},
+    {file = "numpy-1.23.5-cp311-cp311-win32.whl", hash = "sha256:b2a9ab7c279c91974f756c84c365a669a887efa287365a8e2c418f8b3ba73fb0"},
+    {file = "numpy-1.23.5-cp311-cp311-win_amd64.whl", hash = "sha256:0cbe9848fad08baf71de1a39e12d1b6310f1d5b2d0ea4de051058e6e1076852d"},
+    {file = "numpy-1.23.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f063b69b090c9d918f9df0a12116029e274daf0181df392839661c4c7ec9018a"},
+    {file = "numpy-1.23.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0aaee12d8883552fadfc41e96b4c82ee7d794949e2a7c3b3a7201e968c7ecab9"},
+    {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:92c8c1e89a1f5028a4c6d9e3ccbe311b6ba53694811269b992c0b224269e2398"},
+    {file = "numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d208a0f8729f3fb790ed18a003f3a57895b989b40ea4dce4717e9cf4af62c6bb"},
+    {file = "numpy-1.23.5-cp38-cp38-win32.whl", hash = "sha256:06005a2ef6014e9956c09ba07654f9837d9e26696a0470e42beedadb78c11b07"},
+    {file = "numpy-1.23.5-cp38-cp38-win_amd64.whl", hash = "sha256:ca51fcfcc5f9354c45f400059e88bc09215fb71a48d3768fb80e357f3b457e1e"},
+    {file = "numpy-1.23.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8969bfd28e85c81f3f94eb4a66bc2cf1dbdc5c18efc320af34bffc54d6b1e38f"},
+    {file = "numpy-1.23.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7ac231a08bb37f852849bbb387a20a57574a97cfc7b6cabb488a4fc8be176de"},
+    {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf837dc63ba5c06dc8797c398db1e223a466c7ece27a1f7b5232ba3466aafe3d"},
+    {file = "numpy-1.23.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33161613d2269025873025b33e879825ec7b1d831317e68f4f2f0f84ed14c719"},
+    {file = "numpy-1.23.5-cp39-cp39-win32.whl", hash = "sha256:af1da88f6bc3d2338ebbf0e22fe487821ea4d8e89053e25fa59d1d79786e7481"},
+    {file = "numpy-1.23.5-cp39-cp39-win_amd64.whl", hash = "sha256:09b7847f7e83ca37c6e627682f145856de331049013853f344f37b0c9690e3df"},
+    {file = "numpy-1.23.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:abdde9f795cf292fb9651ed48185503a2ff29be87770c3b8e2a14b0cd7aa16f8"},
+    {file = "numpy-1.23.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f9a909a8bae284d46bbfdefbdd4a262ba19d3bc9921b1e76126b1d21c3c34135"},
+    {file = "numpy-1.23.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:01dd17cbb340bf0fc23981e52e1d18a9d4050792e8fb8363cecbf066a84b827d"},
+    {file = "numpy-1.23.5.tar.gz", hash = "sha256:1b1766d6f397c18153d40015ddfc79ddb715cabadc04d2d228d4e5a8bc4ded1a"},
+]
+nvidia-cublas-cu11 = [
+    {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-manylinux1_x86_64.whl", hash = "sha256:d32e4d75f94ddfb93ea0a5dda08389bcc65d8916a25cb9f37ac89edaeed3bded"},
+    {file = "nvidia_cublas_cu11-11.10.3.66-py3-none-win_amd64.whl", hash = "sha256:8ac17ba6ade3ed56ab898a036f9ae0756f1e81052a317bf98f8c6d18dc3ae49e"},
+]
+nvidia-cuda-nvrtc-cu11 = [
+    {file = "nvidia_cuda_nvrtc_cu11-11.7.99-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:9f1562822ea264b7e34ed5930567e89242d266448e936b85bc97a3370feabb03"},
+    {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:f7d9610d9b7c331fa0da2d1b2858a4a8315e6d49765091d28711c8946e7425e7"},
+    {file = "nvidia_cuda_nvrtc_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:f2effeb1309bdd1b3854fc9b17eaf997808f8b25968ce0c7070945c4265d64a3"},
+]
+nvidia-cuda-runtime-cu11 = [
+    {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-manylinux1_x86_64.whl", hash = "sha256:cc768314ae58d2641f07eac350f40f99dcb35719c4faff4bc458a7cd2b119e31"},
+    {file = "nvidia_cuda_runtime_cu11-11.7.99-py3-none-win_amd64.whl", hash = "sha256:bc77fa59a7679310df9d5c70ab13c4e34c64ae2124dd1efd7e5474b71be125c7"},
+]
+nvidia-cudnn-cu11 = [
+    {file = "nvidia_cudnn_cu11-8.5.0.96-2-py3-none-manylinux1_x86_64.whl", hash = "sha256:402f40adfc6f418f9dae9ab402e773cfed9beae52333f6d86ae3107a1b9527e7"},
+    {file = "nvidia_cudnn_cu11-8.5.0.96-py3-none-manylinux1_x86_64.whl", hash = "sha256:71f8111eb830879ff2836db3cccf03bbd735df9b0d17cd93761732ac50a8a108"},
+]
 packaging = [
     {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
     {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
 ]
-pandas = []
+pandas = [
+    {file = "pandas-1.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e9dbacd22555c2d47f262ef96bb4e30880e5956169741400af8b306bbb24a273"},
+    {file = "pandas-1.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e2b83abd292194f350bb04e188f9379d36b8dfac24dd445d5c87575f3beaf789"},
+    {file = "pandas-1.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2552bffc808641c6eb471e55aa6899fa002ac94e4eebfa9ec058649122db5824"},
+    {file = "pandas-1.5.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fc87eac0541a7d24648a001d553406f4256e744d92df1df8ebe41829a915028"},
+    {file = "pandas-1.5.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0d8fd58df5d17ddb8c72a5075d87cd80d71b542571b5f78178fb067fa4e9c72"},
+    {file = "pandas-1.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:4aed257c7484d01c9a194d9a94758b37d3d751849c05a0050c087a358c41ad1f"},
+    {file = "pandas-1.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:375262829c8c700c3e7cbb336810b94367b9c4889818bbd910d0ecb4e45dc261"},
+    {file = "pandas-1.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc3cd122bea268998b79adebbb8343b735a5511ec14efb70a39e7acbc11ccbdc"},
+    {file = "pandas-1.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b4f5a82afa4f1ff482ab8ded2ae8a453a2cdfde2001567b3ca24a4c5c5ca0db3"},
+    {file = "pandas-1.5.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8092a368d3eb7116e270525329a3e5c15ae796ccdf7ccb17839a73b4f5084a39"},
+    {file = "pandas-1.5.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6257b314fc14958f8122779e5a1557517b0f8e500cfb2bd53fa1f75a8ad0af2"},
+    {file = "pandas-1.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:82ae615826da838a8e5d4d630eb70c993ab8636f0eff13cb28aafc4291b632b5"},
+    {file = "pandas-1.5.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:457d8c3d42314ff47cc2d6c54f8fc0d23954b47977b2caed09cd9635cb75388b"},
+    {file = "pandas-1.5.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c009a92e81ce836212ce7aa98b219db7961a8b95999b97af566b8dc8c33e9519"},
+    {file = "pandas-1.5.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:71f510b0efe1629bf2f7c0eadb1ff0b9cf611e87b73cd017e6b7d6adb40e2b3a"},
+    {file = "pandas-1.5.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a40dd1e9f22e01e66ed534d6a965eb99546b41d4d52dbdb66565608fde48203f"},
+    {file = "pandas-1.5.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ae7e989f12628f41e804847a8cc2943d362440132919a69429d4dea1f164da0"},
+    {file = "pandas-1.5.2-cp38-cp38-win32.whl", hash = "sha256:530948945e7b6c95e6fa7aa4be2be25764af53fba93fe76d912e35d1c9ee46f5"},
+    {file = "pandas-1.5.2-cp38-cp38-win_amd64.whl", hash = "sha256:73f219fdc1777cf3c45fde7f0708732ec6950dfc598afc50588d0d285fddaefc"},
+    {file = "pandas-1.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9608000a5a45f663be6af5c70c3cbe634fa19243e720eb380c0d378666bc7702"},
+    {file = "pandas-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:315e19a3e5c2ab47a67467fc0362cb36c7c60a93b6457f675d7d9615edad2ebe"},
+    {file = "pandas-1.5.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e18bc3764cbb5e118be139b3b611bc3fbc5d3be42a7e827d1096f46087b395eb"},
+    {file = "pandas-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0183cb04a057cc38fde5244909fca9826d5d57c4a5b7390c0cc3fa7acd9fa883"},
+    {file = "pandas-1.5.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:344021ed3e639e017b452aa8f5f6bf38a8806f5852e217a7594417fb9bbfa00e"},
+    {file = "pandas-1.5.2-cp39-cp39-win32.whl", hash = "sha256:e7469271497960b6a781eaa930cba8af400dd59b62ec9ca2f4d31a19f2f91090"},
+    {file = "pandas-1.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:c218796d59d5abd8780170c937b812c9637e84c32f8271bbf9845970f8c1351f"},
+    {file = "pandas-1.5.2.tar.gz", hash = "sha256:220b98d15cee0b2cd839a6358bd1f273d0356bf964c1a1aeb32d47db0215488b"},
+]
 parso = [
     {file = "parso-0.8.3-py2.py3-none-any.whl", hash = "sha256:c001d4636cd3aecdaf33cbb40aebb59b094be2a74c556778ef5576c175e19e75"},
     {file = "parso-0.8.3.tar.gz", hash = "sha256:8c07be290bb59f03588915921e29e8a50002acaf2cdc5fa0e0114f91709fafa0"},
@@ -2322,8 +3075,14 @@ pastel = [
     {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
     {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
 ]
-pathspec = []
-pbr = []
+pathspec = [
+    {file = "pathspec-0.10.2-py3-none-any.whl", hash = "sha256:88c2606f2c1e818b978540f73ecc908e13999c6c3a383daf3705652ae79807a5"},
+    {file = "pathspec-0.10.2.tar.gz", hash = "sha256:8f6bf73e5758fd365ef5d58ce09ac7c27d2833a8d7da51712eac6e27e35141b0"},
+]
+pbr = [
+    {file = "pbr-5.11.0-py2.py3-none-any.whl", hash = "sha256:db2317ff07c84c4c63648c9064a79fe9d9f5c7ce85a9099d4b6258b3db83225a"},
+    {file = "pbr-5.11.0.tar.gz", hash = "sha256:b97bc6695b2aff02144133c2e7399d5885223d42b7912ffaec2ca3898e673bfe"},
+]
 pexpect = [
     {file = "pexpect-4.8.0-py2.py3-none-any.whl", hash = "sha256:0b48a55dcb3c05f3329815901ea4fc1537514d6ba867a152b581d69ae3710937"},
     {file = "pexpect-4.8.0.tar.gz", hash = "sha256:fc65a43959d153d0114afe13997d439c22823a27cefceb5ff35c2178c6784c0c"},
@@ -2332,10 +3091,70 @@ pickleshare = [
     {file = "pickleshare-0.7.5-py2.py3-none-any.whl", hash = "sha256:9649af414d74d4df115d5d718f82acb59c9d418196b7b4290ed47a12ce62df56"},
     {file = "pickleshare-0.7.5.tar.gz", hash = "sha256:87683d47965c1da65cdacaf31c8441d12b8044cdec9aca500cd78fc2c683afca"},
 ]
-pillow = []
+pillow = [
+    {file = "Pillow-9.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:0b7257127d646ff8676ec8a15520013a698d1fdc48bc2a79ba4e53df792526f2"},
+    {file = "Pillow-9.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b90f7616ea170e92820775ed47e136208e04c967271c9ef615b6fbd08d9af0e3"},
+    {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68943d632f1f9e3dce98908e873b3a090f6cba1cbb1b892a9e8d97c938871fbe"},
+    {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be55f8457cd1eac957af0c3f5ece7bc3f033f89b114ef30f710882717670b2a8"},
+    {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d77adcd56a42d00cc1be30843d3426aa4e660cab4a61021dc84467123f7a00c"},
+    {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:829f97c8e258593b9daa80638aee3789b7df9da5cf1336035016d76f03b8860c"},
+    {file = "Pillow-9.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:801ec82e4188e935c7f5e22e006d01611d6b41661bba9fe45b60e7ac1a8f84de"},
+    {file = "Pillow-9.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:871b72c3643e516db4ecf20efe735deb27fe30ca17800e661d769faab45a18d7"},
+    {file = "Pillow-9.3.0-cp310-cp310-win32.whl", hash = "sha256:655a83b0058ba47c7c52e4e2df5ecf484c1b0b0349805896dd350cbc416bdd91"},
+    {file = "Pillow-9.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:9f47eabcd2ded7698106b05c2c338672d16a6f2a485e74481f524e2a23c2794b"},
+    {file = "Pillow-9.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:57751894f6618fd4308ed8e0c36c333e2f5469744c34729a27532b3db106ee20"},
+    {file = "Pillow-9.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7db8b751ad307d7cf238f02101e8e36a128a6cb199326e867d1398067381bff4"},
+    {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3033fbe1feb1b59394615a1cafaee85e49d01b51d54de0cbf6aa8e64182518a1"},
+    {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22b012ea2d065fd163ca096f4e37e47cd8b59cf4b0fd47bfca6abb93df70b34c"},
+    {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9a65733d103311331875c1dca05cb4606997fd33d6acfed695b1232ba1df193"},
+    {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:502526a2cbfa431d9fc2a079bdd9061a2397b842bb6bc4239bb176da00993812"},
+    {file = "Pillow-9.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:90fb88843d3902fe7c9586d439d1e8c05258f41da473952aa8b328d8b907498c"},
+    {file = "Pillow-9.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:89dca0ce00a2b49024df6325925555d406b14aa3efc2f752dbb5940c52c56b11"},
+    {file = "Pillow-9.3.0-cp311-cp311-win32.whl", hash = "sha256:3168434d303babf495d4ba58fc22d6604f6e2afb97adc6a423e917dab828939c"},
+    {file = "Pillow-9.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:18498994b29e1cf86d505edcb7edbe814d133d2232d256db8c7a8ceb34d18cef"},
+    {file = "Pillow-9.3.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:772a91fc0e03eaf922c63badeca75e91baa80fe2f5f87bdaed4280662aad25c9"},
+    {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa4107d1b306cdf8953edde0534562607fe8811b6c4d9a486298ad31de733b2"},
+    {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b4012d06c846dc2b80651b120e2cdd787b013deb39c09f407727ba90015c684f"},
+    {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77ec3e7be99629898c9a6d24a09de089fa5356ee408cdffffe62d67bb75fdd72"},
+    {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:6c738585d7a9961d8c2821a1eb3dcb978d14e238be3d70f0a706f7fa9316946b"},
+    {file = "Pillow-9.3.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:828989c45c245518065a110434246c44a56a8b2b2f6347d1409c787e6e4651ee"},
+    {file = "Pillow-9.3.0-cp37-cp37m-win32.whl", hash = "sha256:82409ffe29d70fd733ff3c1025a602abb3e67405d41b9403b00b01debc4c9a29"},
+    {file = "Pillow-9.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:41e0051336807468be450d52b8edd12ac60bebaa97fe10c8b660f116e50b30e4"},
+    {file = "Pillow-9.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:b03ae6f1a1878233ac620c98f3459f79fd77c7e3c2b20d460284e1fb370557d4"},
+    {file = "Pillow-9.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4390e9ce199fc1951fcfa65795f239a8a4944117b5935a9317fb320e7767b40f"},
+    {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40e1ce476a7804b0fb74bcfa80b0a2206ea6a882938eaba917f7a0f004b42502"},
+    {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a0a06a052c5f37b4ed81c613a455a81f9a3a69429b4fd7bb913c3fa98abefc20"},
+    {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03150abd92771742d4a8cd6f2fa6246d847dcd2e332a18d0c15cc75bf6703040"},
+    {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:15c42fb9dea42465dfd902fb0ecf584b8848ceb28b41ee2b58f866411be33f07"},
+    {file = "Pillow-9.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:51e0e543a33ed92db9f5ef69a0356e0b1a7a6b6a71b80df99f1d181ae5875636"},
+    {file = "Pillow-9.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3dd6caf940756101205dffc5367babf288a30043d35f80936f9bfb37f8355b32"},
+    {file = "Pillow-9.3.0-cp38-cp38-win32.whl", hash = "sha256:f1ff2ee69f10f13a9596480335f406dd1f70c3650349e2be67ca3139280cade0"},
+    {file = "Pillow-9.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:276a5ca930c913f714e372b2591a22c4bd3b81a418c0f6635ba832daec1cbcfc"},
+    {file = "Pillow-9.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:73bd195e43f3fadecfc50c682f5055ec32ee2c933243cafbfdec69ab1aa87cad"},
+    {file = "Pillow-9.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1c7c8ae3864846fc95f4611c78129301e203aaa2af813b703c55d10cc1628535"},
+    {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e0918e03aa0c72ea56edbb00d4d664294815aa11291a11504a377ea018330d3"},
+    {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0915e734b33a474d76c28e07292f196cdf2a590a0d25bcc06e64e545f2d146c"},
+    {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af0372acb5d3598f36ec0914deed2a63f6bcdb7b606da04dc19a88d31bf0c05b"},
+    {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:ad58d27a5b0262c0c19b47d54c5802db9b34d38bbf886665b626aff83c74bacd"},
+    {file = "Pillow-9.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:97aabc5c50312afa5e0a2b07c17d4ac5e865b250986f8afe2b02d772567a380c"},
+    {file = "Pillow-9.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9aaa107275d8527e9d6e7670b64aabaaa36e5b6bd71a1015ddd21da0d4e06448"},
+    {file = "Pillow-9.3.0-cp39-cp39-win32.whl", hash = "sha256:bac18ab8d2d1e6b4ce25e3424f709aceef668347db8637c2296bcf41acb7cf48"},
+    {file = "Pillow-9.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:b472b5ea442148d1c3e2209f20f1e0bb0eb556538690fa70b5e1f79fa0ba8dc2"},
+    {file = "Pillow-9.3.0-pp37-pypy37_pp73-macosx_10_10_x86_64.whl", hash = "sha256:ab388aaa3f6ce52ac1cb8e122c4bd46657c15905904b3120a6248b5b8b0bc228"},
+    {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbb8e7f2abee51cef77673be97760abff1674ed32847ce04b4af90f610144c7b"},
+    {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca31dd6014cb8b0b2db1e46081b0ca7d936f856da3b39744aef499db5d84d02"},
+    {file = "Pillow-9.3.0-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c7025dce65566eb6e89f56c9509d4f628fddcedb131d9465cacd3d8bac337e7e"},
+    {file = "Pillow-9.3.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ebf2029c1f464c59b8bdbe5143c79fa2045a581ac53679733d3a91d400ff9efb"},
+    {file = "Pillow-9.3.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b59430236b8e58840a0dfb4099a0e8717ffb779c952426a69ae435ca1f57210c"},
+    {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12ce4932caf2ddf3e41d17fc9c02d67126935a44b86df6a206cf0d7161548627"},
+    {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae5331c23ce118c53b172fa64a4c037eb83c9165aba3a7ba9ddd3ec9fa64a699"},
+    {file = "Pillow-9.3.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:0b07fffc13f474264c336298d1b4ce01d9c5a011415b79d4ee5527bb69ae6f65"},
+    {file = "Pillow-9.3.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:073adb2ae23431d3b9bcbcff3fe698b62ed47211d0716b067385538a1b0f28b8"},
+    {file = "Pillow-9.3.0.tar.gz", hash = "sha256:c935a22a557a560108d780f9a0fc426dd7459940dc54faa49d83249c8d3e760f"},
+]
 platformdirs = [
-    {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"},
-    {file = "platformdirs-2.5.2.tar.gz", hash = "sha256:58c8abb07dcb441e6ee4b11d8df0ac856038f944ab98b7be6b27b2a3c7feef19"},
+    {file = "platformdirs-2.5.4-py3-none-any.whl", hash = "sha256:af0276409f9a02373d540bf8480021a048711d572745aef4b7842dad245eba10"},
+    {file = "platformdirs-2.5.4.tar.gz", hash = "sha256:1006647646d80f16130f052404c6b901e80ee4ed6bef6792e1f238a8969106f7"},
 ]
 pluggy = [
     {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"},
@@ -2345,10 +3164,54 @@ poethepoet = [
     {file = "poethepoet-0.13.1-py3-none-any.whl", hash = "sha256:47e7b38c8b5412f840447f7612a9330697e8633e7500a7340b6734f50e26e380"},
     {file = "poethepoet-0.13.1.tar.gz", hash = "sha256:4f6962f17f5d5a453fd7fa66e3e7897e9191d4289148433efe441c81f2451a46"},
 ]
-pre-commit = []
-prompt-toolkit = []
-protobuf = []
-psutil = []
+pre-commit = [
+    {file = "pre_commit-2.20.0-py2.py3-none-any.whl", hash = "sha256:51a5ba7c480ae8072ecdb6933df22d2f812dc897d5fe848778116129a681aac7"},
+    {file = "pre_commit-2.20.0.tar.gz", hash = "sha256:a978dac7bc9ec0bcee55c18a277d553b0f419d259dadb4b9418ff2d00eb43959"},
+]
+prompt-toolkit = [
+    {file = "prompt_toolkit-3.0.33-py3-none-any.whl", hash = "sha256:ced598b222f6f4029c0800cefaa6a17373fb580cd093223003475ce32805c35b"},
+    {file = "prompt_toolkit-3.0.33.tar.gz", hash = "sha256:535c29c31216c77302877d5120aef6c94ff573748a5b5ca5b1b1f76f5e700c73"},
+]
+protobuf = [
+    {file = "protobuf-3.20.2-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:09e25909c4297d71d97612f04f41cea8fa8510096864f2835ad2f3b3df5a5559"},
+    {file = "protobuf-3.20.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e8fbc522303e09036c752a0afcc5c0603e917222d8bedc02813fd73b4b4ed804"},
+    {file = "protobuf-3.20.2-cp310-cp310-win32.whl", hash = "sha256:84a1544252a933ef07bb0b5ef13afe7c36232a774affa673fc3636f7cee1db6c"},
+    {file = "protobuf-3.20.2-cp310-cp310-win_amd64.whl", hash = "sha256:2c0b040d0b5d5d207936ca2d02f00f765906622c07d3fa19c23a16a8ca71873f"},
+    {file = "protobuf-3.20.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3cb608e5a0eb61b8e00fe641d9f0282cd0eedb603be372f91f163cbfbca0ded0"},
+    {file = "protobuf-3.20.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:84fe5953b18a383fd4495d375fe16e1e55e0a3afe7b4f7b4d01a3a0649fcda9d"},
+    {file = "protobuf-3.20.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:384164994727f274cc34b8abd41a9e7e0562801361ee77437099ff6dfedd024b"},
+    {file = "protobuf-3.20.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:e39cf61bb8582bda88cdfebc0db163b774e7e03364bbf9ce1ead13863e81e359"},
+    {file = "protobuf-3.20.2-cp37-cp37m-win32.whl", hash = "sha256:18e34a10ae10d458b027d7638a599c964b030c1739ebd035a1dfc0e22baa3bfe"},
+    {file = "protobuf-3.20.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8228e56a865c27163d5d1d1771d94b98194aa6917bcfb6ce139cbfa8e3c27334"},
+    {file = "protobuf-3.20.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:03d76b7bd42ac4a6e109742a4edf81ffe26ffd87c5993126d894fe48a120396a"},
+    {file = "protobuf-3.20.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:f52dabc96ca99ebd2169dadbe018824ebda08a795c7684a0b7d203a290f3adb0"},
+    {file = "protobuf-3.20.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:f34464ab1207114e73bba0794d1257c150a2b89b7a9faf504e00af7c9fd58978"},
+    {file = "protobuf-3.20.2-cp38-cp38-win32.whl", hash = "sha256:5d9402bf27d11e37801d1743eada54372f986a372ec9679673bfcc5c60441151"},
+    {file = "protobuf-3.20.2-cp38-cp38-win_amd64.whl", hash = "sha256:9c673c8bfdf52f903081816b9e0e612186684f4eb4c17eeb729133022d6032e3"},
+    {file = "protobuf-3.20.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:291fb4307094bf5ccc29f424b42268640e00d5240bf0d9b86bf3079f7576474d"},
+    {file = "protobuf-3.20.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b4fdb29c5a7406e3f7ef176b2a7079baa68b5b854f364c21abe327bbeec01cdb"},
+    {file = "protobuf-3.20.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7a5037af4e76c975b88c3becdf53922b5ffa3f2cddf657574a4920a3b33b80f3"},
+    {file = "protobuf-3.20.2-cp39-cp39-win32.whl", hash = "sha256:a9e5ae5a8e8985c67e8944c23035a0dff2c26b0f5070b2f55b217a1c33bbe8b1"},
+    {file = "protobuf-3.20.2-cp39-cp39-win_amd64.whl", hash = "sha256:c184485e0dfba4dfd451c3bd348c2e685d6523543a0f91b9fd4ae90eb09e8422"},
+    {file = "protobuf-3.20.2-py2.py3-none-any.whl", hash = "sha256:c9cdf251c582c16fd6a9f5e95836c90828d51b0069ad22f463761d27c6c19019"},
+    {file = "protobuf-3.20.2.tar.gz", hash = "sha256:712dca319eee507a1e7df3591e639a2b112a2f4a62d40fe7832a16fd19151750"},
+]
+psutil = [
+    {file = "psutil-5.9.4-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c1ca331af862803a42677c120aff8a814a804e09832f166f226bfd22b56feee8"},
+    {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:68908971daf802203f3d37e78d3f8831b6d1014864d7a85937941bb35f09aefe"},
+    {file = "psutil-5.9.4-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:3ff89f9b835100a825b14c2808a106b6fdcc4b15483141482a12c725e7f78549"},
+    {file = "psutil-5.9.4-cp27-cp27m-win32.whl", hash = "sha256:852dd5d9f8a47169fe62fd4a971aa07859476c2ba22c2254d4a1baa4e10b95ad"},
+    {file = "psutil-5.9.4-cp27-cp27m-win_amd64.whl", hash = "sha256:9120cd39dca5c5e1c54b59a41d205023d436799b1c8c4d3ff71af18535728e94"},
+    {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:6b92c532979bafc2df23ddc785ed116fced1f492ad90a6830cf24f4d1ea27d24"},
+    {file = "psutil-5.9.4-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:efeae04f9516907be44904cc7ce08defb6b665128992a56957abc9b61dca94b7"},
+    {file = "psutil-5.9.4-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:54d5b184728298f2ca8567bf83c422b706200bcbbfafdc06718264f9393cfeb7"},
+    {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16653106f3b59386ffe10e0bad3bb6299e169d5327d3f187614b1cb8f24cf2e1"},
+    {file = "psutil-5.9.4-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54c0d3d8e0078b7666984e11b12b88af2db11d11249a8ac8920dd5ef68a66e08"},
+    {file = "psutil-5.9.4-cp36-abi3-win32.whl", hash = "sha256:149555f59a69b33f056ba1c4eb22bb7bf24332ce631c44a319cec09f876aaeff"},
+    {file = "psutil-5.9.4-cp36-abi3-win_amd64.whl", hash = "sha256:fd8522436a6ada7b4aad6638662966de0d61d241cb821239b2ae7013d41a43d4"},
+    {file = "psutil-5.9.4-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:6001c809253a29599bc0dfd5179d9f8a5779f9dffea1da0f13c53ee568115e1e"},
+    {file = "psutil-5.9.4.tar.gz", hash = "sha256:3d7f9739eb435d4b1338944abe23f49584bde5395f27487d2ee25ad9a8774a62"},
+]
 ptyprocess = [
     {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"},
     {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"},
@@ -2361,54 +3224,92 @@ py = [
     {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
     {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
 ]
-pyarrow = []
+pyarrow = [
+    {file = "pyarrow-10.0.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:e00174764a8b4e9d8d5909b6d19ee0c217a6cf0232c5682e31fdfbd5a9f0ae52"},
+    {file = "pyarrow-10.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6f7a7dbe2f7f65ac1d0bd3163f756deb478a9e9afc2269557ed75b1b25ab3610"},
+    {file = "pyarrow-10.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb627673cb98708ef00864e2e243f51ba7b4c1b9f07a1d821f98043eccd3f585"},
+    {file = "pyarrow-10.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba71e6fc348c92477586424566110d332f60d9a35cb85278f42e3473bc1373da"},
+    {file = "pyarrow-10.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:7b4ede715c004b6fc535de63ef79fa29740b4080639a5ff1ea9ca84e9282f349"},
+    {file = "pyarrow-10.0.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:e3fe5049d2e9ca661d8e43fab6ad5a4c571af12d20a57dffc392a014caebef65"},
+    {file = "pyarrow-10.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:254017ca43c45c5098b7f2a00e995e1f8346b0fb0be225f042838323bb55283c"},
+    {file = "pyarrow-10.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70acca1ece4322705652f48db65145b5028f2c01c7e426c5d16a30ba5d739c24"},
+    {file = "pyarrow-10.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abb57334f2c57979a49b7be2792c31c23430ca02d24becd0b511cbe7b6b08649"},
+    {file = "pyarrow-10.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1765a18205eb1e02ccdedb66049b0ec148c2a0cb52ed1fb3aac322dfc086a6ee"},
+    {file = "pyarrow-10.0.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:61f4c37d82fe00d855d0ab522c685262bdeafd3fbcb5fe596fe15025fbc7341b"},
+    {file = "pyarrow-10.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e141a65705ac98fa52a9113fe574fdaf87fe0316cde2dffe6b94841d3c61544c"},
+    {file = "pyarrow-10.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bf26f809926a9d74e02d76593026f0aaeac48a65b64f1bb17eed9964bfe7ae1a"},
+    {file = "pyarrow-10.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:443eb9409b0cf78df10ced326490e1a300205a458fbeb0767b6b31ab3ebae6b2"},
+    {file = "pyarrow-10.0.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:f2d00aa481becf57098e85d99e34a25dba5a9ade2f44eb0b7d80c80f2984fc03"},
+    {file = "pyarrow-10.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b1fc226d28c7783b52a84d03a66573d5a22e63f8a24b841d5fc68caeed6784d4"},
+    {file = "pyarrow-10.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efa59933b20183c1c13efc34bd91efc6b2997377c4c6ad9272da92d224e3beb1"},
+    {file = "pyarrow-10.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:668e00e3b19f183394388a687d29c443eb000fb3fe25599c9b4762a0afd37775"},
+    {file = "pyarrow-10.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:d1bc6e4d5d6f69e0861d5d7f6cf4d061cf1069cb9d490040129877acf16d4c2a"},
+    {file = "pyarrow-10.0.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:42ba7c5347ce665338f2bc64685d74855900200dac81a972d49fe127e8132f75"},
+    {file = "pyarrow-10.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b069602eb1fc09f1adec0a7bdd7897f4d25575611dfa43543c8b8a75d99d6874"},
+    {file = "pyarrow-10.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94fb4a0c12a2ac1ed8e7e2aa52aade833772cf2d3de9dde685401b22cec30002"},
+    {file = "pyarrow-10.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db0c5986bf0808927f49640582d2032a07aa49828f14e51f362075f03747d198"},
+    {file = "pyarrow-10.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0ec7587d759153f452d5263dbc8b1af318c4609b607be2bd5127dcda6708cdb1"},
+    {file = "pyarrow-10.0.1.tar.gz", hash = "sha256:1a14f57a5f472ce8234f2964cd5184cccaa8df7e04568c64edc33b23eb285dd5"},
+]
 pycodestyle = [
-    {file = "pycodestyle-2.8.0-py2.py3-none-any.whl", hash = "sha256:720f8b39dde8b293825e7ff02c475f3077124006db4f440dcbc9a20b76548a20"},
-    {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"},
+    {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"},
+    {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"},
 ]
 pycparser = [
     {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"},
     {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"},
 ]
-pydocstyle = [
-    {file = "pydocstyle-6.1.1-py3-none-any.whl", hash = "sha256:6987826d6775056839940041beef5c08cc7e3d71d63149b48e36727f70144dc4"},
-    {file = "pydocstyle-6.1.1.tar.gz", hash = "sha256:1d41b7c459ba0ee6c345f2eb9ae827cab14a7533a88c5c6f7e94923f72df92dc"},
-]
 pyflakes = [
-    {file = "pyflakes-2.4.0-py2.py3-none-any.whl", hash = "sha256:3bb3a3f256f4b7968c9c788781e4ff07dce46bdf12339dcda61053375426ee2e"},
-    {file = "pyflakes-2.4.0.tar.gz", hash = "sha256:05a85c2872edf37a4ed30b0cce2f6093e1d0581f8c19d7393122da7e25b2b24c"},
+    {file = "pyflakes-3.0.1-py2.py3-none-any.whl", hash = "sha256:ec55bf7fe21fff7f1ad2f7da62363d749e2a470500eab1b555334b67aa1ef8cf"},
+    {file = "pyflakes-3.0.1.tar.gz", hash = "sha256:ec8b276a6b60bd80defed25add7e439881c19e64850afd9b346283d4165fd0fd"},
+]
+pygments = [
+    {file = "Pygments-2.13.0-py3-none-any.whl", hash = "sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42"},
+    {file = "Pygments-2.13.0.tar.gz", hash = "sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1"},
+]
+pylint = [
+    {file = "pylint-2.15.7-py3-none-any.whl", hash = "sha256:1d561d1d3e8be9dd880edc685162fbdaa0409c88b9b7400873c0cf345602e326"},
+    {file = "pylint-2.15.7.tar.gz", hash = "sha256:91e4776dbcb4b4d921a3e4b6fec669551107ba11f29d9199154a01622e460a57"},
 ]
-pygments = []
-pylint = []
 pyparsing = [
     {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
     {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
 ]
 pytest = [
-    {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"},
-    {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"},
+    {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"},
+    {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"},
+]
+pytest-cov = [
+    {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"},
+    {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"},
 ]
 python-dateutil = [
     {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"},
 ]
-pytz = []
-pyupgrade = []
+pytz = [
+    {file = "pytz-2022.6-py2.py3-none-any.whl", hash = "sha256:222439474e9c98fced559f1709d89e6c9cbf8d79c794ff3eb9f8800064291427"},
+    {file = "pytz-2022.6.tar.gz", hash = "sha256:e89512406b793ca39f5971bc999cc538ce125c0e51c27941bef4568b460095e2"},
+]
+pyupgrade = [
+    {file = "pyupgrade-2.38.4-py2.py3-none-any.whl", hash = "sha256:944ff993c396ddc2b9012eb3de4cda138eb4c149b22c6c560d4c8bfd0e180982"},
+    {file = "pyupgrade-2.38.4.tar.gz", hash = "sha256:1eb43a49f416752929741ba4d706bf3f33593d3cac9bdc217fc1ef55c047c1f4"},
+]
 pywin32 = [
-    {file = "pywin32-304-cp310-cp310-win32.whl", hash = "sha256:3c7bacf5e24298c86314f03fa20e16558a4e4138fc34615d7de4070c23e65af3"},
-    {file = "pywin32-304-cp310-cp310-win_amd64.whl", hash = "sha256:4f32145913a2447736dad62495199a8e280a77a0ca662daa2332acf849f0be48"},
-    {file = "pywin32-304-cp310-cp310-win_arm64.whl", hash = "sha256:d3ee45adff48e0551d1aa60d2ec066fec006083b791f5c3527c40cd8aefac71f"},
-    {file = "pywin32-304-cp311-cp311-win32.whl", hash = "sha256:30c53d6ce44c12a316a06c153ea74152d3b1342610f1b99d40ba2795e5af0269"},
-    {file = "pywin32-304-cp311-cp311-win_amd64.whl", hash = "sha256:7ffa0c0fa4ae4077e8b8aa73800540ef8c24530057768c3ac57c609f99a14fd4"},
-    {file = "pywin32-304-cp311-cp311-win_arm64.whl", hash = "sha256:cbbe34dad39bdbaa2889a424d28752f1b4971939b14b1bb48cbf0182a3bcfc43"},
-    {file = "pywin32-304-cp36-cp36m-win32.whl", hash = "sha256:be253e7b14bc601718f014d2832e4c18a5b023cbe72db826da63df76b77507a1"},
-    {file = "pywin32-304-cp36-cp36m-win_amd64.whl", hash = "sha256:de9827c23321dcf43d2f288f09f3b6d772fee11e809015bdae9e69fe13213988"},
-    {file = "pywin32-304-cp37-cp37m-win32.whl", hash = "sha256:f64c0377cf01b61bd5e76c25e1480ca8ab3b73f0c4add50538d332afdf8f69c5"},
-    {file = "pywin32-304-cp37-cp37m-win_amd64.whl", hash = "sha256:bb2ea2aa81e96eee6a6b79d87e1d1648d3f8b87f9a64499e0b92b30d141e76df"},
-    {file = "pywin32-304-cp38-cp38-win32.whl", hash = "sha256:94037b5259701988954931333aafd39cf897e990852115656b014ce72e052e96"},
-    {file = "pywin32-304-cp38-cp38-win_amd64.whl", hash = "sha256:ead865a2e179b30fb717831f73cf4373401fc62fbc3455a0889a7ddac848f83e"},
-    {file = "pywin32-304-cp39-cp39-win32.whl", hash = "sha256:25746d841201fd9f96b648a248f731c1dec851c9a08b8e33da8b56148e4c65cc"},
-    {file = "pywin32-304-cp39-cp39-win_amd64.whl", hash = "sha256:d24a3382f013b21aa24a5cfbfad5a2cd9926610c0affde3e8ab5b3d7dbcf4ac9"},
+    {file = "pywin32-305-cp310-cp310-win32.whl", hash = "sha256:421f6cd86e84bbb696d54563c48014b12a23ef95a14e0bdba526be756d89f116"},
+    {file = "pywin32-305-cp310-cp310-win_amd64.whl", hash = "sha256:73e819c6bed89f44ff1d690498c0a811948f73777e5f97c494c152b850fad478"},
+    {file = "pywin32-305-cp310-cp310-win_arm64.whl", hash = "sha256:742eb905ce2187133a29365b428e6c3b9001d79accdc30aa8969afba1d8470f4"},
+    {file = "pywin32-305-cp311-cp311-win32.whl", hash = "sha256:19ca459cd2e66c0e2cc9a09d589f71d827f26d47fe4a9d09175f6aa0256b51c2"},
+    {file = "pywin32-305-cp311-cp311-win_amd64.whl", hash = "sha256:326f42ab4cfff56e77e3e595aeaf6c216712bbdd91e464d167c6434b28d65990"},
+    {file = "pywin32-305-cp311-cp311-win_arm64.whl", hash = "sha256:4ecd404b2c6eceaca52f8b2e3e91b2187850a1ad3f8b746d0796a98b4cea04db"},
+    {file = "pywin32-305-cp36-cp36m-win32.whl", hash = "sha256:48d8b1659284f3c17b68587af047d110d8c44837736b8932c034091683e05863"},
+    {file = "pywin32-305-cp36-cp36m-win_amd64.whl", hash = "sha256:13362cc5aa93c2beaf489c9c9017c793722aeb56d3e5166dadd5ef82da021fe1"},
+    {file = "pywin32-305-cp37-cp37m-win32.whl", hash = "sha256:a55db448124d1c1484df22fa8bbcbc45c64da5e6eae74ab095b9ea62e6d00496"},
+    {file = "pywin32-305-cp37-cp37m-win_amd64.whl", hash = "sha256:109f98980bfb27e78f4df8a51a8198e10b0f347257d1e265bb1a32993d0c973d"},
+    {file = "pywin32-305-cp38-cp38-win32.whl", hash = "sha256:9dd98384da775afa009bc04863426cb30596fd78c6f8e4e2e5bbf4edf8029504"},
+    {file = "pywin32-305-cp38-cp38-win_amd64.whl", hash = "sha256:56d7a9c6e1a6835f521788f53b5af7912090674bb84ef5611663ee1595860fc7"},
+    {file = "pywin32-305-cp39-cp39-win32.whl", hash = "sha256:9d968c677ac4d5cbdaa62fd3014ab241718e619d8e36ef8e11fb930515a1e918"},
+    {file = "pywin32-305-cp39-cp39-win_amd64.whl", hash = "sha256:50768c6b7c3f0b38b7fb14dd4104da93ebced5f1a50dc0e834594bff6fbe1271"},
 ]
 pyyaml = [
     {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"},
@@ -2418,6 +3319,13 @@ pyyaml = [
     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
     {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
     {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
+    {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
+    {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
+    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
+    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
+    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
+    {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
+    {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
     {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
@@ -2445,13 +3353,180 @@ pyyaml = [
     {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"},
     {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"},
 ]
-pyzmq = []
+pyzmq = [
+    {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:28b119ba97129d3001673a697b7cce47fe6de1f7255d104c2f01108a5179a066"},
+    {file = "pyzmq-24.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bcbebd369493d68162cddb74a9c1fcebd139dfbb7ddb23d8f8e43e6c87bac3a6"},
+    {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae61446166983c663cee42c852ed63899e43e484abf080089f771df4b9d272ef"},
+    {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87f7ac99b15270db8d53f28c3c7b968612993a90a5cf359da354efe96f5372b4"},
+    {file = "pyzmq-24.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca7c3956b03b7663fac4d150f5e6d4f6f38b2462c1e9afd83bcf7019f17913"},
+    {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8c78bfe20d4c890cb5580a3b9290f700c570e167d4cdcc55feec07030297a5e3"},
+    {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:48f721f070726cd2a6e44f3c33f8ee4b24188e4b816e6dd8ba542c8c3bb5b246"},
+    {file = "pyzmq-24.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afe1f3bc486d0ce40abb0a0c9adb39aed3bbac36ebdc596487b0cceba55c21c1"},
+    {file = "pyzmq-24.0.1-cp310-cp310-win32.whl", hash = "sha256:3e6192dbcefaaa52ed81be88525a54a445f4b4fe2fffcae7fe40ebb58bd06bfd"},
+    {file = "pyzmq-24.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:86de64468cad9c6d269f32a6390e210ca5ada568c7a55de8e681ca3b897bb340"},
+    {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:838812c65ed5f7c2bd11f7b098d2e5d01685a3f6d1f82849423b570bae698c00"},
+    {file = "pyzmq-24.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:dfb992dbcd88d8254471760879d48fb20836d91baa90f181c957122f9592b3dc"},
+    {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7abddb2bd5489d30ffeb4b93a428130886c171b4d355ccd226e83254fcb6b9ef"},
+    {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94010bd61bc168c103a5b3b0f56ed3b616688192db7cd5b1d626e49f28ff51b3"},
+    {file = "pyzmq-24.0.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8242543c522d84d033fe79be04cb559b80d7eb98ad81b137ff7e0a9020f00ace"},
+    {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ccb94342d13e3bf3ffa6e62f95b5e3f0bc6bfa94558cb37f4b3d09d6feb536ff"},
+    {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6640f83df0ae4ae1104d4c62b77e9ef39be85ebe53f636388707d532bee2b7b8"},
+    {file = "pyzmq-24.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a180dbd5ea5d47c2d3b716d5c19cc3fb162d1c8db93b21a1295d69585bfddac1"},
+    {file = "pyzmq-24.0.1-cp311-cp311-win32.whl", hash = "sha256:624321120f7e60336be8ec74a172ae7fba5c3ed5bf787cc85f7e9986c9e0ebc2"},
+    {file = "pyzmq-24.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:1724117bae69e091309ffb8255412c4651d3f6355560d9af312d547f6c5bc8b8"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:15975747462ec49fdc863af906bab87c43b2491403ab37a6d88410635786b0f4"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b947e264f0e77d30dcbccbb00f49f900b204b922eb0c3a9f0afd61aaa1cedc3d"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0ec91f1bad66f3ee8c6deb65fa1fe418e8ad803efedd69c35f3b5502f43bd1dc"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:db03704b3506455d86ec72c3358a779e9b1d07b61220dfb43702b7b668edcd0d"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:e7e66b4e403c2836ac74f26c4b65d8ac0ca1eef41dfcac2d013b7482befaad83"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:7a23ccc1083c260fa9685c93e3b170baba45aeed4b524deb3f426b0c40c11639"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:fa0ae3275ef706c0309556061185dd0e4c4cd3b7d6f67ae617e4e677c7a41e2e"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-win32.whl", hash = "sha256:f01de4ec083daebf210531e2cca3bdb1608dbbbe00a9723e261d92087a1f6ebc"},
+    {file = "pyzmq-24.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:de4217b9eb8b541cf2b7fde4401ce9d9a411cc0af85d410f9d6f4333f43640be"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:78068e8678ca023594e4a0ab558905c1033b2d3e806a0ad9e3094e231e115a33"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77c2713faf25a953c69cf0f723d1b7dd83827b0834e6c41e3fb3bbc6765914a1"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bb4af15f305056e95ca1bd086239b9ebc6ad55e9f49076d27d80027f72752f6"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:0f14cffd32e9c4c73da66db97853a6aeceaac34acdc0fae9e5bbc9370281864c"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0108358dab8c6b27ff6b985c2af4b12665c1bc659648284153ee501000f5c107"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:d66689e840e75221b0b290b0befa86f059fb35e1ee6443bce51516d4d61b6b99"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae08ac90aa8fa14caafc7a6251bd218bf6dac518b7bff09caaa5e781119ba3f2"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-win32.whl", hash = "sha256:8421aa8c9b45ea608c205db9e1c0c855c7e54d0e9c2c2f337ce024f6843cab3b"},
+    {file = "pyzmq-24.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:54d8b9c5e288362ec8595c1d98666d36f2070fd0c2f76e2b3c60fbad9bd76227"},
+    {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:acbd0a6d61cc954b9f535daaa9ec26b0a60a0d4353c5f7c1438ebc88a359a47e"},
+    {file = "pyzmq-24.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:47b11a729d61a47df56346283a4a800fa379ae6a85870d5a2e1e4956c828eedc"},
+    {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abe6eb10122f0d746a0d510c2039ae8edb27bc9af29f6d1b05a66cc2401353ff"},
+    {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:07bec1a1b22dacf718f2c0e71b49600bb6a31a88f06527dfd0b5aababe3fa3f7"},
+    {file = "pyzmq-24.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0d945a85b70da97ae86113faf9f1b9294efe66bd4a5d6f82f2676d567338b66"},
+    {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1b7928bb7580736ffac5baf814097be342ba08d3cfdfb48e52773ec959572287"},
+    {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b946da90dc2799bcafa682692c1d2139b2a96ec3c24fa9fc6f5b0da782675330"},
+    {file = "pyzmq-24.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c8840f064b1fb377cffd3efeaad2b190c14d4c8da02316dae07571252d20b31f"},
+    {file = "pyzmq-24.0.1-cp38-cp38-win32.whl", hash = "sha256:4854f9edc5208f63f0841c0c667260ae8d6846cfa233c479e29fdc85d42ebd58"},
+    {file = "pyzmq-24.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:42d4f97b9795a7aafa152a36fe2ad44549b83a743fd3e77011136def512e6c2a"},
+    {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:52afb0ac962963fff30cf1be775bc51ae083ef4c1e354266ab20e5382057dd62"},
+    {file = "pyzmq-24.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bad8210ad4df68c44ff3685cca3cda448ee46e20d13edcff8909eba6ec01ca4"},
+    {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dabf1a05318d95b1537fd61d9330ef4313ea1216eea128a17615038859da3b3b"},
+    {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5bd3d7dfd9cd058eb68d9a905dec854f86649f64d4ddf21f3ec289341386c44b"},
+    {file = "pyzmq-24.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8012bce6836d3f20a6c9599f81dfa945f433dab4dbd0c4917a6fb1f998ab33d"},
+    {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c31805d2c8ade9b11feca4674eee2b9cce1fec3e8ddb7bbdd961a09dc76a80ea"},
+    {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3104f4b084ad5d9c0cb87445cc8cfd96bba710bef4a66c2674910127044df209"},
+    {file = "pyzmq-24.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:df0841f94928f8af9c7a1f0aaaffba1fb74607af023a152f59379c01c53aee58"},
+    {file = "pyzmq-24.0.1-cp39-cp39-win32.whl", hash = "sha256:a435ef8a3bd95c8a2d316d6e0ff70d0db524f6037411652803e118871d703333"},
+    {file = "pyzmq-24.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:2032d9cb994ce3b4cba2b8dfae08c7e25bc14ba484c770d4d3be33c27de8c45b"},
+    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bb5635c851eef3a7a54becde6da99485eecf7d068bd885ac8e6d173c4ecd68b0"},
+    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:83ea1a398f192957cb986d9206ce229efe0ee75e3c6635baff53ddf39bd718d5"},
+    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:941fab0073f0a54dc33d1a0460cb04e0d85893cb0c5e1476c785000f8b359409"},
+    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e8f482c44ccb5884bf3f638f29bea0f8dc68c97e38b2061769c4cb697f6140d"},
+    {file = "pyzmq-24.0.1-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:613010b5d17906c4367609e6f52e9a2595e35d5cc27d36ff3f1b6fa6e954d944"},
+    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:65c94410b5a8355cfcf12fd600a313efee46ce96a09e911ea92cf2acf6708804"},
+    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:20e7eeb1166087db636c06cae04a1ef59298627f56fb17da10528ab52a14c87f"},
+    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2712aee7b3834ace51738c15d9ee152cc5a98dc7d57dd93300461b792ab7b43"},
+    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a7c280185c4da99e0cc06c63bdf91f5b0b71deb70d8717f0ab870a43e376db8"},
+    {file = "pyzmq-24.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:858375573c9225cc8e5b49bfac846a77b696b8d5e815711b8d4ba3141e6e8879"},
+    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:80093b595921eed1a2cead546a683b9e2ae7f4a4592bb2ab22f70d30174f003a"},
+    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f3f3154fde2b1ff3aa7b4f9326347ebc89c8ef425ca1db8f665175e6d3bd42f"},
+    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abb756147314430bee5d10919b8493c0ccb109ddb7f5dfd2fcd7441266a25b75"},
+    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44e706bac34e9f50779cb8c39f10b53a4d15aebb97235643d3112ac20bd577b4"},
+    {file = "pyzmq-24.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:687700f8371643916a1d2c61f3fdaa630407dd205c38afff936545d7b7466066"},
+    {file = "pyzmq-24.0.1.tar.gz", hash = "sha256:216f5d7dbb67166759e59b0479bca82b8acf9bed6015b526b8eb10143fb08e77"},
+]
 recommonmark = [
     {file = "recommonmark-0.7.1-py2.py3-none-any.whl", hash = "sha256:1b1db69af0231efce3fa21b94ff627ea33dee7079a01dd0a7f8482c3da148b3f"},
     {file = "recommonmark-0.7.1.tar.gz", hash = "sha256:bdb4db649f2222dcd8d2d844f0006b958d627f732415d399791ee436a3686d67"},
 ]
-regex = []
-requests = []
+regex = [
+    {file = "regex-2022.10.31-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a8ff454ef0bb061e37df03557afda9d785c905dab15584860f982e88be73015f"},
+    {file = "regex-2022.10.31-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1eba476b1b242620c266edf6325b443a2e22b633217a9835a52d8da2b5c051f9"},
+    {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0e5af9a9effb88535a472e19169e09ce750c3d442fb222254a276d77808620b"},
+    {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d03fe67b2325cb3f09be029fd5da8df9e6974f0cde2c2ac6a79d2634e791dd57"},
+    {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a9d0b68ac1743964755ae2d89772c7e6fb0118acd4d0b7464eaf3921c6b49dd4"},
+    {file = "regex-2022.10.31-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a45b6514861916c429e6059a55cf7db74670eaed2052a648e3e4d04f070e001"},
+    {file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8b0886885f7323beea6f552c28bff62cbe0983b9fbb94126531693ea6c5ebb90"},
+    {file = "regex-2022.10.31-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5aefb84a301327ad115e9d346c8e2760009131d9d4b4c6b213648d02e2abe144"},
+    {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:702d8fc6f25bbf412ee706bd73019da5e44a8400861dfff7ff31eb5b4a1276dc"},
+    {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a3c1ebd4ed8e76e886507c9eddb1a891673686c813adf889b864a17fafcf6d66"},
+    {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:50921c140561d3db2ab9f5b11c5184846cde686bb5a9dc64cae442926e86f3af"},
+    {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:7db345956ecce0c99b97b042b4ca7326feeec6b75facd8390af73b18e2650ffc"},
+    {file = "regex-2022.10.31-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:763b64853b0a8f4f9cfb41a76a4a85a9bcda7fdda5cb057016e7706fde928e66"},
+    {file = "regex-2022.10.31-cp310-cp310-win32.whl", hash = "sha256:44136355e2f5e06bf6b23d337a75386371ba742ffa771440b85bed367c1318d1"},
+    {file = "regex-2022.10.31-cp310-cp310-win_amd64.whl", hash = "sha256:bfff48c7bd23c6e2aec6454aaf6edc44444b229e94743b34bdcdda2e35126cf5"},
+    {file = "regex-2022.10.31-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b4b1fe58cd102d75ef0552cf17242705ce0759f9695334a56644ad2d83903fe"},
+    {file = "regex-2022.10.31-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:542e3e306d1669b25936b64917285cdffcd4f5c6f0247636fec037187bd93542"},
+    {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c27cc1e4b197092e50ddbf0118c788d9977f3f8f35bfbbd3e76c1846a3443df7"},
+    {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8e38472739028e5f2c3a4aded0ab7eadc447f0d84f310c7a8bb697ec417229e"},
+    {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:76c598ca73ec73a2f568e2a72ba46c3b6c8690ad9a07092b18e48ceb936e9f0c"},
+    {file = "regex-2022.10.31-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c28d3309ebd6d6b2cf82969b5179bed5fefe6142c70f354ece94324fa11bf6a1"},
+    {file = "regex-2022.10.31-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9af69f6746120998cd9c355e9c3c6aec7dff70d47247188feb4f829502be8ab4"},
+    {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a5f9505efd574d1e5b4a76ac9dd92a12acb2b309551e9aa874c13c11caefbe4f"},
+    {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5ff525698de226c0ca743bfa71fc6b378cda2ddcf0d22d7c37b1cc925c9650a5"},
+    {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe7fda2fe7c8890d454f2cbc91d6c01baf206fbc96d89a80241a02985118c0c"},
+    {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2cdc55ca07b4e70dda898d2ab7150ecf17c990076d3acd7a5f3b25cb23a69f1c"},
+    {file = "regex-2022.10.31-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:44a6c2f6374e0033873e9ed577a54a3602b4f609867794c1a3ebba65e4c93ee7"},
+    {file = "regex-2022.10.31-cp311-cp311-win32.whl", hash = "sha256:d8716f82502997b3d0895d1c64c3b834181b1eaca28f3f6336a71777e437c2af"},
+    {file = "regex-2022.10.31-cp311-cp311-win_amd64.whl", hash = "sha256:61edbca89aa3f5ef7ecac8c23d975fe7261c12665f1d90a6b1af527bba86ce61"},
+    {file = "regex-2022.10.31-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:0a069c8483466806ab94ea9068c34b200b8bfc66b6762f45a831c4baaa9e8cdd"},
+    {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d26166acf62f731f50bdd885b04b38828436d74e8e362bfcb8df221d868b5d9b"},
+    {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac741bf78b9bb432e2d314439275235f41656e189856b11fb4e774d9f7246d81"},
+    {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75f591b2055523fc02a4bbe598aa867df9e953255f0b7f7715d2a36a9c30065c"},
+    {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b30bddd61d2a3261f025ad0f9ee2586988c6a00c780a2fb0a92cea2aa702c54"},
+    {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef4163770525257876f10e8ece1cf25b71468316f61451ded1a6f44273eedeb5"},
+    {file = "regex-2022.10.31-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7b280948d00bd3973c1998f92e22aa3ecb76682e3a4255f33e1020bd32adf443"},
+    {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:d0213671691e341f6849bf33cd9fad21f7b1cb88b89e024f33370733fec58742"},
+    {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:22e7ebc231d28393dfdc19b185d97e14a0f178bedd78e85aad660e93b646604e"},
+    {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:8ad241da7fac963d7573cc67a064c57c58766b62a9a20c452ca1f21050868dfa"},
+    {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:586b36ebda81e6c1a9c5a5d0bfdc236399ba6595e1397842fd4a45648c30f35e"},
+    {file = "regex-2022.10.31-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0653d012b3bf45f194e5e6a41df9258811ac8fc395579fa82958a8b76286bea4"},
+    {file = "regex-2022.10.31-cp36-cp36m-win32.whl", hash = "sha256:144486e029793a733e43b2e37df16a16df4ceb62102636ff3db6033994711066"},
+    {file = "regex-2022.10.31-cp36-cp36m-win_amd64.whl", hash = "sha256:c14b63c9d7bab795d17392c7c1f9aaabbffd4cf4387725a0ac69109fb3b550c6"},
+    {file = "regex-2022.10.31-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4cac3405d8dda8bc6ed499557625585544dd5cbf32072dcc72b5a176cb1271c8"},
+    {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23cbb932cc53a86ebde0fb72e7e645f9a5eec1a5af7aa9ce333e46286caef783"},
+    {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74bcab50a13960f2a610cdcd066e25f1fd59e23b69637c92ad470784a51b1347"},
+    {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:78d680ef3e4d405f36f0d6d1ea54e740366f061645930072d39bca16a10d8c93"},
+    {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce6910b56b700bea7be82c54ddf2e0ed792a577dfaa4a76b9af07d550af435c6"},
+    {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:659175b2144d199560d99a8d13b2228b85e6019b6e09e556209dfb8c37b78a11"},
+    {file = "regex-2022.10.31-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1ddf14031a3882f684b8642cb74eea3af93a2be68893901b2b387c5fd92a03ec"},
+    {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b683e5fd7f74fb66e89a1ed16076dbab3f8e9f34c18b1979ded614fe10cdc4d9"},
+    {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2bde29cc44fa81c0a0c8686992c3080b37c488df167a371500b2a43ce9f026d1"},
+    {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4919899577ba37f505aaebdf6e7dc812d55e8f097331312db7f1aab18767cce8"},
+    {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:9c94f7cc91ab16b36ba5ce476f1904c91d6c92441f01cd61a8e2729442d6fcf5"},
+    {file = "regex-2022.10.31-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ae1e96785696b543394a4e3f15f3f225d44f3c55dafe3f206493031419fedf95"},
+    {file = "regex-2022.10.31-cp37-cp37m-win32.whl", hash = "sha256:c670f4773f2f6f1957ff8a3962c7dd12e4be54d05839b216cb7fd70b5a1df394"},
+    {file = "regex-2022.10.31-cp37-cp37m-win_amd64.whl", hash = "sha256:8e0caeff18b96ea90fc0eb6e3bdb2b10ab5b01a95128dfeccb64a7238decf5f0"},
+    {file = "regex-2022.10.31-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:131d4be09bea7ce2577f9623e415cab287a3c8e0624f778c1d955ec7c281bd4d"},
+    {file = "regex-2022.10.31-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:e613a98ead2005c4ce037c7b061f2409a1a4e45099edb0ef3200ee26ed2a69a8"},
+    {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052b670fafbe30966bbe5d025e90b2a491f85dfe5b2583a163b5e60a85a321ad"},
+    {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa62a07ac93b7cb6b7d0389d8ef57ffc321d78f60c037b19dfa78d6b17c928ee"},
+    {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5352bea8a8f84b89d45ccc503f390a6be77917932b1c98c4cdc3565137acc714"},
+    {file = "regex-2022.10.31-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:20f61c9944f0be2dc2b75689ba409938c14876c19d02f7585af4460b6a21403e"},
+    {file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29c04741b9ae13d1e94cf93fca257730b97ce6ea64cfe1eba11cf9ac4e85afb6"},
+    {file = "regex-2022.10.31-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:543883e3496c8b6d58bd036c99486c3c8387c2fc01f7a342b760c1ea3158a318"},
+    {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7a8b43ee64ca8f4befa2bea4083f7c52c92864d8518244bfa6e88c751fa8fff"},
+    {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6a9a19bea8495bb419dc5d38c4519567781cd8d571c72efc6aa959473d10221a"},
+    {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:6ffd55b5aedc6f25fd8d9f905c9376ca44fcf768673ffb9d160dd6f409bfda73"},
+    {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:4bdd56ee719a8f751cf5a593476a441c4e56c9b64dc1f0f30902858c4ef8771d"},
+    {file = "regex-2022.10.31-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ca88da1bd78990b536c4a7765f719803eb4f8f9971cc22d6ca965c10a7f2c4c"},
+    {file = "regex-2022.10.31-cp38-cp38-win32.whl", hash = "sha256:5a260758454580f11dd8743fa98319bb046037dfab4f7828008909d0aa5292bc"},
+    {file = "regex-2022.10.31-cp38-cp38-win_amd64.whl", hash = "sha256:5e6a5567078b3eaed93558842346c9d678e116ab0135e22eb72db8325e90b453"},
+    {file = "regex-2022.10.31-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5217c25229b6a85049416a5c1e6451e9060a1edcf988641e309dbe3ab26d3e49"},
+    {file = "regex-2022.10.31-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4bf41b8b0a80708f7e0384519795e80dcb44d7199a35d52c15cc674d10b3081b"},
+    {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf0da36a212978be2c2e2e2d04bdff46f850108fccc1851332bcae51c8907cc"},
+    {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d403d781b0e06d2922435ce3b8d2376579f0c217ae491e273bab8d092727d244"},
+    {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a37d51fa9a00d265cf73f3de3930fa9c41548177ba4f0faf76e61d512c774690"},
+    {file = "regex-2022.10.31-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4f781ffedd17b0b834c8731b75cce2639d5a8afe961c1e58ee7f1f20b3af185"},
+    {file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d243b36fbf3d73c25e48014961e83c19c9cc92530516ce3c43050ea6276a2ab7"},
+    {file = "regex-2022.10.31-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:370f6e97d02bf2dd20d7468ce4f38e173a124e769762d00beadec3bc2f4b3bc4"},
+    {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:597f899f4ed42a38df7b0e46714880fb4e19a25c2f66e5c908805466721760f5"},
+    {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7dbdce0c534bbf52274b94768b3498abdf675a691fec5f751b6057b3030f34c1"},
+    {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:22960019a842777a9fa5134c2364efaed5fbf9610ddc5c904bd3a400973b0eb8"},
+    {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:7f5a3ffc731494f1a57bd91c47dc483a1e10048131ffb52d901bfe2beb6102e8"},
+    {file = "regex-2022.10.31-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7ef6b5942e6bfc5706301a18a62300c60db9af7f6368042227ccb7eeb22d0892"},
+    {file = "regex-2022.10.31-cp39-cp39-win32.whl", hash = "sha256:395161bbdbd04a8333b9ff9763a05e9ceb4fe210e3c7690f5e68cedd3d65d8e1"},
+    {file = "regex-2022.10.31-cp39-cp39-win_amd64.whl", hash = "sha256:957403a978e10fb3ca42572a23e6f7badff39aa1ce2f4ade68ee452dc6807692"},
+    {file = "regex-2022.10.31.tar.gz", hash = "sha256:a3a98921da9a1bf8457aeee6a551948a83601689e5ecdd736894ea9bbec77e83"},
+]
+requests = [
+    {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
+    {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
+]
 responses = [
     {file = "responses-0.18.0-py3-none-any.whl", hash = "sha256:15c63ad16de13ee8e7182d99c9334f64fd81f1ee79f90748d527c28f7ca9dd51"},
     {file = "responses-0.18.0.tar.gz", hash = "sha256:380cad4c1c1dc942e5e8a8eaae0b4d4edf708f4f010db8b7bcfafad1fcd254ff"},
@@ -2460,14 +3535,142 @@ rich = [
     {file = "rich-10.16.2-py3-none-any.whl", hash = "sha256:c59d73bd804c90f747c8d7b1d023b88f2a9ac2454224a4aeaf959b21eeb42d03"},
     {file = "rich-10.16.2.tar.gz", hash = "sha256:720974689960e06c2efdb54327f8bf0cdbdf4eae4ad73b6c94213cad405c371b"},
 ]
+ruamel-yaml = [
+    {file = "ruamel.yaml-0.17.21-py3-none-any.whl", hash = "sha256:742b35d3d665023981bd6d16b3d24248ce5df75fdb4e2924e93a05c1f8b61ca7"},
+    {file = "ruamel.yaml-0.17.21.tar.gz", hash = "sha256:8b7ce697a2f212752a35c1ac414471dc16c424c9573be4926b56ff3f5d23b7af"},
+]
+ruamel-yaml-clib = [
+    {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_12_6_arm64.whl", hash = "sha256:721bc4ba4525f53f6a611ec0967bdcee61b31df5a56801281027a3a6d1c2daf5"},
+    {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"},
+]
 safety = [
-    {file = "safety-1.10.3-py2.py3-none-any.whl", hash = "sha256:5f802ad5df5614f9622d8d71fedec2757099705c2356f862847c58c6dfe13e84"},
-    {file = "safety-1.10.3.tar.gz", hash = "sha256:30e394d02a20ac49b7f65292d19d38fa927a8f9582cdfd3ad1adbbc66c641ad5"},
+    {file = "safety-2.3.3-py3-none-any.whl", hash = "sha256:c12b2aaf3495faf42951fdd91d3c5ce6ecffd05efa423a29244408b72c556744"},
+    {file = "safety-2.3.3.tar.gz", hash = "sha256:2e17cf127472ca720cdcc65f834008b555a10fe56627646009ab7565dd2459cf"},
+]
+scikit-learn = [
+    {file = "scikit-learn-1.1.3.tar.gz", hash = "sha256:bef51978a51ec19977700fe7b86aecea49c825884f3811756b74a3b152bb4e35"},
+    {file = "scikit_learn-1.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8e9dd76c7274055d1acf4526b8efb16a3531c26dcda714a0c16da99bf9d41900"},
+    {file = "scikit_learn-1.1.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ee47f68d973cee7009f06edb956f2f5588a0f230f24a2a70175fd0ecf36e2653"},
+    {file = "scikit_learn-1.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da5a2e95fef9805b1750e4abda4e834bf8835d26fc709a391543b53feee7bd0e"},
+    {file = "scikit_learn-1.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:701181792a28c82fecae12adb5d15d0ecf57bffab7cf4bdbb52c7b3fd428d540"},
+    {file = "scikit_learn-1.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:30e27721adc308e8fd9f419f43068e43490005f911edf4476a9e585059fa8a83"},
+    {file = "scikit_learn-1.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5699cded6c0685426433c7e5afe0fecad80ec831ec7fa264940e50c796775cc5"},
+    {file = "scikit_learn-1.1.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:2ee2c649f2231b68511aabb0dc827edd8936aad682acc6263c34aed11bc95dac"},
+    {file = "scikit_learn-1.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6d1c1394e38a3319ace620381f6f23cc807d8780e9915c152449a86fc8f1db21"},
+    {file = "scikit_learn-1.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:250da993701da88bf475e7c5746abf1285ea0ae47e4d0917cd13afd6600bb162"},
+    {file = "scikit_learn-1.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:fd3ee69d36d42a7dcbb17e355a5653af5fd241a7dfd9133080b3dde8d9e2aafb"},
+    {file = "scikit_learn-1.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f5644663987ee221f5d1f47a593271b966c271c236fe05634e6bdc06041b5a2b"},
+    {file = "scikit_learn-1.1.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:748f2bd632d6993e8918d43f1a26c380aeda4e122a88840d4c3a9af99d4239fe"},
+    {file = "scikit_learn-1.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd55c6fbef7608dbce1f22baf289dfcc6eb323247daa3c3542f73d389c724786"},
+    {file = "scikit_learn-1.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38814f66285318f2e241305cca545eaa9b4126c65aa5dd78c69371f235f78e2b"},
+    {file = "scikit_learn-1.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:f4931f2a6c06e02c6c17a05f8ae397e2545965bc7a0a6cb38c8cd7d4fba8624d"},
+    {file = "scikit_learn-1.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6785b8a3093329bf90ac01801be5525551728ae73edb11baa175df660820add4"},
+    {file = "scikit_learn-1.1.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:28b2bd6a1419acd522ff45d282c8ba23dbccb5338802ab0ee12baa4ade0aba4c"},
+    {file = "scikit_learn-1.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23fb9e74b813cc2528b5167d82ed08950b11106ccf50297161875e45152fb311"},
+    {file = "scikit_learn-1.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5d4231af7199531e77da1b78a4cc6b3d960a00b1ec672578ac818aae2b9c35d"},
+    {file = "scikit_learn-1.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:4d3a19166d4e1cdfcab975c68f471e046ce01e74c42a9a33fa89a14c2fcedf60"},
+]
+scipy = [
+    {file = "scipy-1.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1884b66a54887e21addf9c16fb588720a8309a57b2e258ae1c7986d4444d3bc0"},
+    {file = "scipy-1.9.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:83b89e9586c62e787f5012e8475fbb12185bafb996a03257e9675cd73d3736dd"},
+    {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a72d885fa44247f92743fc20732ae55564ff2a519e8302fb7e18717c5355a8b"},
+    {file = "scipy-1.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d01e1dd7b15bd2449c8bfc6b7cc67d630700ed655654f0dfcf121600bad205c9"},
+    {file = "scipy-1.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:68239b6aa6f9c593da8be1509a05cb7f9efe98b80f43a5861cd24c7557e98523"},
+    {file = "scipy-1.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b41bc822679ad1c9a5f023bc93f6d0543129ca0f37c1ce294dd9d386f0a21096"},
+    {file = "scipy-1.9.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:90453d2b93ea82a9f434e4e1cba043e779ff67b92f7a0e85d05d286a3625df3c"},
+    {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83c06e62a390a9167da60bedd4575a14c1f58ca9dfde59830fc42e5197283dab"},
+    {file = "scipy-1.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abaf921531b5aeaafced90157db505e10345e45038c39e5d9b6c7922d68085cb"},
+    {file = "scipy-1.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:06d2e1b4c491dc7d8eacea139a1b0b295f74e1a1a0f704c375028f8320d16e31"},
+    {file = "scipy-1.9.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5a04cd7d0d3eff6ea4719371cbc44df31411862b9646db617c99718ff68d4840"},
+    {file = "scipy-1.9.3-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:545c83ffb518094d8c9d83cce216c0c32f8c04aaf28b92cc8283eda0685162d5"},
+    {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d54222d7a3ba6022fdf5773931b5d7c56efe41ede7f7128c7b1637700409108"},
+    {file = "scipy-1.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cff3a5295234037e39500d35316a4c5794739433528310e117b8a9a0c76d20fc"},
+    {file = "scipy-1.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:2318bef588acc7a574f5bfdff9c172d0b1bf2c8143d9582e05f878e580a3781e"},
+    {file = "scipy-1.9.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d644a64e174c16cb4b2e41dfea6af722053e83d066da7343f333a54dae9bc31c"},
+    {file = "scipy-1.9.3-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:da8245491d73ed0a994ed9c2e380fd058ce2fa8a18da204681f2fe1f57f98f95"},
+    {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4db5b30849606a95dcf519763dd3ab6fe9bd91df49eba517359e450a7d80ce2e"},
+    {file = "scipy-1.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c68db6b290cbd4049012990d7fe71a2abd9ffbe82c0056ebe0f01df8be5436b0"},
+    {file = "scipy-1.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:5b88e6d91ad9d59478fafe92a7c757d00c59e3bdc3331be8ada76a4f8d683f58"},
+    {file = "scipy-1.9.3.tar.gz", hash = "sha256:fbc5c05c85c1a02be77b1ff591087c83bc44579c6d2bd9fb798bb64ea5e1a027"},
+]
+sentencepiece = [
+    {file = "sentencepiece-0.1.97-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f249c8f1852893be86eae66b19d522c5fb30bbad4fe2d1b07f06fdc86e1907e"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09e1bc53178de70c557a9ba4fece07364b4416ce3d36570726b3372b68aea135"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:667193c57fb48b238be7e3d7636cfc8da56cb5bac5559d8f0b647334e1175be8"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2780531985af79c6163f63d4f200fec8a28b70b6768d2c19f70d01568a4524e8"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:205050670c53ef9015e2a98cce3934bfbcf0aafaa14caa0c618dd5667bc217ee"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28b183dadef8e8b6b4645c1c20692d7be0a13ecc3ec1a07b3885c8905516675f"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-win32.whl", hash = "sha256:ee3c9dbd558d8d85bb1617087b86df6ea2b856a528669630ce6cedeb4353b823"},
+    {file = "sentencepiece-0.1.97-cp310-cp310-win_amd64.whl", hash = "sha256:f7dc55379e2f7dee86537180283db2e5f8418c6825fdd2fe436c724eb5604c05"},
+    {file = "sentencepiece-0.1.97-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ba1b4154f9144c5a7528b00aff5cffaa1a896a1c6ca53ca78b6e74cd2dae5244"},
+    {file = "sentencepiece-0.1.97-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac3d90aee5581e55d029d124ac11b6ae2fbae0817863b664b2f2302e966ababb"},
+    {file = "sentencepiece-0.1.97-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c27400f1ac46518a01c87cb7703650e4e48728649feb115d2e3f1102a946a42"},
+    {file = "sentencepiece-0.1.97-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6e12a166eba75994ca749aadc4a5056b91b31405f805d6de6e8914cc9741c60"},
+    {file = "sentencepiece-0.1.97-cp36-cp36m-win32.whl", hash = "sha256:ed85dff5c0a9b3dd1a414c7e1119f2a19e863fc3f81da525bf7f885ebc883de0"},
+    {file = "sentencepiece-0.1.97-cp36-cp36m-win_amd64.whl", hash = "sha256:91a19ab6f40ffbae6d6127119953d2c6a85e93d734953dbc8629fde0d21ace66"},
+    {file = "sentencepiece-0.1.97-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bae580e4a35a9314ff49561ac7c06574fe6afc71b821ed6bb00534e571458156"},
+    {file = "sentencepiece-0.1.97-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ad7262e7530c683b186672b5dd0082f82719a50a500a8cfbc4bbd7cde5bff8c"},
+    {file = "sentencepiece-0.1.97-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:620cee35279720016735a7c7103cddbd9b84fe5e2f098bd5e673834d69fee2b8"},
+    {file = "sentencepiece-0.1.97-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93b921b59914c0ec6697e8c6d5e6b44d99d1298fb1a0af56980a79ade0540c19"},
+    {file = "sentencepiece-0.1.97-cp37-cp37m-win32.whl", hash = "sha256:9b9a4c44a31d5f47616e9568dcf31e029b0bfa776e0a252c0b59247881598b09"},
+    {file = "sentencepiece-0.1.97-cp37-cp37m-win_amd64.whl", hash = "sha256:f31533cdacced56219e239d3459a003ece35116920dd64b2309d4ad047b77644"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7d643c01d1cad13b9206a276bbe5bc1a468e3d7cf6a26bde7783f945277f859d"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:542f1985b1ee279a92bef7740ec0781452372028ce01e15aa88df3228b197ba3"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:93701da21fea906dd244bf88cdbe640385a89c45d3c1812b76dbadf8782cdbcd"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a51514047b964047b7fadb480d88a5e0f72c02f6ca1ba96258fbbc6e79274a94"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e3ae2e9b7a5b6f2aa64ec9240b0c185dabe597d0e787dc4344acfbaef1ffe0b2"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923ee4af16dbae1f2ab358ed09f8a0eb89e40a8198a8b343bf54181482342721"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-win32.whl", hash = "sha256:fa6f2b88850b5fae3a05053658824cf9f147c8e3c3b40eb64539a976c83d8a24"},
+    {file = "sentencepiece-0.1.97-cp38-cp38-win_amd64.whl", hash = "sha256:5137ff0d0b1cc574751d178650ef800ff8d90bf21eb9f71e9567d4a0548940a5"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f92876271a10494671431ad955bff2d6f8ea59baaf957f5ae5946aff56dfcb90"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:35c227b6d55e473033db7e0ecc51b1e99e6ed7607cc08602fb5768132543c81d"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1706a8a8188f7b3d4b7922db9bb00c64c4e16ee68ab4caaae79f55b3e18748c7"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce61efc1862ccb18856c4aabbd930e13d5bfbb4b09b4f111081ac53a9dc62275"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a78c03800ef9f02d320e0159f5768b15357f3e9ebea545c9c4ba7928ba8ba254"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753b8088fd685ee787d9f54c84275ab347de558c7c4ebc6accb4c35bf7776f20"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-win32.whl", hash = "sha256:24306fd86031c17a1a6ae92671e76a350390a3140a65620bc2843dad7db24e2a"},
+    {file = "sentencepiece-0.1.97-cp39-cp39-win_amd64.whl", hash = "sha256:c6641d0b7acec61fde5881ea6ebe098c169557ac9aa3bdabdf124eab5a5592bb"},
+    {file = "sentencepiece-0.1.97.tar.gz", hash = "sha256:c901305e0a710bbcd296f66d79e96f744e6e175b29812bd5178318437d4e1f6c"},
+]
+setuptools = [
+    {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
+    {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
+]
+setuptools-scm = [
+    {file = "setuptools_scm-7.0.5-py3-none-any.whl", hash = "sha256:7930f720905e03ccd1e1d821db521bff7ec2ac9cf0ceb6552dd73d24a45d3b02"},
+    {file = "setuptools_scm-7.0.5.tar.gz", hash = "sha256:031e13af771d6f892b941adb6ea04545bbf91ebc5ce68c78aaf3fff6e1fb4844"},
 ]
-scikit-learn = []
-scipy = []
-sentencepiece = []
-setuptools-scm = []
 six = [
     {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
     {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
@@ -2480,18 +3683,24 @@ snowballstemmer = [
     {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"},
     {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"},
 ]
-sphinx = []
+sphinx = [
+    {file = "Sphinx-5.3.0.tar.gz", hash = "sha256:51026de0a9ff9fc13c05d74913ad66047e104f56a129ff73e174eb5c3ee794b5"},
+    {file = "sphinx-5.3.0-py3-none-any.whl", hash = "sha256:060ca5c9f7ba57a08a1219e547b269fadf125ae25b06b9fa7f66768efb652d6d"},
+]
 sphinx-copybutton = [
     {file = "sphinx-copybutton-0.4.0.tar.gz", hash = "sha256:8daed13a87afd5013c3a9af3575cc4d5bec052075ccd3db243f895c07a689386"},
     {file = "sphinx_copybutton-0.4.0-py3-none-any.whl", hash = "sha256:4340d33c169dac6dd82dce2c83333412aa786a42dd01a81a8decac3b130dc8b0"},
 ]
 sphinx-gitstamp = [
-    {file = "sphinx-gitstamp-0.3.2.tar.gz", hash = "sha256:520c1edd7b84806e9480e80dc7f599d32ef8d2dcd6d95e60523f0fa36c110e4a"},
+    {file = "sphinx-gitstamp-0.3.3.tar.gz", hash = "sha256:cd8ff6eb2029deed51797c23da4dbcd9e4d1dea261124770f537cb4de86f7e38"},
+]
+sphinx-markdown-tables = [
+    {file = "sphinx-markdown-tables-0.0.17.tar.gz", hash = "sha256:6bc6d3d400eaccfeebd288446bc08dd83083367c58b85d40fe6c12d77ef592f1"},
+    {file = "sphinx_markdown_tables-0.0.17-py3-none-any.whl", hash = "sha256:2bd0c30779653e4dd120300cbd9ca412c480738cc2241f6dea477a883f299e04"},
 ]
-sphinx-markdown-tables = []
 sphinx-rtd-theme = [
-    {file = "sphinx_rtd_theme-1.0.0-py2.py3-none-any.whl", hash = "sha256:4d35a56f4508cfee4c4fb604373ede6feae2a306731d533f409ef5c3496fdbd8"},
-    {file = "sphinx_rtd_theme-1.0.0.tar.gz", hash = "sha256:eec6d497e4c2195fa0e8b2016b337532b8a699a68bcb22a512870e16925c6a5c"},
+    {file = "sphinx_rtd_theme-1.1.1-py2.py3-none-any.whl", hash = "sha256:31faa07d3e97c8955637fc3f1423a5ab2c44b74b8cc558a51498c202ce5cbda7"},
+    {file = "sphinx_rtd_theme-1.1.1.tar.gz", hash = "sha256:6146c845f1e1947b3c3dd4432c28998a1693ccc742b4f9ad7c63129f0757c103"},
 ]
 sphinxcontrib-applehelp = [
     {file = "sphinxcontrib-applehelp-1.0.2.tar.gz", hash = "sha256:a072735ec80e7675e3f432fcae8610ecf509c5f1869d17e2eecff44389cdbc58"},
@@ -2524,8 +3733,14 @@ sphinxext-opengraph = [
     {file = "sphinxext-opengraph-0.4.2.tar.gz", hash = "sha256:5da1a6eaab25e377b841f506ef7d7c44b539428f3d6094ccc16d1dfd3ef65501"},
     {file = "sphinxext_opengraph-0.4.2-py3-none-any.whl", hash = "sha256:a51f2604f9a5b6c0d25d3a88e694d5c02e20812dc0e482adf96c8628f9109357"},
 ]
-stack-data = []
-stevedore = []
+stack-data = [
+    {file = "stack_data-0.6.2-py3-none-any.whl", hash = "sha256:cbb2a53eb64e5785878201a97ed7c7b94883f48b87bfb0bbe8b623c74679e4a8"},
+    {file = "stack_data-0.6.2.tar.gz", hash = "sha256:32d2dd0376772d01b6cb9fc996f3c8b57a357089dec328ed4b6553d037eaf815"},
+]
+stevedore = [
+    {file = "stevedore-4.1.1-py3-none-any.whl", hash = "sha256:aa6436565c069b2946fe4ebff07f5041e0c8bf18c7376dd29edf80cf7d524e4e"},
+    {file = "stevedore-4.1.1.tar.gz", hash = "sha256:7f8aeb6e3f90f96832c301bff21a7eb5eefbe894c88c506483d355565d88cc1a"},
+]
 threadpoolctl = [
     {file = "threadpoolctl-3.1.0-py3-none-any.whl", hash = "sha256:8b99adda265feb6773280df41eece7b2e6561b772d21ffd52e372f999024907b"},
     {file = "threadpoolctl-3.1.0.tar.gz", hash = "sha256:a335baacfaa4400ae1f0d8e3a58d6674d2f8828e3716bb2802c44955ad391380"},
@@ -2534,7 +3749,44 @@ tokenize-rt = [
     {file = "tokenize_rt-4.2.1-py2.py3-none-any.whl", hash = "sha256:08a27fa032a81cf45e8858d0ac706004fcd523e8463415ddf1442be38e204ea8"},
     {file = "tokenize_rt-4.2.1.tar.gz", hash = "sha256:0d4f69026fed520f8a1e0103aa36c406ef4661417f20ca643f913e33531b3b94"},
 ]
-tokenizers = []
+tokenizers = [
+    {file = "tokenizers-0.13.2-cp310-cp310-macosx_10_11_x86_64.whl", hash = "sha256:a6f36b1b499233bb4443b5e57e20630c5e02fba61109632f5e00dab970440157"},
+    {file = "tokenizers-0.13.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:bc6983282ee74d638a4b6d149e5dadd8bc7ff1d0d6de663d69f099e0c6bddbeb"},
+    {file = "tokenizers-0.13.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16756e6ab264b162f99c0c0a8d3d521328f428b33374c5ee161c0ebec42bf3c0"},
+    {file = "tokenizers-0.13.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b10db6e4b036c78212c6763cb56411566edcf2668c910baa1939afd50095ce48"},
+    {file = "tokenizers-0.13.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:238e879d1a0f4fddc2ce5b2d00f219125df08f8532e5f1f2ba9ad42f02b7da59"},
+    {file = "tokenizers-0.13.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47ef745dbf9f49281e900e9e72915356d69de3a4e4d8a475bda26bfdb5047736"},
+    {file = "tokenizers-0.13.2-cp310-cp310-win32.whl", hash = "sha256:96cedf83864bcc15a3ffd088a6f81a8a8f55b8b188eabd7a7f2a4469477036df"},
+    {file = "tokenizers-0.13.2-cp310-cp310-win_amd64.whl", hash = "sha256:eda77de40a0262690c666134baf19ec5c4f5b8bde213055911d9f5a718c506e1"},
+    {file = "tokenizers-0.13.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a689654fc745135cce4eea3b15e29c372c3e0b01717c6978b563de5c38af9811"},
+    {file = "tokenizers-0.13.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3606528c07cda0566cff6cbfbda2b167f923661be595feac95701ffcdcbdbb21"},
+    {file = "tokenizers-0.13.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:41291d0160946084cbd53c8ec3d029df3dc2af2673d46b25ff1a7f31a9d55d51"},
+    {file = "tokenizers-0.13.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7892325f9ca1cc5fca0333d5bfd96a19044ce9b092ce2df625652109a3de16b8"},
+    {file = "tokenizers-0.13.2-cp311-cp311-win32.whl", hash = "sha256:93714958d4ebe5362d3de7a6bd73dc86c36b5af5941ebef6c325ac900fa58865"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-macosx_10_11_x86_64.whl", hash = "sha256:da521bfa94df6a08a6254bb8214ea04854bb9044d61063ae2529361688b5440a"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a739d4d973d422e1073989769723f3b6ad8b11e59e635a63de99aea4b2208188"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cac01fc0b868e4d0a3aa7c5c53396da0a0a63136e81475d32fcf5c348fcb2866"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0901a5c6538d2d2dc752c6b4bde7dab170fddce559ec75662cfad03b3187c8f6"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ba9baa76b5a3eefa78b6cc351315a216232fd727ee5e3ce0f7c6885d9fb531b"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-win32.whl", hash = "sha256:a537061ee18ba104b7f3daa735060c39db3a22c8a9595845c55b6c01d36c5e87"},
+    {file = "tokenizers-0.13.2-cp37-cp37m-win_amd64.whl", hash = "sha256:c82fb87b1cbfa984d8f05b2b3c3c73e428b216c1d4f0e286d0a3b27f521b32eb"},
+    {file = "tokenizers-0.13.2-cp38-cp38-macosx_10_11_x86_64.whl", hash = "sha256:ce298605a833ac7f81b8062d3102a42dcd9fa890493e8f756112c346339fe5c5"},
+    {file = "tokenizers-0.13.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a51b93932daba12ed07060935978a6779593a59709deab04a0d10e6fd5c29e60"},
+    {file = "tokenizers-0.13.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6969e5ea7ccb909ce7d6d4dfd009115dc72799b0362a2ea353267168667408c4"},
+    {file = "tokenizers-0.13.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:92f040c4d938ea64683526b45dfc81c580e3b35aaebe847e7eec374961231734"},
+    {file = "tokenizers-0.13.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d3bc9f7d7f4c1aa84bb6b8d642a60272c8a2c987669e9bb0ac26daf0c6a9fc8"},
+    {file = "tokenizers-0.13.2-cp38-cp38-win32.whl", hash = "sha256:efbf189fb9cf29bd29e98c0437bdb9809f9de686a1e6c10e0b954410e9ca2142"},
+    {file = "tokenizers-0.13.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b4cb2c60c094f31ea652f6cf9f349aae815f9243b860610c29a69ed0d7a88f8"},
+    {file = "tokenizers-0.13.2-cp39-cp39-macosx_10_11_x86_64.whl", hash = "sha256:b47d6212e7dd05784d7330b3b1e5a170809fa30e2b333ca5c93fba1463dec2b7"},
+    {file = "tokenizers-0.13.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:80a57501b61ec4f94fb7ce109e2b4a1a090352618efde87253b4ede6d458b605"},
+    {file = "tokenizers-0.13.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61507a9953f6e7dc3c972cbc57ba94c80c8f7f686fbc0876afe70ea2b8cc8b04"},
+    {file = "tokenizers-0.13.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c09f4fa620e879debdd1ec299bb81e3c961fd8f64f0e460e64df0818d29d845c"},
+    {file = "tokenizers-0.13.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:66c892d85385b202893ac6bc47b13390909e205280e5df89a41086cfec76fedb"},
+    {file = "tokenizers-0.13.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3e306b0941ad35087ae7083919a5c410a6b672be0343609d79a1171a364ce79"},
+    {file = "tokenizers-0.13.2-cp39-cp39-win32.whl", hash = "sha256:79189e7f706c74dbc6b753450757af172240916d6a12ed4526af5cc6d3ceca26"},
+    {file = "tokenizers-0.13.2-cp39-cp39-win_amd64.whl", hash = "sha256:486d637b413fddada845a10a45c74825d73d3725da42ccd8796ccd7a1c07a024"},
+    {file = "tokenizers-0.13.2.tar.gz", hash = "sha256:f9525375582fd1912ac3caa2f727d36c86ff8c0c6de45ae1aaff90f87f33b907"},
+]
 toml = [
     {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"},
     {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"},
@@ -2543,28 +3795,90 @@ tomli = [
     {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
     {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
 ]
-tomlkit = []
-torch = []
+tomlkit = [
+    {file = "tomlkit-0.11.6-py3-none-any.whl", hash = "sha256:07de26b0d8cfc18f871aec595fda24d95b08fef89d147caa861939f37230bf4b"},
+    {file = "tomlkit-0.11.6.tar.gz", hash = "sha256:71b952e5721688937fb02cf9d354dbcf0785066149d2855e44531ebdd2b65d73"},
+]
+torch = [
+    {file = "torch-1.13.0-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:f68edfea71ade3862039ba66bcedf954190a2db03b0c41a9b79afd72210abd97"},
+    {file = "torch-1.13.0-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:d2d2753519415d154de4d3e64d2eaaeefdba6b6fd7d69d5ffaef595988117700"},
+    {file = "torch-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:6c227c16626e4ce766cca5351cc62a2358a11e8e466410a298487b9dff159eb1"},
+    {file = "torch-1.13.0-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:49a949b8136b32b2ec0724cbf4c6678b54e974b7d68f19f1231eea21cde5c23b"},
+    {file = "torch-1.13.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:0fdd38c96230947b1ed870fed4a560252f8d23c3a2bf4dab9d2d42b18f2e67c8"},
+    {file = "torch-1.13.0-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:43db0723fc66ad6486f86dc4890c497937f7cd27429f28f73fb7e4d74b7482e2"},
+    {file = "torch-1.13.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e643ac8d086706e82f77b5d4dfcf145a9dd37b69e03e64177fc23821754d2ed7"},
+    {file = "torch-1.13.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:bb33a911460475d1594a8c8cb73f58c08293211760796d99cae8c2509b86d7f1"},
+    {file = "torch-1.13.0-cp37-cp37m-win_amd64.whl", hash = "sha256:220325d0f4e69ee9edf00c04208244ef7cf22ebce083815ce272c7491f0603f5"},
+    {file = "torch-1.13.0-cp37-none-macosx_10_9_x86_64.whl", hash = "sha256:cd1e67db6575e1b173a626077a54e4911133178557aac50683db03a34e2b636a"},
+    {file = "torch-1.13.0-cp37-none-macosx_11_0_arm64.whl", hash = "sha256:9197ec216833b836b67e4d68e513d31fb38d9789d7cd998a08fba5b499c38454"},
+    {file = "torch-1.13.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:fa768432ce4b8ffa29184c79a3376ab3de4a57b302cdf3c026a6be4c5a8ab75b"},
+    {file = "torch-1.13.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:635dbb99d981a6483ca533b3dc7be18ef08dd9e1e96fb0bb0e6a99d79e85a130"},
+    {file = "torch-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:857c7d5b1624c5fd979f66d2b074765733dba3f5e1cc97b7d6909155a2aae3ce"},
+    {file = "torch-1.13.0-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:ef934a21da6f6a516d0a9c712a80d09c56128abdc6af8dc151bee5199b4c3b4e"},
+    {file = "torch-1.13.0-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:f01a9ae0d4b69d2fc4145e8beab45b7877342dddbd4838a7d3c11ca7f6680745"},
+    {file = "torch-1.13.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:9ac382cedaf2f70afea41380ad8e7c06acef6b5b7e2aef3971cdad666ca6e185"},
+    {file = "torch-1.13.0-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:e20df14d874b024851c58e8bb3846249cb120e677f7463f60c986e3661f88680"},
+    {file = "torch-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:4a378f5091307381abfb30eb821174e12986f39b1cf7c4522bf99155256819eb"},
+    {file = "torch-1.13.0-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:922a4910613b310fbeb87707f00cb76fec328eb60cc1349ed2173e7c9b6edcd8"},
+    {file = "torch-1.13.0-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:47fe6228386bff6d74319a2ffe9d4ed943e6e85473d78e80502518c607d644d2"},
+]
 torchtyping = [
     {file = "torchtyping-0.1.4-py3-none-any.whl", hash = "sha256:485fb6ef3965c39b0de15f00d6f49373e0a3a6993e9733942a63c5e207d35390"},
     {file = "torchtyping-0.1.4.tar.gz", hash = "sha256:4763375d17752641bd1bff0faaddade29be3c125fca6355e3cee7700e975fdb5"},
 ]
-tornado = []
-tqdm = []
-traitlets = []
-transformers = []
+tornado = [
+    {file = "tornado-6.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:20f638fd8cc85f3cbae3c732326e96addff0a15e22d80f049e00121651e82e72"},
+    {file = "tornado-6.2-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:87dcafae3e884462f90c90ecc200defe5e580a7fbbb4365eda7c7c1eb809ebc9"},
+    {file = "tornado-6.2-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba09ef14ca9893954244fd872798b4ccb2367c165946ce2dd7376aebdde8e3ac"},
+    {file = "tornado-6.2-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8150f721c101abdef99073bf66d3903e292d851bee51910839831caba341a75"},
+    {file = "tornado-6.2-cp37-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3a2f5999215a3a06a4fc218026cd84c61b8b2b40ac5296a6db1f1451ef04c1e"},
+    {file = "tornado-6.2-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5f8c52d219d4995388119af7ccaa0bcec289535747620116a58d830e7c25d8a8"},
+    {file = "tornado-6.2-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:6fdfabffd8dfcb6cf887428849d30cf19a3ea34c2c248461e1f7d718ad30b66b"},
+    {file = "tornado-6.2-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:1d54d13ab8414ed44de07efecb97d4ef7c39f7438cf5e976ccd356bebb1b5fca"},
+    {file = "tornado-6.2-cp37-abi3-win32.whl", hash = "sha256:5c87076709343557ef8032934ce5f637dbb552efa7b21d08e89ae7619ed0eb23"},
+    {file = "tornado-6.2-cp37-abi3-win_amd64.whl", hash = "sha256:e5f923aa6a47e133d1cf87d60700889d7eae68988704e20c75fb2d65677a8e4b"},
+    {file = "tornado-6.2.tar.gz", hash = "sha256:9b630419bde84ec666bfd7ea0a4cb2a8a651c2d5cccdbdd1972a0c859dfc3c13"},
+]
+tqdm = [
+    {file = "tqdm-4.64.1-py2.py3-none-any.whl", hash = "sha256:6fee160d6ffcd1b1c68c65f14c829c22832bc401726335ce92c52d395944a6a1"},
+    {file = "tqdm-4.64.1.tar.gz", hash = "sha256:5f4f682a004951c1b450bc753c710e9280c5746ce6ffedee253ddbcbf54cf1e4"},
+]
+traitlets = [
+    {file = "traitlets-5.6.0-py3-none-any.whl", hash = "sha256:1410755385d778aed847d68deb99b3ba30fbbf489e17a1e8cbb753060d5cce73"},
+    {file = "traitlets-5.6.0.tar.gz", hash = "sha256:10b6ed1c9cedee83e795db70a8b9c2db157bb3778ec4587a349ecb7ef3b1033b"},
+]
+transformers = [
+    {file = "transformers-4.24.0-py3-none-any.whl", hash = "sha256:b7ab50039ef9bf817eff14ab974f306fd20a72350bdc9df3a858fd009419322e"},
+    {file = "transformers-4.24.0.tar.gz", hash = "sha256:486f353a8e594002e48be0e2aba723d96eda839e63bfe274702a4b5eda85559b"},
+]
 typeguard = [
     {file = "typeguard-2.13.3-py3-none-any.whl", hash = "sha256:5e3e3be01e887e7eafae5af63d1f36c849aaa94e3a0112097312aabfa16284f1"},
     {file = "typeguard-2.13.3.tar.gz", hash = "sha256:00edaa8da3a133674796cf5ea87d9f4b4c367d77476e185e80251cc13dfbb8c4"},
 ]
-typing-extensions = []
-urllib3 = []
-virtualenv = []
+typing-extensions = [
+    {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"},
+    {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"},
+]
+urllib3 = [
+    {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"},
+    {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"},
+]
+virtualenv = [
+    {file = "virtualenv-20.17.0-py3-none-any.whl", hash = "sha256:40a7e06a98728fd5769e1af6fd1a706005b4bb7e16176a272ed4292473180389"},
+    {file = "virtualenv-20.17.0.tar.gz", hash = "sha256:7d6a8d55b2f73b617f684ee40fd85740f062e1f2e379412cb1879c7136f05902"},
+]
 wcwidth = [
     {file = "wcwidth-0.2.5-py2.py3-none-any.whl", hash = "sha256:beb4802a9cebb9144e99086eff703a642a13d6a0052920003a230f3294bbe784"},
     {file = "wcwidth-0.2.5.tar.gz", hash = "sha256:c4d647b99872929fdb7bdcaa4fbe7f01413ed3d98077df798530e5b04f116c83"},
 ]
-widgetsnbextension = []
+wheel = [
+    {file = "wheel-0.38.4-py3-none-any.whl", hash = "sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8"},
+    {file = "wheel-0.38.4.tar.gz", hash = "sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac"},
+]
+widgetsnbextension = [
+    {file = "widgetsnbextension-4.0.3-py3-none-any.whl", hash = "sha256:7f3b0de8fda692d31ef03743b598620e31c2668b835edbd3962d080ccecf31eb"},
+    {file = "widgetsnbextension-4.0.3.tar.gz", hash = "sha256:34824864c062b0b3030ad78210db5ae6a3960dfb61d5b27562d6631774de0286"},
+]
 wrapt = [
     {file = "wrapt-1.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3"},
     {file = "wrapt-1.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef"},
@@ -2631,6 +3945,149 @@ wrapt = [
     {file = "wrapt-1.14.1-cp39-cp39-win_amd64.whl", hash = "sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb"},
     {file = "wrapt-1.14.1.tar.gz", hash = "sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d"},
 ]
-xxhash = []
-yarl = []
-zipp = []
+xxhash = [
+    {file = "xxhash-3.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5e9141f224a4dc984ea016744aa40a8a040054ef91933b2f9c81ba18e5b9d06e"},
+    {file = "xxhash-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b8810fa72d361262168c2b215e3cee223eb19b74806c08713b943f57f0c91fd6"},
+    {file = "xxhash-3.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb07bb4125c432f500a76a84ef51c0eafc09afbd1479308c6e1e2bbb73a33bb4"},
+    {file = "xxhash-3.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4582e12d9aa25530449a8cad4e9e8e973e0b2f28e77ef6504fc6f216f8f07406"},
+    {file = "xxhash-3.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d72b5d4eee98ecd25a2c647f7547a024585400ab13aa7ec837ebb8a25151bbef"},
+    {file = "xxhash-3.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f50cfc3e80fe241d25e557f7ca5a145d3d557bdf738cd2d355bfe1324c28d21"},
+    {file = "xxhash-3.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:90d03b46fc06f9ca3c0a4db685df3efffeb880ebcef2ffee707057e09fb8cba2"},
+    {file = "xxhash-3.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:540966f42ccd0d3d09539a7236fbfdce6b15d7be49ee5d5adaef0aa0d020cd1e"},
+    {file = "xxhash-3.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2d65d773c4d9c8d1a88af8e0e2169910cfc3d425006e2eb18cd13a6391543ed1"},
+    {file = "xxhash-3.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:3a9e2052ac6520e1f56630ff689b2b85ccd24799d362493435cf46defe163cc1"},
+    {file = "xxhash-3.1.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:77c6d1e0993e8a314f4a6aec911c12fbb4caf4f58223381d3d41fa153ae6924f"},
+    {file = "xxhash-3.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aa4e22665290f2dfa608901c38b1a5f0d367280fd8adc5996356d7f4993f41f7"},
+    {file = "xxhash-3.1.0-cp310-cp310-win32.whl", hash = "sha256:5c65cfb8fd3efd3d574a0cd4abbe59741f720334fa1d79e5366b34b0f4584b66"},
+    {file = "xxhash-3.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:8f32770a4b39ffe6a5785f87b66435b2e4048ba4a36334108ac5d375447ce667"},
+    {file = "xxhash-3.1.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:effd26669365a71e1337977ba789c95029c9cb0ac26e7455255922d3c9ff8fff"},
+    {file = "xxhash-3.1.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2324c31095708ceb7ee8c15b31bd1bea7376ca477748f9a20aba2e94d01fab1"},
+    {file = "xxhash-3.1.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1980f79c8ab4536c01048eb6398db0ac2049292150064bef665fa4c89918f86c"},
+    {file = "xxhash-3.1.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11d4af8d50b8b08835f653a96d58bb3658454144e5e4d28e369f4b3ad2bff4ea"},
+    {file = "xxhash-3.1.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a7b89e0b8b26cb86369ca0a7395299e0046930664ce96cbc07702504af9a26"},
+    {file = "xxhash-3.1.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca24dd052adf23e1fd8fb5839d9046328e60222a866fa3c2761e90ddab1fc2b8"},
+    {file = "xxhash-3.1.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:f7f1b27db4798f7ebe599107c75b2a0648fc1f9d9226fa2771fc296c5593dc7e"},
+    {file = "xxhash-3.1.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:e24bab9aecdfba23c7feb3b173488ca6b3168a50095ff544dedc7caa0c05ac3c"},
+    {file = "xxhash-3.1.0-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:cb3032588cd46bc6d16b2b35cd7ff5041fcc90423ae7c8f62263a029ff8f1e5d"},
+    {file = "xxhash-3.1.0-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:b9c56f45fd18879212b480dc44dc1da44a22d453e3b4038c4b686f6307124220"},
+    {file = "xxhash-3.1.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:00f2603b91fbb6fd1c3b83b263a405834e2df393fd2bac6a86e2e0ecc511076c"},
+    {file = "xxhash-3.1.0-cp36-cp36m-win32.whl", hash = "sha256:33f865b6eb9126a60345cf3106925a5039ef582b840d2df96f7777a160d0ef17"},
+    {file = "xxhash-3.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:95175636d28943eaf3da331aa57c7d02756017880151e11f8476a2ef49dd35de"},
+    {file = "xxhash-3.1.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b43b55e0d2d81f4ec8caaf165a0a96325d7dd4317770b663701700f9aee855ed"},
+    {file = "xxhash-3.1.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:694fd42161959382b70ea3442ea017675071dafe8b960849d5a599c4538737d8"},
+    {file = "xxhash-3.1.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3a3d7cd6412a1d0d5e43be188a67f95326e5a8c5d2ae1ad10adf8f896e630091"},
+    {file = "xxhash-3.1.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ab8f652ffaed3855d25f7666f63bf1ee81ead4d9d30cc9e592571a3959d2964"},
+    {file = "xxhash-3.1.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2259f13de36b4e675840e50b16bcd5c6f7aec6f5e833af47b3a0186c19e92dd"},
+    {file = "xxhash-3.1.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e86290486768b51478f320abca9fe61805578298b6e60719ec23bca85c60eec"},
+    {file = "xxhash-3.1.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d08ebd5313f6811ef76cde0f97179374b047442b918089a09019fed53b9f9cef"},
+    {file = "xxhash-3.1.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2e798287d6efcd51df12ac67f65ba7d78937be80c2c91bff2d17bf5404c63a24"},
+    {file = "xxhash-3.1.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:91bf72f009114320d9cbb452d5995286f2c6f70b3f53041f72654c4c1a8b79bd"},
+    {file = "xxhash-3.1.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:d30df80c8bc56aa55f545b1840d84ad6f773a3623b3e1462f17ebbd93c4c69ae"},
+    {file = "xxhash-3.1.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:9d4f9c8570e9adecae7d480090bcbf856b1d28f462c30c5cbe9f23b6418d6423"},
+    {file = "xxhash-3.1.0-cp37-cp37m-win32.whl", hash = "sha256:0bce4ce403129c6cee69860cf2597d04f29c714797c11e8ec3b2b7b3677c4586"},
+    {file = "xxhash-3.1.0-cp37-cp37m-win_amd64.whl", hash = "sha256:cf20bca461ae45273599be8635b60b517d2212b51d6d5d85fc8c441078eb02ab"},
+    {file = "xxhash-3.1.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a9efbc1c780ef3b578486eb250f5e93b2934c918386d981d96b7a06bae90c4d4"},
+    {file = "xxhash-3.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b16e7fc7991118c0b6cd9f5e141911110388f39df58b2996834619d2b956b4a8"},
+    {file = "xxhash-3.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0f1e298f80e302fd1b859e0b27f997eae82e9e9592843a1df2ca79122365ac1"},
+    {file = "xxhash-3.1.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4645b106732885fc488656657a5790dee4d8ffd123d2134647028f6575f2c05e"},
+    {file = "xxhash-3.1.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:02f9a6176152a64955b3dff89dfb2d3c9a7c93e862cbc37c0858e8e25d1f3f3c"},
+    {file = "xxhash-3.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:edd65c4850231324af7a613e5647c1c484f3dcbcde4a0e608d099050c684ae79"},
+    {file = "xxhash-3.1.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80b6cd0f781c198b0b53f78124658d0f407fbba7450e79d537505608bf4125ba"},
+    {file = "xxhash-3.1.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ae86b9672ad4ef431b0e1d284530289382575e2569078071c7adcf5827b4995"},
+    {file = "xxhash-3.1.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3cb1c759c2a863dd963bdca8504c7ae39388dd1ef189fca91b94f18acb7bde26"},
+    {file = "xxhash-3.1.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:e5d54d8e01c34acf3361bb58c5022a92abc9d5054b919a1d483679d59989bbff"},
+    {file = "xxhash-3.1.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:362520c908887c85af832e16448bad58cb182d165a16241e3251bdd17bd427be"},
+    {file = "xxhash-3.1.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6502a60ced52547e9c8e3eba3e5818ac0adca3e9abb5e32d2ee73a060f3dc362"},
+    {file = "xxhash-3.1.0-cp38-cp38-win32.whl", hash = "sha256:4143a1ad5f436550fcc091c80e7af23ec31cca1991750391067b24b051dcd0d7"},
+    {file = "xxhash-3.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:04812deabfdba3fa9cae57abb908a3f980bccbe9a4178f3e56afca2f1f625874"},
+    {file = "xxhash-3.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:53e587e6625bc9a7cfa5e067837590a626ff4150000ae31be2af73a67d08ea8c"},
+    {file = "xxhash-3.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:778f3c6007d280b6fff12f95c81d9c4ad6907632a0bfecf23aca18afb54319c0"},
+    {file = "xxhash-3.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc93e4bd34fd14459672345ca4a070b0f28d906bea4b178373b4271498e38ec9"},
+    {file = "xxhash-3.1.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65a9aac88cc960b3a21a52922d5846f1b15af7a5b937a26c7edee1d3fe80800c"},
+    {file = "xxhash-3.1.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b74a787be31b8493797d3e7dfac2b240ed443bcd1b42dfbb406629538f103667"},
+    {file = "xxhash-3.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21e030031f13455c9bfc10ed58301fbee8fad0e179cc6a1b15e899d71af2958f"},
+    {file = "xxhash-3.1.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c627840400b90a90d989ebef431b146e89e44377de42cd2e75996bbed394e3c5"},
+    {file = "xxhash-3.1.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:62cc09f3024ef1a0153e32ac6593025f20fae13b1bc5d08b639891ec110cacec"},
+    {file = "xxhash-3.1.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:de9758872881d50d0946dfc6067b4782986de6af5ec74c266d47d85c699aa0de"},
+    {file = "xxhash-3.1.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:216b90f30351fe434903bb039ae88df4c5ae43eb4320a012f6c73bec1d630213"},
+    {file = "xxhash-3.1.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:84e9d14baccdf31e3c59ed34b9d00df52ad4db376dbbbaad936ea02b9be4a534"},
+    {file = "xxhash-3.1.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8f4089c92b7aac2ead222345b0368e7d69e7a61e7a56762ae2f5e8d67fb67349"},
+    {file = "xxhash-3.1.0-cp39-cp39-win32.whl", hash = "sha256:dfa73020bc696a46dab2dddd28c76d1abcd0643dc8a2dd06a037392bda5cc5ec"},
+    {file = "xxhash-3.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:0602b45447934fd5b81b387e76512a7c7c946b571b3f9a7d7b2cd9d3a09f9041"},
+    {file = "xxhash-3.1.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a06311c247f2f45619e754249ca6f868c349fbfb63979ce291c83151840952a2"},
+    {file = "xxhash-3.1.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f109a872aba254ffebe3c749a6b7148463e5d3168ac5afb515f1a929e73feb8f"},
+    {file = "xxhash-3.1.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4521fed12d111bb2691ca0dc01fa8b36f6c626f53d9ee54befcea957e1b4dbaa"},
+    {file = "xxhash-3.1.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c60ff7946e46beaa873509c1ca41937b40fc3048620cbd8441bfe03aa053f33"},
+    {file = "xxhash-3.1.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:379c37f2d46a441bdb71af79443990e21943ef644ffeed5662157a9a682d55be"},
+    {file = "xxhash-3.1.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:daa1a37685759003680bd2775053bbf772c4f71ad3c729810ea4901535635d5e"},
+    {file = "xxhash-3.1.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c58b2bc7240966f54db9ef7dcfcc988362b0a315c12ed13a778917457c8dfe9d"},
+    {file = "xxhash-3.1.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efafa866662f6ab50f1ffb808424ca9373d2f3b4a73e6ea66432dce1779f501c"},
+    {file = "xxhash-3.1.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea074722fa953a1a3bece979620e2f0b43f2dfca841de84aca32a477c2fdb658"},
+    {file = "xxhash-3.1.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:369af334d58f6d2f716bd1557d3580c4c1235077090769abf1d54daec2b301a7"},
+    {file = "xxhash-3.1.0.tar.gz", hash = "sha256:ac21b1e21dc6fdfee9a57b53f4777539d53a84f2e1546a3f802f159f9966bdc1"},
+]
+yarl = [
+    {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:abc06b97407868ef38f3d172762f4069323de52f2b70d133d096a48d72215d28"},
+    {file = "yarl-1.8.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:07b21e274de4c637f3e3b7104694e53260b5fc10d51fb3ec5fed1da8e0f754e3"},
+    {file = "yarl-1.8.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9de955d98e02fab288c7718662afb33aab64212ecb368c5dc866d9a57bf48880"},
+    {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ec362167e2c9fd178f82f252b6d97669d7245695dc057ee182118042026da40"},
+    {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:20df6ff4089bc86e4a66e3b1380460f864df3dd9dccaf88d6b3385d24405893b"},
+    {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5999c4662631cb798496535afbd837a102859568adc67d75d2045e31ec3ac497"},
+    {file = "yarl-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed19b74e81b10b592084a5ad1e70f845f0aacb57577018d31de064e71ffa267a"},
+    {file = "yarl-1.8.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e4808f996ca39a6463f45182e2af2fae55e2560be586d447ce8016f389f626f"},
+    {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2d800b9c2eaf0684c08be5f50e52bfa2aa920e7163c2ea43f4f431e829b4f0fd"},
+    {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6628d750041550c5d9da50bb40b5cf28a2e63b9388bac10fedd4f19236ef4957"},
+    {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:f5af52738e225fcc526ae64071b7e5342abe03f42e0e8918227b38c9aa711e28"},
+    {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:76577f13333b4fe345c3704811ac7509b31499132ff0181f25ee26619de2c843"},
+    {file = "yarl-1.8.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0c03f456522d1ec815893d85fccb5def01ffaa74c1b16ff30f8aaa03eb21e453"},
+    {file = "yarl-1.8.1-cp310-cp310-win32.whl", hash = "sha256:ea30a42dc94d42f2ba4d0f7c0ffb4f4f9baa1b23045910c0c32df9c9902cb272"},
+    {file = "yarl-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:9130ddf1ae9978abe63808b6b60a897e41fccb834408cde79522feb37fb72fb0"},
+    {file = "yarl-1.8.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0ab5a138211c1c366404d912824bdcf5545ccba5b3ff52c42c4af4cbdc2c5035"},
+    {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0fb2cb4204ddb456a8e32381f9a90000429489a25f64e817e6ff94879d432fc"},
+    {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:85cba594433915d5c9a0d14b24cfba0339f57a2fff203a5d4fd070e593307d0b"},
+    {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ca7e596c55bd675432b11320b4eacc62310c2145d6801a1f8e9ad160685a231"},
+    {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0f77539733e0ec2475ddcd4e26777d08996f8cd55d2aef82ec4d3896687abda"},
+    {file = "yarl-1.8.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29e256649f42771829974e742061c3501cc50cf16e63f91ed8d1bf98242e5507"},
+    {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7fce6cbc6c170ede0221cc8c91b285f7f3c8b9fe28283b51885ff621bbe0f8ee"},
+    {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:59ddd85a1214862ce7c7c66457f05543b6a275b70a65de366030d56159a979f0"},
+    {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:12768232751689c1a89b0376a96a32bc7633c08da45ad985d0c49ede691f5c0d"},
+    {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:b19255dde4b4f4c32e012038f2c169bb72e7f081552bea4641cab4d88bc409dd"},
+    {file = "yarl-1.8.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:6c8148e0b52bf9535c40c48faebb00cb294ee577ca069d21bd5c48d302a83780"},
+    {file = "yarl-1.8.1-cp37-cp37m-win32.whl", hash = "sha256:de839c3a1826a909fdbfe05f6fe2167c4ab033f1133757b5936efe2f84904c07"},
+    {file = "yarl-1.8.1-cp37-cp37m-win_amd64.whl", hash = "sha256:dd032e8422a52e5a4860e062eb84ac94ea08861d334a4bcaf142a63ce8ad4802"},
+    {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19cd801d6f983918a3f3a39f3a45b553c015c5aac92ccd1fac619bd74beece4a"},
+    {file = "yarl-1.8.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6347f1a58e658b97b0a0d1ff7658a03cb79bdbda0331603bed24dd7054a6dea1"},
+    {file = "yarl-1.8.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7c0da7e44d0c9108d8b98469338705e07f4bb7dab96dbd8fa4e91b337db42548"},
+    {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5587bba41399854703212b87071c6d8638fa6e61656385875f8c6dff92b2e461"},
+    {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31a9a04ecccd6b03e2b0e12e82131f1488dea5555a13a4d32f064e22a6003cfe"},
+    {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:205904cffd69ae972a1707a1bd3ea7cded594b1d773a0ce66714edf17833cdae"},
+    {file = "yarl-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea513a25976d21733bff523e0ca836ef1679630ef4ad22d46987d04b372d57fc"},
+    {file = "yarl-1.8.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0b51530877d3ad7a8d47b2fff0c8df3b8f3b8deddf057379ba50b13df2a5eae"},
+    {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d2b8f245dad9e331540c350285910b20dd913dc86d4ee410c11d48523c4fd546"},
+    {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:ab2a60d57ca88e1d4ca34a10e9fb4ab2ac5ad315543351de3a612bbb0560bead"},
+    {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:449c957ffc6bc2309e1fbe67ab7d2c1efca89d3f4912baeb8ead207bb3cc1cd4"},
+    {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a165442348c211b5dea67c0206fc61366212d7082ba8118c8c5c1c853ea4d82e"},
+    {file = "yarl-1.8.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b3ded839a5c5608eec8b6f9ae9a62cb22cd037ea97c627f38ae0841a48f09eae"},
+    {file = "yarl-1.8.1-cp38-cp38-win32.whl", hash = "sha256:c1445a0c562ed561d06d8cbc5c8916c6008a31c60bc3655cdd2de1d3bf5174a0"},
+    {file = "yarl-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:56c11efb0a89700987d05597b08a1efcd78d74c52febe530126785e1b1a285f4"},
+    {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e80ed5a9939ceb6fda42811542f31c8602be336b1fb977bccb012e83da7e4936"},
+    {file = "yarl-1.8.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6afb336e23a793cd3b6476c30f030a0d4c7539cd81649683b5e0c1b0ab0bf350"},
+    {file = "yarl-1.8.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4c322cbaa4ed78a8aac89b2174a6df398faf50e5fc12c4c191c40c59d5e28357"},
+    {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fae37373155f5ef9b403ab48af5136ae9851151f7aacd9926251ab26b953118b"},
+    {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5395da939ffa959974577eff2cbfc24b004a2fb6c346918f39966a5786874e54"},
+    {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:076eede537ab978b605f41db79a56cad2e7efeea2aa6e0fa8f05a26c24a034fb"},
+    {file = "yarl-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d1a50e461615747dd93c099f297c1994d472b0f4d2db8a64e55b1edf704ec1c"},
+    {file = "yarl-1.8.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7de89c8456525650ffa2bb56a3eee6af891e98f498babd43ae307bd42dca98f6"},
+    {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4a88510731cd8d4befaba5fbd734a7dd914de5ab8132a5b3dde0bbd6c9476c64"},
+    {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2d93a049d29df172f48bcb09acf9226318e712ce67374f893b460b42cc1380ae"},
+    {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:21ac44b763e0eec15746a3d440f5e09ad2ecc8b5f6dcd3ea8cb4773d6d4703e3"},
+    {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:d0272228fabe78ce00a3365ffffd6f643f57a91043e119c289aaba202f4095b0"},
+    {file = "yarl-1.8.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99449cd5366fe4608e7226c6cae80873296dfa0cde45d9b498fefa1de315a09e"},
+    {file = "yarl-1.8.1-cp39-cp39-win32.whl", hash = "sha256:8b0af1cf36b93cee99a31a545fe91d08223e64390c5ecc5e94c39511832a4bb6"},
+    {file = "yarl-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:de49d77e968de6626ba7ef4472323f9d2e5a56c1d85b7c0e2a190b2173d3b9be"},
+    {file = "yarl-1.8.1.tar.gz", hash = "sha256:af887845b8c2e060eb5605ff72b6f2dd2aab7a761379373fd89d314f4752abbf"},
+]
+zipp = [
+    {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"},
+    {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"},
+]
diff --git a/pyproject.toml b/pyproject.toml
index b29b497f..e1345dbc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -44,7 +44,7 @@ classifiers = [  #! Update me
 "inseq" = "inseq.commands.cli:main"
 
 [tool.poetry.dependencies]
-python = ">=3.8,<3.12"
+python = ">=3.8.1,<3.12"
 
 rich = "^10.13.0"
 transformers =  { version = "^4.20.1", extras = ["sentencepiece", "tokenizers", "torch"] }
@@ -57,11 +57,11 @@ torch = "^1.13.0"
 scipy = "^1.8.1"
 matplotlib = "^3.5.2"
 tqdm = "^4.64.0"
-ipykernel = "^6.15.0"
-ipywidgets = "^8.0.0rc2"
 poethepoet = "^0.13.1"
-joblib = "^1.2.0"
 
+ipykernel = { version = "^6.15.0", optional = true }
+ipywidgets = { version = "^8.0.0rc2", optional = true }
+joblib = { version = "^1.2.0", optional = true }
 scikit-learn = { version = "^1.1.1", optional = true }
 datasets = { version = "^2.3.2", optional = true, extras = ["torch"] }
 
@@ -83,19 +83,21 @@ optional = true
 
 [tool.poetry.group.lint.dependencies]
 bandit = "^1.7.4"
-safety = "^1.10.3"
+safety = "^2.2.0"
 black = "^22.6.0"
 darglint = "^1.8.1"
-flake8 = "^4.0.1"
+flake8 = "^6.0.0"
 isort = {extras = ["colors"], version = "^5.10.1"}
 pre-commit = "^2.19.0"
-pylint = "^2.14.1"
+pylint = "^2.15.7"
 pyupgrade = "^2.34.0"
-pytest = "^6.2.5"
+pytest = "^7.2.0"
+pytest-cov = "^4.0.0"
 
 [tool.poetry.extras]
-scikit-learn = ["scikit-learn"]
+sklearn = ["scikit-learn", "joblib"]
 datasets = ["datasets"]
+notebook = ["ipykernel", "ipywidgets"]
 
 [tool.poe.tasks]
 upgrade-pip = "python -m pip install --upgrade pip"
@@ -179,7 +181,7 @@ doctest_optionflags = ["NUMBER", "NORMALIZE_WHITESPACE", "IGNORE_EXCEPTION_DETAI
 
 markers = [
   "slow",
-  "require_gpu"
+  "require_cuda_gpu"
 ]
 
 # Extra options:
diff --git a/requirements-dev.txt b/requirements-dev.txt
new file mode 100644
index 00000000..483cc389
--- /dev/null
+++ b/requirements-dev.txt
@@ -0,0 +1,165 @@
+aiohttp==3.8.3 ; python_version >= "3.8" and python_version < "3.12"
+aiosignal==1.3.1 ; python_version >= "3.8" and python_version < "3.12"
+alabaster==0.7.12 ; python_version >= "3.8" and python_version < "3.12"
+appnope==0.1.3 ; python_version >= "3.8" and python_version < "3.12" and platform_system == "Darwin" or python_version >= "3.8" and python_version < "3.12" and sys_platform == "darwin"
+astroid==2.12.13 ; python_version >= "3.8" and python_version < "3.12"
+asttokens==2.2.0 ; python_version >= "3.8" and python_version < "3.12"
+async-timeout==4.0.2 ; python_version >= "3.8" and python_version < "3.12"
+attrs==22.1.0 ; python_version >= "3.8" and python_version < "3.12"
+babel==2.11.0 ; python_version >= "3.8" and python_version < "3.12"
+backcall==0.2.0 ; python_version >= "3.8" and python_version < "3.12"
+bandit==1.7.4 ; python_version >= "3.8" and python_version < "3.12"
+black==22.10.0 ; python_version >= "3.8" and python_version < "3.12"
+captum==0.5.0 ; python_version >= "3.8" and python_version < "3.12"
+certifi==2022.9.24 ; python_version >= "3.8" and python_version < "3.12"
+cffi==1.15.1 ; python_version >= "3.8" and python_version < "3.12" and implementation_name == "pypy"
+cfgv==3.3.1 ; python_version >= "3.8" and python_version < "3.12"
+charset-normalizer==2.1.1 ; python_version >= "3.8" and python_version < "3.12"
+click==8.1.3 ; python_version >= "3.8" and python_version < "3.12"
+colorama==0.4.6 ; python_version >= "3.8" and python_version < "3.12"
+comm==0.1.1 ; python_version >= "3.8" and python_version < "3.12"
+commonmark==0.9.1 ; python_version >= "3.8" and python_version < "3.12"
+contourpy==1.0.6 ; python_version >= "3.8" and python_version < "3.12"
+coverage[toml]==6.5.0 ; python_version >= "3.8" and python_version < "3.12"
+cycler==0.11.0 ; python_version >= "3.8" and python_version < "3.12"
+darglint==1.8.1 ; python_version >= "3.8" and python_version < "3.12"
+datasets[torch]==2.7.1 ; python_version >= "3.8" and python_version < "3.12"
+debugpy==1.6.4 ; python_version >= "3.8" and python_version < "3.12"
+decorator==5.1.1 ; python_version >= "3.8" and python_version < "3.12"
+dill==0.3.6 ; python_version >= "3.8" and python_version < "3.12"
+distlib==0.3.6 ; python_version >= "3.8" and python_version < "3.12"
+docutils==0.17.1 ; python_version >= "3.8" and python_version < "3.12"
+dparse==0.6.2 ; python_version >= "3.8" and python_version < "3.12"
+entrypoints==0.4 ; python_version >= "3.8" and python_version < "3.12"
+exceptiongroup==1.0.4 ; python_version >= "3.8" and python_version < "3.11"
+executing==1.2.0 ; python_version >= "3.8" and python_version < "3.12"
+filelock==3.8.0 ; python_version >= "3.8" and python_version < "3.12"
+flake8==5.0.4 ; python_version >= "3.8" and python_version < "3.12"
+fonttools==4.38.0 ; python_version >= "3.8" and python_version < "3.12"
+frozenlist==1.3.3 ; python_version >= "3.8" and python_version < "3.12"
+fsspec[http]==2022.11.0 ; python_version >= "3.8" and python_version < "3.12"
+gitdb==4.0.10 ; python_version >= "3.8" and python_version < "3.12"
+gitpython==3.1.29 ; python_version >= "3.8" and python_version < "3.12"
+huggingface-hub==0.11.1 ; python_version >= "3.8" and python_version < "3.12"
+identify==2.5.9 ; python_version >= "3.8" and python_version < "3.12"
+idna==3.4 ; python_version >= "3.8" and python_version < "3.12"
+imagesize==1.4.1 ; python_version >= "3.8" and python_version < "3.12"
+importlib-metadata==5.1.0 ; python_version >= "3.8" and python_version < "3.10"
+iniconfig==1.1.1 ; python_version >= "3.8" and python_version < "3.12"
+ipykernel==6.18.2 ; python_version >= "3.8" and python_version < "3.12"
+ipython==8.7.0 ; python_version >= "3.8" and python_version < "3.12"
+ipywidgets==8.0.2 ; python_version >= "3.8" and python_version < "3.12"
+isort==5.10.1 ; python_version >= "3.8" and python_version < "3.12"
+isort[colors]==5.10.1 ; python_version >= "3.8" and python_version < "3.12"
+jedi==0.18.2 ; python_version >= "3.8" and python_version < "3.12"
+jinja2==3.1.2 ; python_version >= "3.8" and python_version < "3.12"
+joblib==1.2.0 ; python_version >= "3.8" and python_version < "3.12"
+json-tricks==3.16.1 ; python_version >= "3.8" and python_version < "3.12"
+jupyter-client==7.4.7 ; python_version >= "3.8" and python_version < "3.12"
+jupyter-core==5.1.0 ; python_version >= "3.8" and python_version < "3.12"
+jupyterlab-widgets==3.0.3 ; python_version >= "3.8" and python_version < "3.12"
+kiwisolver==1.4.4 ; python_version >= "3.8" and python_version < "3.12"
+lazy-object-proxy==1.8.0 ; python_version >= "3.8" and python_version < "3.12"
+markdown==3.4.1 ; python_version >= "3.8" and python_version < "3.12"
+markupsafe==2.1.1 ; python_version >= "3.8" and python_version < "3.12"
+matplotlib-inline==0.1.6 ; python_version >= "3.8" and python_version < "3.12"
+matplotlib==3.6.2 ; python_version >= "3.8" and python_version < "3.12"
+mccabe==0.7.0 ; python_version >= "3.8" and python_version < "3.12"
+multidict==6.0.2 ; python_version >= "3.8" and python_version < "3.12"
+multiprocess==0.70.14 ; python_version >= "3.8" and python_version < "3.12"
+mypy-extensions==0.4.3 ; python_version >= "3.8" and python_version < "3.12"
+nest-asyncio==1.5.6 ; python_version >= "3.8" and python_version < "3.12"
+nodeenv==1.7.0 ; python_version >= "3.8" and python_version < "3.12"
+numpy==1.23.5 ; python_version < "3.12" and python_version >= "3.8"
+nvidia-cublas-cu11==11.10.3.66 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cuda-nvrtc-cu11==11.7.99 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cuda-runtime-cu11==11.7.99 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cudnn-cu11==8.5.0.96 ; python_version >= "3.8" and python_version < "3.12"
+packaging==21.3 ; python_version >= "3.8" and python_version < "3.12"
+pandas==1.5.2 ; python_version >= "3.8" and python_version < "3.12"
+parso==0.8.3 ; python_version >= "3.8" and python_version < "3.12"
+pastel==0.2.1 ; python_version >= "3.8" and python_version < "3.12"
+pathspec==0.10.2 ; python_version >= "3.8" and python_version < "3.12"
+pbr==5.11.0 ; python_version >= "3.8" and python_version < "3.12"
+pexpect==4.8.0 ; python_version >= "3.8" and python_version < "3.12" and sys_platform != "win32"
+pickleshare==0.7.5 ; python_version >= "3.8" and python_version < "3.12"
+pillow==9.3.0 ; python_version >= "3.8" and python_version < "3.12"
+platformdirs==2.5.4 ; python_version >= "3.8" and python_version < "3.12"
+pluggy==1.0.0 ; python_version >= "3.8" and python_version < "3.12"
+poethepoet==0.13.1 ; python_version >= "3.8" and python_version < "3.12"
+pre-commit==2.20.0 ; python_version >= "3.8" and python_version < "3.12"
+prompt-toolkit==3.0.33 ; python_version >= "3.8" and python_version < "3.12"
+protobuf==3.20.2 ; python_version >= "3.8" and python_version < "3.12"
+psutil==5.9.4 ; python_version >= "3.8" and python_version < "3.12"
+ptyprocess==0.7.0 ; python_version >= "3.8" and python_version < "3.12" and sys_platform != "win32"
+pure-eval==0.2.2 ; python_version >= "3.8" and python_version < "3.12"
+py==1.11.0 ; python_version >= "3.8" and python_version < "3.12" and implementation_name == "pypy"
+pyarrow==10.0.1 ; python_version >= "3.8" and python_version < "3.12"
+pycodestyle==2.9.1 ; python_version >= "3.8" and python_version < "3.12"
+pycparser==2.21 ; python_version >= "3.8" and python_version < "3.12" and implementation_name == "pypy"
+pyflakes==2.5.0 ; python_version >= "3.8" and python_version < "3.12"
+pygments==2.13.0 ; python_version >= "3.8" and python_version < "3.12"
+pylint==2.15.7 ; python_version >= "3.8" and python_version < "3.12"
+pyparsing==3.0.9 ; python_version >= "3.8" and python_version < "3.12"
+pytest-cov==4.0.0 ; python_version >= "3.8" and python_version < "3.12"
+pytest==7.2.0 ; python_version >= "3.8" and python_version < "3.12"
+python-dateutil==2.8.2 ; python_version >= "3.8" and python_version < "3.12"
+pytz==2022.6 ; python_version >= "3.8" and python_version < "3.12"
+pyupgrade==2.38.4 ; python_version >= "3.8" and python_version < "3.12"
+pywin32==305 ; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.8" and python_version < "3.12"
+pyyaml==6.0 ; python_version >= "3.8" and python_version < "3.12"
+pyzmq==24.0.1 ; python_version >= "3.8" and python_version < "3.12"
+recommonmark==0.7.1 ; python_version >= "3.8" and python_version < "3.12"
+regex==2022.10.31 ; python_version >= "3.8" and python_version < "3.12"
+requests==2.28.1 ; python_version >= "3.8" and python_version < "3.12"
+responses==0.18.0 ; python_version >= "3.8" and python_version < "3.12"
+rich==10.16.2 ; python_version >= "3.8" and python_version < "3.12"
+ruamel-yaml-clib==0.2.7 ; platform_python_implementation == "CPython" and python_version < "3.11" and python_version >= "3.8"
+ruamel-yaml==0.17.21 ; python_version >= "3.8" and python_version < "3.12"
+safety==2.3.3 ; python_version >= "3.8" and python_version < "3.12"
+scikit-learn==1.1.3 ; python_version >= "3.8" and python_version < "3.12"
+scipy==1.9.3 ; python_version >= "3.8" and python_version < "3.12"
+sentencepiece==0.1.97 ; python_version >= "3.8" and python_version < "3.12"
+setuptools-scm==7.0.5 ; python_version >= "3.8" and python_version < "3.12"
+setuptools==65.6.3 ; python_version >= "3.8" and python_version < "3.12"
+six==1.16.0 ; python_version >= "3.8" and python_version < "3.12"
+smmap==5.0.0 ; python_version >= "3.8" and python_version < "3.12"
+snowballstemmer==2.2.0 ; python_version >= "3.8" and python_version < "3.12"
+sphinx-copybutton==0.4.0 ; python_version >= "3.8" and python_version < "3.12"
+sphinx-gitstamp==0.3.3 ; python_version >= "3.8" and python_version < "3.12"
+sphinx-markdown-tables==0.0.17 ; python_version >= "3.8" and python_version < "3.12"
+sphinx-rtd-theme==1.1.1 ; python_version >= "3.8" and python_version < "3.12"
+sphinx==5.3.0 ; python_version >= "3.8" and python_version < "3.12"
+sphinxcontrib-applehelp==1.0.2 ; python_version >= "3.8" and python_version < "3.12"
+sphinxcontrib-devhelp==1.0.2 ; python_version >= "3.8" and python_version < "3.12"
+sphinxcontrib-htmlhelp==2.0.0 ; python_version >= "3.8" and python_version < "3.12"
+sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.8" and python_version < "3.12"
+sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.8" and python_version < "3.12"
+sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.8" and python_version < "3.12"
+sphinxemoji==0.2.0 ; python_version >= "3.8" and python_version < "3.12"
+sphinxext-opengraph==0.4.2 ; python_version >= "3.8" and python_version < "3.12"
+stack-data==0.6.2 ; python_version >= "3.8" and python_version < "3.12"
+stevedore==4.1.1 ; python_version >= "3.8" and python_version < "3.12"
+threadpoolctl==3.1.0 ; python_version >= "3.8" and python_version < "3.12"
+tokenize-rt==4.2.1 ; python_version >= "3.8" and python_version < "3.12"
+tokenizers==0.13.2 ; python_version >= "3.8" and python_version < "3.12"
+toml==0.10.2 ; python_version >= "3.8" and python_version < "3.12"
+tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.12"
+tomlkit==0.11.6 ; python_version >= "3.8" and python_version < "3.12"
+torch==1.13.0 ; python_version >= "3.8" and python_version < "3.12"
+torchtyping==0.1.4 ; python_version >= "3.8" and python_version < "3.12"
+tornado==6.2 ; python_version >= "3.8" and python_version < "3.12"
+tqdm==4.64.1 ; python_version >= "3.8" and python_version < "3.12"
+traitlets==5.6.0 ; python_version >= "3.8" and python_version < "3.12"
+transformers[sentencepiece,tokenizers,torch]==4.24.0 ; python_version >= "3.8" and python_version < "3.12"
+typeguard==2.13.3 ; python_version >= "3.8" and python_version < "3.12"
+typing-extensions==4.4.0 ; python_version >= "3.8" and python_version < "3.12"
+urllib3==1.26.13 ; python_version >= "3.8" and python_version < "3.12"
+virtualenv==20.17.0 ; python_version >= "3.8" and python_version < "3.12"
+wcwidth==0.2.5 ; python_version >= "3.8" and python_version < "3.12"
+wheel==0.38.4 ; python_version >= "3.8" and python_version < "3.12"
+widgetsnbextension==4.0.3 ; python_version >= "3.8" and python_version < "3.12"
+wrapt==1.14.1 ; python_version >= "3.8" and python_version < "3.12"
+xxhash==3.1.0 ; python_version >= "3.8" and python_version < "3.12"
+yarl==1.8.1 ; python_version >= "3.8" and python_version < "3.12"
+zipp==3.11.0 ; python_version >= "3.8" and python_version < "3.10"
diff --git a/requirements.txt b/requirements.txt
index d9ecd70b..1df14b55 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,80 +1,46 @@
-appnope==0.1.3; platform_system == "Darwin" and python_version >= "3.8" and sys_platform == "darwin"
-asttokens==2.1.0; python_version >= "3.8"
-backcall==0.2.0; python_version >= "3.8"
-captum==0.5.0; python_version >= "3.6"
-certifi==2022.9.24; python_version >= "3.7" and python_version < "4" and python_full_version >= "3.7.0"
-cffi==1.15.1; implementation_name == "pypy" and python_version >= "3.7"
-charset-normalizer==2.1.1; python_version >= "3.7" and python_version < "4" and python_full_version >= "3.7.0"
-colorama==0.4.6; python_full_version >= "3.7.0" and python_full_version < "4.0.0" and platform_system == "Windows" and (python_version >= "3.8" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.8" and python_full_version >= "3.7.0")
-commonmark==0.9.1; python_full_version >= "3.6.2" and python_full_version < "4.0.0"
-contourpy==1.0.5; python_version >= "3.8"
-cycler==0.11.0; python_version >= "3.8"
-debugpy==1.6.3; python_version >= "3.7"
-decorator==5.1.1; python_version >= "3.8"
-entrypoints==0.4; python_version >= "3.7"
-executing==1.2.0; python_version >= "3.8"
-filelock==3.8.0; python_version >= "3.7" and python_full_version >= "3.7.0"
-fonttools==4.38.0; python_version >= "3.8"
-huggingface-hub==0.10.1; python_full_version >= "3.7.0"
-idna==3.4; python_version >= "3.7" and python_version < "4" and python_full_version >= "3.7.0"
-importlib-metadata==5.0.0; python_full_version >= "3.7.0" and python_version >= "3.7"
-ipykernel==6.16.2; python_version >= "3.7"
-ipython==8.6.0; python_version >= "3.8"
-ipywidgets==8.0.2; python_version >= "3.7"
-jedi==0.18.1; python_version >= "3.8"
-joblib==1.2.0; python_version >= "3.7"
-json-tricks==3.15.5
-jupyter-client==7.4.4; python_version >= "3.7"
-jupyter-core==4.11.2; python_version >= "3.7"
-jupyterlab-widgets==3.0.3; python_version >= "3.7"
-kiwisolver==1.4.4; python_version >= "3.8"
-matplotlib-inline==0.1.6; python_version >= "3.8"
-matplotlib==3.6.1; python_version >= "3.8"
-nest-asyncio==1.5.6; python_version >= "3.7"
-numpy==1.23.4; python_version >= "3.8"
-nvidia-cublas-cu11==11.10.3.66; python_full_version >= "3.7.0" and python_version >= "3.6"
-nvidia-cuda-nvrtc-cu11==11.7.99; python_full_version >= "3.7.0" and python_version >= "3.6"
-nvidia-cuda-runtime-cu11==11.7.99; python_full_version >= "3.7.0" and python_version >= "3.6"
-nvidia-cudnn-cu11==8.5.0.96; python_full_version >= "3.7.0" and python_version >= "3.6"
-packaging==21.3; python_version >= "3.8" and python_full_version >= "3.7.0"
-parso==0.8.3; python_version >= "3.8"
-pastel==0.2.1; python_full_version >= "3.6.2"
-pexpect==4.8.0; sys_platform != "win32" and python_version >= "3.8"
-pickleshare==0.7.5; python_version >= "3.8"
-pillow==9.3.0; python_version >= "3.8"
-poethepoet==0.13.1; python_full_version >= "3.6.2"
-prompt-toolkit==3.0.31; python_full_version >= "3.6.2" and python_version >= "3.8"
-protobuf==3.20.2; python_version >= "3.7"
-psutil==5.9.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7"
-ptyprocess==0.7.0; sys_platform != "win32" and python_version >= "3.8"
-pure-eval==0.2.2; python_version >= "3.8"
-py==1.11.0; python_version >= "3.7" and python_full_version < "3.0.0" and implementation_name == "pypy" or implementation_name == "pypy" and python_version >= "3.7" and python_full_version >= "3.5.0"
-pycparser==2.21; python_version >= "3.7" and python_full_version < "3.0.0" and implementation_name == "pypy" or implementation_name == "pypy" and python_version >= "3.7" and python_full_version >= "3.4.0"
-pygments==2.13.0; python_full_version >= "3.6.2" and python_full_version < "4.0.0" and python_version >= "3.8"
-pyparsing==3.0.9; python_full_version >= "3.7.0" and python_version >= "3.8"
-python-dateutil==2.8.2; python_version >= "3.8" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.8"
-pywin32==304; sys_platform == "win32" and platform_python_implementation != "PyPy" and python_version >= "3.7"
-pyyaml==6.0; python_version >= "3.6" and python_full_version >= "3.7.0"
-pyzmq==24.0.1; python_version >= "3.7"
-regex==2022.9.13; python_version >= "3.6" and python_full_version >= "3.7.0"
-requests==2.28.1; python_version >= "3.7" and python_version < "4" and python_full_version >= "3.7.0"
-rich==10.16.2; python_full_version >= "3.6.2" and python_full_version < "4.0.0"
-scipy==1.9.3; python_version >= "3.8"
-sentencepiece==0.1.97; python_full_version >= "3.7.0"
-setuptools-scm==7.0.5; python_version >= "3.8"
-six==1.16.0; python_version >= "3.8" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.8"
-stack-data==0.6.0; python_version >= "3.8"
-tokenizers==0.13.1; python_full_version >= "3.7.0"
-tomli==2.0.1; python_version >= "3.8" and python_full_version >= "3.6.2"
-torch==1.13.0; python_full_version >= "3.7.0"
-torchtyping==0.1.4; python_full_version >= "3.7.0"
-tornado==6.2; python_version >= "3.7"
-tqdm==4.64.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0")
-traitlets==5.5.0; python_version >= "3.8"
-transformers==4.23.1; python_full_version >= "3.7.0"
-typeguard==2.13.3; python_full_version >= "3.7.0"
-typing-extensions==4.4.0; python_full_version >= "3.7.0" and python_version >= "3.8"
-urllib3==1.26.12; python_full_version >= "3.7.0" and python_version < "4" and python_version >= "3.7"
-wcwidth==0.2.5; python_full_version >= "3.6.2" and python_version >= "3.8"
-widgetsnbextension==4.0.3; python_version >= "3.7"
-zipp==3.10.0; python_full_version >= "3.7.0" and python_version >= "3.7"
+captum==0.5.0 ; python_version >= "3.8" and python_version < "3.12"
+certifi==2022.9.24 ; python_version >= "3.8" and python_version < "3.12"
+charset-normalizer==2.1.1 ; python_version >= "3.8" and python_version < "3.12"
+colorama==0.4.6 ; python_version >= "3.8" and python_version < "3.12"
+commonmark==0.9.1 ; python_version >= "3.8" and python_version < "3.12"
+contourpy==1.0.6 ; python_version >= "3.8" and python_version < "3.12"
+cycler==0.11.0 ; python_version >= "3.8" and python_version < "3.12"
+filelock==3.8.0 ; python_version >= "3.8" and python_version < "3.12"
+fonttools==4.38.0 ; python_version >= "3.8" and python_version < "3.12"
+huggingface-hub==0.11.1 ; python_version >= "3.8" and python_version < "3.12"
+idna==3.4 ; python_version >= "3.8" and python_version < "3.12"
+json-tricks==3.16.1 ; python_version >= "3.8" and python_version < "3.12"
+kiwisolver==1.4.4 ; python_version >= "3.8" and python_version < "3.12"
+matplotlib==3.6.2 ; python_version >= "3.8" and python_version < "3.12"
+numpy==1.23.5 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cublas-cu11==11.10.3.66 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cuda-nvrtc-cu11==11.7.99 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cuda-runtime-cu11==11.7.99 ; python_version >= "3.8" and python_version < "3.12"
+nvidia-cudnn-cu11==8.5.0.96 ; python_version >= "3.8" and python_version < "3.12"
+packaging==21.3 ; python_version >= "3.8" and python_version < "3.12"
+pastel==0.2.1 ; python_version >= "3.8" and python_version < "3.12"
+pillow==9.3.0 ; python_version >= "3.8" and python_version < "3.12"
+poethepoet==0.13.1 ; python_version >= "3.8" and python_version < "3.12"
+protobuf==3.20.2 ; python_version >= "3.8" and python_version < "3.12"
+pygments==2.13.0 ; python_version >= "3.8" and python_version < "3.12"
+pyparsing==3.0.9 ; python_version >= "3.8" and python_version < "3.12"
+python-dateutil==2.8.2 ; python_version >= "3.8" and python_version < "3.12"
+pyyaml==6.0 ; python_version >= "3.8" and python_version < "3.12"
+regex==2022.10.31 ; python_version >= "3.8" and python_version < "3.12"
+requests==2.28.1 ; python_version >= "3.8" and python_version < "3.12"
+rich==10.16.2 ; python_version >= "3.8" and python_version < "3.12"
+scipy==1.9.3 ; python_version >= "3.8" and python_version < "3.12"
+sentencepiece==0.1.97 ; python_version >= "3.8" and python_version < "3.12"
+setuptools-scm==7.0.5 ; python_version >= "3.8" and python_version < "3.12"
+setuptools==65.6.3 ; python_version >= "3.8" and python_version < "3.12"
+six==1.16.0 ; python_version >= "3.8" and python_version < "3.12"
+tokenizers==0.13.2 ; python_version >= "3.8" and python_version < "3.12"
+tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.12"
+torch==1.13.0 ; python_version >= "3.8" and python_version < "3.12"
+torchtyping==0.1.4 ; python_version >= "3.8" and python_version < "3.12"
+tqdm==4.64.1 ; python_version >= "3.8" and python_version < "3.12"
+transformers[sentencepiece,tokenizers,torch]==4.24.0 ; python_version >= "3.8" and python_version < "3.12"
+typeguard==2.13.3 ; python_version >= "3.8" and python_version < "3.12"
+typing-extensions==4.4.0 ; python_version >= "3.8" and python_version < "3.12"
+urllib3==1.26.13 ; python_version >= "3.8" and python_version < "3.12"
+wheel==0.38.4 ; python_version >= "3.8" and python_version < "3.12"
diff --git a/setup.cfg b/setup.cfg
index ca425003..c4e6f0bf 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -34,16 +34,12 @@ exclude =
     venv,
     .venv
 select = E,W,F
-doctests = True
+doctests = False
 verbose = 2
 format = pylint
 max-line-length = 119
 per-file-ignores = __init__.py:F401
-ignore=
-    E731, # do not assign lambda, use a def
-    E741, # ambiguous variable name
-    F821, # undefined name for TensorType dimensions
-    W503, # line break occurred before a binary operator
+ignore= E203, E731, E741, F821, W503, C901
 
 [metadata]
 license_file = LICENSE


Test patch:
diff --git a/tests/attr/feat/test_feature_attribution.py b/tests/attr/feat/test_feature_attribution.py
index 609cfc2e..8322f110 100644
--- a/tests/attr/feat/test_feature_attribution.py
+++ b/tests/attr/feat/test_feature_attribution.py
@@ -3,14 +3,20 @@
 from transformers import AutoModelForSeq2SeqLM
 
 import inseq
+from inseq.models import HuggingfaceDecoderOnlyModel, HuggingfaceEncoderDecoderModel
 from inseq.utils import output2prob
 
 
 @fixture(scope="session")
-def saliency_mt_model():
+def saliency_mt_model() -> HuggingfaceEncoderDecoderModel:
     return inseq.load_model("Helsinki-NLP/opus-mt-en-it", "saliency")
 
 
+@fixture(scope="session")
+def saliency_gpt_model() -> HuggingfaceDecoderOnlyModel:
+    return inseq.load_model("gpt2", "saliency")
+
+
 @fixture(scope="session")
 def auxiliary_saliency_mt_model():
     aux_model = AutoModelForSeq2SeqLM.from_pretrained("Helsinki-NLP/opus-mt-en-it")
@@ -47,19 +53,29 @@ def attribute_contrast_logits_diff(
     # We select the next contrastive token as target
     contrast_target_ids = contrast_ids[:, decoder_input_ids.shape[1]].to(attribution_model.device)
     # Forward pass with the same model used for the main generation, but using contrastive inputs instead
-    contrast_output = attribution_model.model(
-        inputs_embeds=encoder_input_embeds,
-        attention_mask=encoder_attention_mask,
-        decoder_input_ids=contrast_decoder_input_ids,
-        decoder_attention_mask=contrast_decoder_attention_mask,
-    )
+    if isinstance(attribution_model, HuggingfaceEncoderDecoderModel):
+        contrast_decoder_input_embeds = attribution_model.embed_ids(contrast_decoder_input_ids, as_targets=True)
+        contrast_output = attribution_model.get_forward_output(
+            forward_tensor=encoder_input_embeds,
+            encoder_attention_mask=encoder_attention_mask,
+            decoder_input_embeds=contrast_decoder_input_embeds,
+            decoder_attention_mask=contrast_decoder_attention_mask,
+        )
+    elif isinstance(attribution_model, HuggingfaceDecoderOnlyModel):
+        contrast_output = attribution_model.get_forward_output(
+            forward_tensor=contrast_decoder_input_ids,
+            attention_mask=contrast_decoder_attention_mask,
+            use_embeddings=False,
+        )
+    else:
+        raise ValueError("Unsupported attribution model type")
     # Return the prob difference as target for attribution
     model_probs = output2prob(attribution_model, forward_output, target_ids)
     contrast_probs = output2prob(attribution_model, contrast_output, contrast_target_ids)
     return model_probs - contrast_probs
 
 
-def test_contrastive_attribution(saliency_mt_model):
+def test_contrastive_attribution_seq2seq(saliency_mt_model: HuggingfaceEncoderDecoderModel):
     """Runs a contrastive feature attribution using the method relying on logits difference
     introduced by [Yin and Neubig '22](https://arxiv.org/pdf/2202.10419.pdf), taking advantage of
     the custom feature attribution target function module.
@@ -73,7 +89,7 @@ def test_contrastive_attribution(saliency_mt_model):
     )
 
     # Pre-compute ids and attention map for the contrastive target
-    contrast = saliency_mt_model.encode("Non posso crederlo.", as_targets=True, prepend_bos_token=True)
+    contrast = saliency_mt_model.encode("Non posso crederlo.", as_targets=True)
 
     # Perform the contrastive attribution:
     # Regular (forced) target -> "Non posso crederci."
@@ -82,10 +98,10 @@ def test_contrastive_attribution(saliency_mt_model):
     out = saliency_mt_model.attribute(
         "I can't believe it",
         "Non posso crederci.",
-        n_steps=10,
         attributed_fn="contrast_logits_diff",
         contrast_ids=contrast.input_ids,
         contrast_attention_mask=contrast.attention_mask,
+        show_progress=False,
     )
     attribution_scores = out.sequence_attributions[0].source_attributions
 
@@ -97,6 +113,25 @@ def test_contrastive_attribution(saliency_mt_model):
     assert not attribution_scores[:, :4].sum().eq(0)
 
 
+def test_contrastive_attribution_gpt(saliency_gpt_model: HuggingfaceDecoderOnlyModel):
+    inseq.register_step_score(
+        fn=attribute_contrast_logits_diff,
+        identifier="contrast_logits_diff",
+        aggregate_map={"span_aggregate": lambda x: x.prod(dim=1, keepdim=True)},
+    )
+    contrast = saliency_gpt_model.encode("The female student didn't participate because he was sick.")
+    out = saliency_gpt_model.attribute(
+        "The female student didn't participate because",
+        "The female student didn't participate because she was sick.",
+        attributed_fn="contrast_logits_diff",
+        contrast_ids=contrast.input_ids,
+        contrast_attention_mask=contrast.attention_mask,
+        show_progress=False,
+    )
+    attribution_scores = out.sequence_attributions[0].target_attributions
+    assert attribution_scores.shape == torch.Size([11, 4, 768])
+
+
 def attribute_mcd_uncertainty_weighted(
     attribution_model,
     forward_output,
@@ -151,6 +186,7 @@ def test_mcd_weighted_attribution(saliency_mt_model, auxiliary_saliency_mt_model
         "Hello ladies and badgers!",
         attributed_fn="mcd_uncertainty_weighted",
         attributed_fn_args={"n_mcd_steps": 5, "aux_model": auxiliary_saliency_mt_model.to(saliency_mt_model.device)},
+        show_progress=False,
     )
     attribution_scores = out.sequence_attributions[0].source_attributions
     assert isinstance(attribution_scores, torch.Tensor)
diff --git a/tests/data/test_aggregator.py b/tests/data/test_aggregator.py
index 48d203db..5eb24fb5 100644
--- a/tests/data/test_aggregator.py
+++ b/tests/data/test_aggregator.py
@@ -30,6 +30,7 @@ def test_sequence_attribution_aggregator(saliency_mt_model):
         attribute_target=True,
         output_step_attributions=True,
         device="cpu",
+        show_progress=False,
     )
     seqattr = out.sequence_attributions[0]
     assert seqattr.source_attributions.shape == (6, 7, 512)
@@ -46,7 +47,7 @@ def test_sequence_attribution_aggregator(saliency_mt_model):
 
 def test_continuous_span_aggregator(saliency_mt_model):
     out = saliency_mt_model.attribute(
-        "This is a test.", attribute_target=True, step_scores=["probability"], device="cpu"
+        "This is a test.", attribute_target=True, step_scores=["probability"], device="cpu", show_progress=False
     )
     seqattr = out.sequence_attributions[0]
     out_agg = seqattr.aggregate(ContiguousSpanAggregator, source_spans=(3, 5), target_spans=[(0, 3), (4, 6)])
@@ -57,7 +58,7 @@ def test_continuous_span_aggregator(saliency_mt_model):
 
 def test_aggregator_pipeline(saliency_mt_model):
     out = saliency_mt_model.attribute(
-        "This is a test.", attribute_target=True, step_scores=["probability"], device="cpu"
+        "This is a test.", attribute_target=True, step_scores=["probability"], device="cpu", show_progress=False
     )
     seqattr = out.sequence_attributions[0]
     squeezesum = AggregatorPipeline([ContiguousSpanAggregator, SequenceAttributionAggregator])
@@ -75,7 +76,7 @@ def test_aggregator_pipeline(saliency_mt_model):
 
 
 def test_subword_aggregator(saliency_mt_model):
-    out = saliency_mt_model.attribute(EXAMPLES["source"])
+    out = saliency_mt_model.attribute(EXAMPLES["source"], show_progress=False)
     seqattr = out.sequence_attributions[0]
     for idx, token in enumerate(seqattr.source):
         assert token.token == EXAMPLES["source_subwords"][idx]
@@ -102,7 +103,7 @@ def test_subword_aggregator(saliency_mt_model):
 
 
 def test_pair_aggregator(saliency_mt_model):
-    out = saliency_mt_model.attribute([EXAMPLES["source"], EXAMPLES["alternative_source"]])
+    out = saliency_mt_model.attribute([EXAMPLES["source"], EXAMPLES["alternative_source"]], show_progress=False)
     orig_seqattr = out.sequence_attributions[0].aggregate(aggregator=SequenceAttributionAggregator)
     alt_seqattr = out.sequence_attributions[1].aggregate(aggregator=SequenceAttributionAggregator)
     diff_seqattr = orig_seqattr.aggregate(PairAggregator, paired_attr=alt_seqattr)
diff --git a/tests/data/test_attribution.py b/tests/data/test_attribution.py
index 176e044d..f0554ddb 100644
--- a/tests/data/test_attribution.py
+++ b/tests/data/test_attribution.py
@@ -1,16 +1,16 @@
 from pytest import fixture
 
-from inseq import AttributionModel, FeatureAttributionOutput
+from inseq import FeatureAttributionOutput, load_model
 
 
 @fixture(scope="session")
 def saliency_mt_model():
-    return AttributionModel.load("Helsinki-NLP/opus-mt-en-it", "saliency", device="cpu")
+    return load_model("Helsinki-NLP/opus-mt-en-it", "saliency", device="cpu")
 
 
 def test_save_load_attribution(tmp_path, saliency_mt_model):
     out_path = tmp_path / "tmp_attr.json"
-    out = saliency_mt_model.attribute("This is a test.", device="cpu")
+    out = saliency_mt_model.attribute("This is a test.", device="cpu", show_progress=False)
     out.save(out_path)
     loaded_out = FeatureAttributionOutput.load(out_path)
     assert out == loaded_out
diff --git a/tests/fixtures/m2m_418M_batches.json b/tests/fixtures/m2m_418M_batches.json
index 0cd2d231..1f08b243 100644
--- a/tests/fixtures/m2m_418M_batches.json
+++ b/tests/fixtures/m2m_418M_batches.json
@@ -17,7 +17,6 @@
         "model_name": "facebook/m2m100_418M",
         "output_step_attributions": false,
         "step_scores": ["probability"],
-        "prepend_bos_token": true,
         "tokenizer_class": "M2M100Tokenizer",
         "tokenizer_name": "facebook/m2m100_418M"
     },
diff --git a/tests/models/test_huggingface_model.py b/tests/models/test_huggingface_model.py
index 911c7c13..91660478 100644
--- a/tests/models/test_huggingface_model.py
+++ b/tests/models/test_huggingface_model.py
@@ -13,6 +13,7 @@
 import inseq
 from inseq import list_feature_attribution_methods
 from inseq.data import FeatureAttributionOutput, FeatureAttributionSequenceOutput
+from inseq.utils import get_default_device
 
 
 EXAMPLES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "../fixtures/huggingface_model.json")
@@ -30,19 +31,24 @@ def saliency_mt_model():
     return inseq.load_model("Helsinki-NLP/opus-mt-en-it", "saliency")
 
 
+@fixture(scope="session")
+def saliency_gpt2_model():
+    return inseq.load_model("gpt2", "saliency")
+
+
 @mark.slow
-@mark.require_gpu
+@mark.require_cuda_gpu
 @mark.parametrize(("texts", "reference_texts"), EXAMPLES["short_texts"])
 @mark.parametrize("attribute_target", ATTRIBUTE_TARGET)
-def test_cuda_attribution_consistency(texts, reference_texts, attribute_target, saliency_mt_model):
+def test_cuda_attribution_consistency_seq2seq(texts, reference_texts, attribute_target, saliency_mt_model):
     out = {}
-    for device in ["cpu", "cuda:0"]:
+    for device in ["cpu", "cuda"]:
         out[device] = saliency_mt_model.attribute(
             texts, reference_texts, show_progress=False, attribute_target=attribute_target, device=device
         )
         assert isinstance(out[device], FeatureAttributionOutput)
         assert isinstance(out[device].sequence_attributions[0], FeatureAttributionSequenceOutput)
-    for out_cpu, out_gpu in zip(out["cpu"].sequence_attributions, out["cuda:0"].sequence_attributions):
+    for out_cpu, out_gpu in zip(out["cpu"].sequence_attributions, out["cuda"].sequence_attributions):
         assert all([tok_cpu == tok_gpu for tok_cpu, tok_gpu in zip(out_cpu.target, out_gpu.target)])
         attr_score_matches = [
             torch.allclose(cpu_attr, gpu_attr, atol=1e-3)
@@ -55,7 +61,9 @@ def test_cuda_attribution_consistency(texts, reference_texts, attribute_target,
 @mark.parametrize("attribution_method", ATTRIBUTION_METHODS)
 @mark.parametrize("use_reference", USE_REFERENCE_TEXT)
 @mark.parametrize("attribute_target", ATTRIBUTE_TARGET)
-def test_batched_attribution_consistency(attribution_method, use_reference, attribute_target, saliency_mt_model):
+def test_batched_attribution_consistency_seq2seq(
+    attribution_method, use_reference, attribute_target, saliency_mt_model
+):
     if attribution_method == "discretized_integrated_gradients":
         pytest.skip("discretized_integrated_gradients currently unsupported")
     if attribution_method.startswith("layer_") and attribute_target:
@@ -69,7 +77,7 @@ def test_batched_attribution_consistency(attribution_method, use_reference, attr
         reference_single,
         show_progress=False,
         attribute_target=attribute_target,
-        device="cuda:0" if torch.cuda.is_available() else "cpu",
+        device=get_default_device(),
         method=attribution_method,
     )
     out_batch = saliency_mt_model.attribute(
@@ -77,7 +85,7 @@ def test_batched_attribution_consistency(attribution_method, use_reference, attr
         reference_batch,
         show_progress=False,
         attribute_target=attribute_target,
-        device="cuda:0" if torch.cuda.is_available() else "cpu",
+        device=get_default_device(),
         method=attribution_method,
     )
     assert torch.allclose(
@@ -101,7 +109,7 @@ def test_batched_attribution_consistency(attribution_method, use_reference, attr
 @mark.parametrize("attribute_target", ATTRIBUTE_TARGET)
 @mark.parametrize("return_convergence_delta", RETURN_CONVERGENCE_DELTA)
 @mark.parametrize("step_scores", STEP_SCORES)
-def test_attribute(
+def test_attribute_seq2seq(
     texts,
     reference_texts,
     attribution_method,
@@ -127,7 +135,7 @@ def test_attribute(
         step_scores=step_scores,
         internal_batch_size=50,
         n_steps=100,
-        device="cuda:0" if torch.cuda.is_available() else "cpu",
+        device=get_default_device(),
     )
     assert isinstance(out, FeatureAttributionOutput)
     assert isinstance(out.sequence_attributions[0], FeatureAttributionSequenceOutput)
@@ -148,7 +156,7 @@ def test_attribute(
 @mark.parametrize(("texts", "reference_texts"), EXAMPLES["long_text"])
 @mark.parametrize("attribution_method", ATTRIBUTION_METHODS)
 @mark.parametrize("use_reference", USE_REFERENCE_TEXT)
-def test_attribute_long_text(texts, reference_texts, attribution_method, use_reference, saliency_mt_model):
+def test_attribute_long_text_seq2seq(texts, reference_texts, attribution_method, use_reference, saliency_mt_model):
     if attribution_method == "discretized_integrated_gradients":
         pytest.skip("discretized_integrated_gradients currently unsupported")
     if not use_reference:
@@ -160,7 +168,142 @@ def test_attribute_long_text(texts, reference_texts, attribution_method, use_ref
         show_progress=False,
         internal_batch_size=10,
         n_steps=100,
-        device="cuda:0" if torch.cuda.is_available() else "cpu",
+        device=get_default_device(),
+    )
+    assert isinstance(out, FeatureAttributionOutput)
+    assert isinstance(out.sequence_attributions[0], FeatureAttributionSequenceOutput)
+
+
+def test_attribute_slice_seq2seq(saliency_mt_model):
+    texts, reference_texts = EXAMPLES["texts"][2][0], EXAMPLES["texts"][2][1]
+    out = saliency_mt_model.attribute(
+        texts,
+        reference_texts,
+        show_progress=False,
+        device=get_default_device(),
+        attr_pos_start=13,
+        attr_pos_end=17,
+        attribute_target=True,
+    )
+    assert isinstance(out, FeatureAttributionOutput)
+    assert len(out.sequence_attributions) == 3
+    assert isinstance(out.sequence_attributions[0], FeatureAttributionSequenceOutput)
+    ex1, ex2, ex3 = out.sequence_attributions[0], out.sequence_attributions[1], out.sequence_attributions[2]
+    assert ex1.attr_pos_start == 13
+    assert ex1.attr_pos_end == 17
+    assert ex1.source_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[0] == ex1.attr_pos_end
+    # Empty attributions outputs have start and end set to seq length
+    assert ex2.attr_pos_start == len(ex2.target)
+    assert ex2.attr_pos_end == len(ex2.target)
+    assert ex2.source_attributions.shape[1] == 0 and ex2.target_attributions.shape[1] == 0
+    assert ex3.attr_pos_start == 13
+    assert ex3.attr_pos_end == 15
+    assert ex1.source_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[0] == ex1.attr_pos_end
+    assert out.info["attr_pos_start"] == 13
+    assert out.info["attr_pos_end"] == 17
+    aggregated = [attr.aggregate(attr._aggregator) for attr in out.sequence_attributions]
+    assert all(isinstance(aggr_attr, FeatureAttributionSequenceOutput) for aggr_attr in aggregated)
+
+
+def test_attribute_decoder(saliency_gpt2_model):
+    texts = EXAMPLES["texts"][2][0]
+    out = saliency_gpt2_model.attribute(
+        texts,
+        show_progress=False,
+        device=get_default_device(),
+        generation_args={"max_new_tokens": 10},
+    )
+    assert isinstance(out, FeatureAttributionOutput)
+    assert len(out.sequence_attributions) == 3
+    assert isinstance(out.sequence_attributions[0], FeatureAttributionSequenceOutput)
+    ex1, ex2, ex3 = out.sequence_attributions[0], out.sequence_attributions[1], out.sequence_attributions[2]
+    assert ex1.attr_pos_start == 17
+    assert ex1.attr_pos_end == 27
+    assert ex1.target_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[0] == ex1.attr_pos_end
+    # Empty attributions outputs have start and end set to seq length
+    assert ex2.attr_pos_start == 6
+    assert ex2.attr_pos_end == 16
+    assert ex2.target_attributions.shape[1] == ex2.attr_pos_end - ex2.attr_pos_start
+    assert ex2.target_attributions.shape[0] == ex2.attr_pos_end
+    assert ex3.attr_pos_start == 12
+    assert ex3.attr_pos_end == 22
+    assert ex3.target_attributions.shape[1] == ex3.attr_pos_end - ex3.attr_pos_start
+    assert ex3.target_attributions.shape[0] == ex3.attr_pos_end
+    assert out.info["attr_pos_start"] == 17
+    assert out.info["attr_pos_end"] == 27
+    aggregated = [attr.aggregate(attr._aggregator) for attr in out.sequence_attributions]
+    assert all(isinstance(aggr_attr, FeatureAttributionSequenceOutput) for aggr_attr in aggregated)
+
+
+def test_attribute_decoder_forced(saliency_gpt2_model):
+    texts = [
+        "Colorless green ideas sleep",
+        "The scientist told the director that",
+    ]
+    forced_generations = [
+        "Colorless green ideas sleep furiously.",
+        "The scientist told the director that the experiment was a success.",
+    ]
+    out = saliency_gpt2_model.attribute(
+        texts,
+        forced_generations,
+        show_progress=False,
+        device=get_default_device(),
+    )
+    assert isinstance(out, FeatureAttributionOutput)
+    assert len(out.sequence_attributions) == 2
+    assert isinstance(out.sequence_attributions[0], FeatureAttributionSequenceOutput)
+    ex1, ex2 = out.sequence_attributions[0], out.sequence_attributions[1]
+    assert ex1.attr_pos_start == 5
+    assert ex1.attr_pos_end == 7
+    assert ex1.target_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[0] == ex1.attr_pos_end
+    # Empty attributions outputs have start and end set to seq length
+    assert ex2.attr_pos_start == 6
+    assert ex2.attr_pos_end == 12
+    assert ex2.target_attributions.shape[1] == ex2.attr_pos_end - ex2.attr_pos_start
+    assert ex2.target_attributions.shape[0] == ex2.attr_pos_end
+    assert out.info["attr_pos_start"] == 5
+    assert out.info["attr_pos_end"] == 12
+    aggregated = [attr.aggregate(attr._aggregator) for attr in out.sequence_attributions]
+    assert all(isinstance(aggr_attr, FeatureAttributionSequenceOutput) for aggr_attr in aggregated)
+
+
+def test_attribute_decoder_forced_sliced(saliency_gpt2_model):
+    texts = [
+        "Colorless green ideas sleep",
+        "The scientist told the director that",
+    ]
+    forced_generations = [
+        "Colorless green ideas sleep furiously.",
+        "The scientist told the director that the experiment was a success.",
+    ]
+    out = saliency_gpt2_model.attribute(
+        texts,
+        forced_generations,
+        show_progress=False,
+        device=inseq.utils.get_default_device(),
+        attr_pos_start=6,
+        attr_pos_end=10,
     )
     assert isinstance(out, FeatureAttributionOutput)
+    assert len(out.sequence_attributions) == 2
     assert isinstance(out.sequence_attributions[0], FeatureAttributionSequenceOutput)
+    ex1, ex2 = out.sequence_attributions[0], out.sequence_attributions[1]
+    assert ex1.attr_pos_start == 6
+    assert ex1.attr_pos_end == 7
+    assert ex1.target_attributions.shape[1] == ex1.attr_pos_end - ex1.attr_pos_start
+    assert ex1.target_attributions.shape[0] == ex1.attr_pos_end
+    assert ex2.attr_pos_start == 6
+    assert ex2.attr_pos_end == 10
+    assert ex2.target_attributions.shape[1] == ex2.attr_pos_end - ex2.attr_pos_start
+    assert ex2.target_attributions.shape[0] == ex2.attr_pos_end
+    assert out.info["attr_pos_start"] == 6
+    assert out.info["attr_pos_end"] == 10
+    aggregated = [attr.aggregate(attr._aggregator) for attr in out.sequence_attributions]
+    assert all(isinstance(aggr_attr, FeatureAttributionSequenceOutput) for aggr_attr in aggregated)