Repository: eurodecision/pandas-cleaner (language: python)

Issue:
Add README.md



Discussion / hints:

Fix patch:
diff --git a/.coveragerc b/.coveragerc
index 9480074..d31227d 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,2 +1,2 @@
 [run]
-omit=pdcleaner/tests/*
+omit=tests/*
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 8bebbea..dfc0d90 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -31,10 +31,30 @@ jobs:
         # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
         flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
 
+    - name: Install python package
+      run: |
+        python setup.py develop
+
     - name: Test with pytest
       run: |
         pytest
 
+    - name: Get Coverage for badge
+      run: |
+        SUMMARY="$(pytest --cov --cov-report term-missing | tail -3 | head -1)"
+        TOKENS=($SUMMARY)
+        echo "COVERAGE=$(echo ${TOKENS[-1]})" >> $GITHUB_ENV
+
+    - name: Create the Badge
+      uses: schneegans/dynamic-badges-action@v1.4.0
+      with:
+        auth: ${{ secrets.GIST_TOKEN }}
+        gistID: 74e11571ef9b1a732e44fe9fbbdc7f0b
+        filename: pdcleaner_coverage.json
+        label: Test Coverage
+        message: ${{ env.COVERAGE }}
+        color: green
+
     - name: Build python package
       run: |
         python setup.py sdist bdist_wheel
diff --git a/.gitignore b/.gitignore
index e87e8f8..6d96e26 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 .vscode/
 .ipynb_checkpoints/
 .idea/
+.pytest_cache/
 
 #compiled sources
 *.py[ocd]
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100755
index 0000000..5d48a51
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,128 @@
+
+# Code of Conduct
+
+## Our Pledge
+
+We as members, contributors, and leaders pledge to make participation in our
+community a harassment-free experience for everyone, regardless of age, body
+size, visible or invisible disability, ethnicity, sex characteristics, gender
+identity and expression, level of experience, education, socio-economic status,
+nationality, personal appearance, race, caste, color, religion, or sexual
+identity and orientation.
+
+We pledge to act and interact in ways that contribute to an open, welcoming,
+diverse, inclusive, and healthy community.
+
+## Our Standards
+
+Examples of behavior that contributes to a positive environment for our
+community include:
+
+* Demonstrating empathy and kindness toward other people
+* Being respectful of differing opinions, viewpoints, and experiences
+* Giving and gracefully accepting constructive feedback
+* Accepting responsibility and apologizing to those affected by our mistakes,
+  and learning from the experience
+* Focusing on what is best not just for us as individuals, but for the overall
+  community
+
+Examples of unacceptable behavior include:
+
+* The use of sexualized language or imagery, and sexual attention or advances of
+  any kind
+* Trolling, insulting or derogatory comments, and personal or political attacks
+* Public or private harassment
+* Publishing others' private information, such as a physical or email address,
+  without their explicit permission
+* Other conduct which could reasonably be considered inappropriate in a
+  professional setting
+
+## Enforcement Responsibilities
+
+Community leaders are responsible for clarifying and enforcing our standards of
+acceptable behavior and will take appropriate and fair corrective action in
+response to any behavior that they deem inappropriate, threatening, offensive,
+or harmful.
+
+Community leaders have the right and responsibility to remove, edit, or reject
+comments, commits, code, wiki edits, issues, and other contributions that are
+not aligned to this Code of Conduct, and will communicate reasons for moderation
+decisions when appropriate.
+
+## Scope
+
+This Code of Conduct applies within all community spaces, and also applies when
+an individual is officially representing the community in public spaces.
+Examples of representing our community include using an official e-mail address,
+posting via an official social media account, or acting as an appointed
+representative at an online or offline event.
+
+## Enforcement
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be
+reported to the community leaders responsible for enforcement at
+renan.hilbert@eurodecision.com.
+All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the
+reporter of any incident.
+
+## Enforcement Guidelines
+
+Community leaders will follow these Community Impact Guidelines in determining
+the consequences for any action they deem in violation of this Code of Conduct:
+
+### 1. Correction
+
+**Community Impact**: Use of inappropriate language or other behavior deemed
+unprofessional or unwelcome in the community.
+
+**Consequence**: A private, written warning from community leaders, providing
+clarity around the nature of the violation and an explanation of why the
+behavior was inappropriate. A public apology may be requested.
+
+### 2. Warning
+
+**Community Impact**: A violation through a single incident or series of
+actions.
+
+**Consequence**: A warning with consequences for continued behavior. No
+interaction with the people involved, including unsolicited interaction with
+those enforcing the Code of Conduct, for a specified period of time. This
+includes avoiding interactions in community spaces as well as external channels
+like social media. Violating these terms may lead to a temporary or permanent
+ban.
+
+### 3. Temporary Ban
+
+**Community Impact**: A serious violation of community standards, including
+sustained inappropriate behavior.
+
+**Consequence**: A temporary ban from any sort of interaction or public
+communication with the community for a specified period of time. No public or
+private interaction with the people involved, including unsolicited interaction
+with those enforcing the Code of Conduct, is allowed during this period.
+Violating these terms may lead to a permanent ban.
+
+### 4. Permanent Ban
+
+**Community Impact**: Demonstrating a pattern of violation of community
+standards, including sustained inappropriate behavior, harassment of an
+individual, or aggression toward or disparagement of classes of individuals.
+
+**Consequence**: A permanent ban from any sort of public interaction within the
+community.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage],
+version 2.1, available at
+[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html].
+
+Community Impact Guidelines were inspired by
+[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
+
+For answers to common questions about this code of conduct, see the FAQ at
+[https://www.contributor-covenant.org/faq]. Translations are available at
+[https://www.contributor-covenant.org/translations].
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..6a4458f
--- /dev/null
+++ b/README.md
@@ -0,0 +1,88 @@
+# Pandas-cleaner
+
+<img src=https://img.shields.io/pypi/v/pandas-cleaner.svg target=https://pypi.python.org/pypi/pandas-cleaner> <img src=https://img.shields.io/pypi/l/pandas-cleaner.svg target=https://pypi.python.org/pypi/pandas-cleaner> <img src="https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/ed-ialifinaritra/74e11571ef9b1a732e44fe9fbbdc7f0b/raw/pdcleaner_coverage.json">
+
+Pandas-cleaner is a Python package, built on top of pandas, that provides methods detect, analyze and clean errors in datasets with different types of data (numerical, categorical, text, datetimes...).
+
+![](https://github.com/eurodecision/pandas-cleaner/blob/master/docs/source/pandas-cleaner.png)
+
+## Features
+
+Pandas-cleaner offers functionnalities to automatically :
+
+:arrow_right: **detect** different kind of potential errors in datasets such as outliers, inconsistencies, typos, wrong-typed ..., given predefined rules or statistiscal estimations,  via an easy-to-use API extending pandas,
+
+:arrow_right: **analyze** these errors, via reports and plots, to check the validity of the set and/or decide if any correction is needed,
+
+:arrow_right: **clean** the datasets, either by dropping the lines with errors, emptying, correcting or replacing bad values,
+
+:arrow_right: **reapply** the same rules to any other incoming fresh data.
+
+## Usage
+
+Import the package
+
+```python
+import pandas as pd
+import pdcleaner
+```
+
+Create an example data series
+
+```python
+series = pd.Series([1, 5, -6, 100, 10])
+```
+
+Detect the errors in the series with a given method (such as `bounded`, `iqr`, `zscore` and many more depending the type of data...)
+
+```python
+detector = series.cleaner.detect('bounded', lower=0, upper=10)
+```
+
+Inspect the result:
+
+```python
+detector.report()
+```
+```none
+                                 Detection report                               
+==============================================================================
+Method:                      bounded      Nb samples:                        5
+Date:                January 24,2022      Nb errors:                         2
+Time:                       16:06:08      Nb rows with NaN:                  0
+------------------------------------------------------------------------------
+lower                              0      upper                             10
+inclusive                       both      sided                           both
+==============================================================================
+```
+
+Check the potential errors that have been detected
+
+```python
+detector.detected()
+```
+```
+ 2     -6
+ 3    100
+ dtype: int64
+```
+
+Clean the detected errors from the series using the chosen method among `drop`, `to_na`, `clip`
+, `replace`...
+
+```python
+series.cleaner.clean("drop", detector, inplace=True)
+   series
+```
+```
+ 0      1
+ 1      5
+ 4     10
+ dtype: int64
+```
+
+## Contributing to pandas-cleaner
+
+All contributions, bug reports, bug fixes, documentation improvements, enhancements, and ideas are welcome.
+
+Issues and bugs can be reported at https://github.com/eurodecision/pandas-cleaner/issues
diff --git a/RELEASE.md b/RELEASE.md
index 1d4e8eb..ce7894b 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -1,4 +1,34 @@
-## Version 0.0.1
+### What's new in 0.0.2 (October 17, 2022)
+
++ **New detection methods**
+    + `'value'` to detect cells different from a given value
+    + ``'custom'`` to apply an user-defined python callable to detect the errors
+    + ``'spaces'`` to detect extra spaces before or after strings
+    + ``'duplicated'`` to detect duplicated records (whole row or subset of columns)
+    + ``'date_range'`` to detect dates outside a given time range
++ **New cleaning method**
+    + ``'cast'`` associated to the detector ``castable`` to cast strings into floats, integers, dates or NaNs
++ **Enhancements**
+    + The detectors have two new useful methods `.detected()` and `.valid()` that return valid/unvalid rows
+    + Gaussian detectors (``iqr``, ``zscore``, ``modzscore``) now have a systematic normality test and an option to transform the distribution
+      (Box-Cox, Yeo-Johnson) before applying the detector
+    + Reports are more detailed when using a multivariate qualitative/ quantitative detector
+    + Detector ``castable`` now applies to booleans
+    + Detector ``values`` is now called ``enum``
+    + Detector ``keycollision`` 
+        + is now called ``alternatives`` 
+        + is much faster
+        + now offers the choice to keep either most frequent representation or the first encountered
+    + Plot method for ``freq`` and ``cat`` detectors now have options ``nfirst`` and ``nlast``
+    + API for detector ``length`` has been simplified
++ **Bug fixes**
+    + Detector ``pattern`` now works with compiled regex
+    + Cleaning methods applied to DataFrames have been fixed
+    + Booleans are better displayed in reports
+    + Fixed bug with ``association`` detector plot method
++  **Code**
+    + Detector classes now have much simplier names
+    + ``tests`` folder has been reorganized  to mimic ``src`` structure
 
 ### What's new in 0.0.1 (February 25, 2022)
 
diff --git a/README.rst b/_README.rst
similarity index 87%
rename from README.rst
rename to _README.rst
index da8f5aa..e207c69 100644
--- a/README.rst
+++ b/_README.rst
@@ -6,6 +6,14 @@
 pandas-cleaner
 ==============
 
+.. image:: https://img.shields.io/pypi/v/pandas-cleaner.svg
+        :target: https://pypi.python.org/pypi/pandas-cleaner
+
+.. image:: https://img.shields.io/pypi/l/pandas-cleaner.svg
+        :target: https://pypi.python.org/pypi/pandas-cleaner
+
+.. image:: https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/ed-ialifinaritra/74e11571ef9b1a732e44fe9fbbdc7f0b/raw/pdcleaner_coverage.json
+
 
 What is it ?
 ------------
@@ -70,7 +78,7 @@ Check the potential errors that have been detected
 
 .. code-block:: python
 
-   detector.detected
+   detector.detected()
 
 .. parsed-literal::
 
@@ -93,21 +101,6 @@ Clean the detected errors from the series using the chosen method among `drop`,
     4     10
     dtype: int64
 
-Documentation
--------------
-
-The documentation is still a **work in progress**. 
-
-* Clone the project
-
-* Build the documentation using :
-
-.. code-block:: bash
-
-    cd docs
-    make html
-
-* Open `docs/build/html/index.html` in your browser
 
 Contributing to pandas-cleaner
 ------------------------------
diff --git a/docs/source/_static/favicon.png b/docs/source/_static/favicon.png
new file mode 100755
index 0000000..a73fe13
Binary files /dev/null and b/docs/source/_static/favicon.png differ
diff --git a/docs/source/_static/logo_ed_star.png b/docs/source/_static/logo_ed_star.png
new file mode 100755
index 0000000..5f22a38
Binary files /dev/null and b/docs/source/_static/logo_ed_star.png differ
diff --git a/docs/source/_static/pandas-cleaner-dark.png b/docs/source/_static/pandas-cleaner-dark.png
new file mode 100755
index 0000000..6f4efb2
Binary files /dev/null and b/docs/source/_static/pandas-cleaner-dark.png differ
diff --git a/docs/source/_static/pandas-cleaner.png b/docs/source/_static/pandas-cleaner.png
new file mode 100755
index 0000000..d402d51
Binary files /dev/null and b/docs/source/_static/pandas-cleaner.png differ
diff --git a/docs/source/_static/plot_alternatives_1.png b/docs/source/_static/plot_alternatives_1.png
new file mode 100644
index 0000000..9fef732
Binary files /dev/null and b/docs/source/_static/plot_alternatives_1.png differ
diff --git a/docs/source/_static/plot_alternatives_nfirst_2.png b/docs/source/_static/plot_alternatives_nfirst_2.png
new file mode 100644
index 0000000..96e97bd
Binary files /dev/null and b/docs/source/_static/plot_alternatives_nfirst_2.png differ
diff --git a/docs/source/_static/plot_alternatives_nlast_1.png b/docs/source/_static/plot_alternatives_nlast_1.png
new file mode 100644
index 0000000..cb9fcf7
Binary files /dev/null and b/docs/source/_static/plot_alternatives_nlast_1.png differ
diff --git a/docs/source/_static/plot_association.png b/docs/source/_static/plot_association.png
index a9475fa..ffebbb4 100644
Binary files a/docs/source/_static/plot_association.png and b/docs/source/_static/plot_association.png differ
diff --git a/docs/source/_static/plot_freq.png b/docs/source/_static/plot_freq.png
index 7ade402..de0f278 100644
Binary files a/docs/source/_static/plot_freq.png and b/docs/source/_static/plot_freq.png differ
diff --git a/docs/source/_static/plot_freq_nfirst_nlast.png b/docs/source/_static/plot_freq_nfirst_nlast.png
index 6c5da11..de0f278 100644
Binary files a/docs/source/_static/plot_freq_nfirst_nlast.png and b/docs/source/_static/plot_freq_nfirst_nlast.png differ
diff --git a/docs/source/_static/plot_keycollision_1.png b/docs/source/_static/plot_keycollision_1.png
deleted file mode 100644
index 94a48cf..0000000
Binary files a/docs/source/_static/plot_keycollision_1.png and /dev/null differ
diff --git a/docs/source/_static/plot_keycollision_nfirst_2.png b/docs/source/_static/plot_keycollision_nfirst_2.png
deleted file mode 100644
index cc70cd6..0000000
Binary files a/docs/source/_static/plot_keycollision_nfirst_2.png and /dev/null differ
diff --git a/docs/source/_static/plot_keycollision_nlast_1.png b/docs/source/_static/plot_keycollision_nlast_1.png
deleted file mode 100644
index 05f5a2a..0000000
Binary files a/docs/source/_static/plot_keycollision_nlast_1.png and /dev/null differ
diff --git a/docs/source/_static/plot_numseries copy.png b/docs/source/_static/plot_numseries copy.png
deleted file mode 100644
index b0c11b2..0000000
Binary files a/docs/source/_static/plot_numseries copy.png and /dev/null differ
diff --git a/docs/source/_static/plot_numseries.png b/docs/source/_static/plot_numseries.png
index 4b5367e..56428fb 100644
Binary files a/docs/source/_static/plot_numseries.png and b/docs/source/_static/plot_numseries.png differ
diff --git a/docs/source/_templates/logo.html b/docs/source/_templates/logo.html
index 998ca10..d47b088 100644
--- a/docs/source/_templates/logo.html
+++ b/docs/source/_templates/logo.html
@@ -1,7 +1,7 @@
 <div class="sidebar-end-items">
-<a href="https://www.eurodecision.eu/" target="_blank">
+<a href="https://www.eurodecision.com/" target="_blank">
 
-<img src="https://www.eurodecision.com/wp-content/themes/eurodecision/img/logo-eurod.jpg" width=250>
+<img src="https://www.eurodecision.com/wp-content/themes/eurodecision/img/logo-eurod.jpg" width=125>
 </a>
 </div>
 
diff --git a/docs/source/conf.py b/docs/source/conf.py
index c98a54f..399606a 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -35,14 +35,17 @@
 # Add any Sphinx extension module names here, as strings. They can be
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
-extensions = ["sphinx.ext.autodoc",
-              'sphinx.ext.napoleon',  # handle numpy & google style docstrings
-              'sphinx.ext.coverage',
-              "m2r2",  # md to rst
-              "sphinx_copybutton",
-              "sphinx_automodapi.automodapi",
-              "sphinx.ext.mathjax",
-              ]
+extensions = [
+    "sphinx.ext.autodoc",
+    'sphinx.ext.napoleon',  # handle numpy & google style docstrings
+    'sphinx.ext.coverage',
+    "m2r2",  # md to rst
+    "sphinx_copybutton",
+    "sphinx_automodapi.automodapi",
+    "sphinx.ext.mathjax",
+    "sphinx.ext.autosectionlabel",
+    "sphinx.ext.viewcode",
+]
 
 numpydoc_show_class_members = False
 automodsumm_inherited_members = True
@@ -69,17 +72,32 @@
 # so a file named "default.css" will overwrite the builtin "default.css".
 html_static_path = ['_static']
 
-html_logo = "_static/logo_pandas-cleaner.svg"
-html_favicon = "_static/favicon.ico"
+html_logo = "_static/pandas-cleaner.png"
+html_favicon = "_static/favicon.png"
 
 html_theme_options = {
     "icon_links": [
             {
-                "name": "GitLab",
-                "url": "https://edgitlab.eurodecision.com/data/pandas-cleaner",
-                "icon": "fab fa-gitlab",
+                "name": "Github",
+                "url": "https://github.com/eurodecision/pandas-cleaner",
+                "icon": "fab fa-github",
+            },
+            {
+                "name": "pypi",
+                "url": "https://pypi.org/project/pandas-cleaner/",
+                "icon": "fas fa-box",
+            },
+            {
+                "name": "EURODECISION",
+                "url": "https://eurodecision.com",
+                "icon": "_static/logo_ed_star.png",
+                "type": "local"
             },
         ],
+    "logo": {
+      "image_light": "pandas-cleaner.png",
+      "image_dark": "pandas-cleaner-dark.png",
+    }
 }
 
 html_sidebars = {
diff --git a/docs/source/contributing/bugs.rst b/docs/source/contributing/bugs.rst
deleted file mode 100644
index 84911c5..0000000
--- a/docs/source/contributing/bugs.rst
+++ /dev/null
@@ -1,2 +0,0 @@
-Bug reports
-===========
diff --git a/docs/source/contributing/code_of_conduct.rst b/docs/source/contributing/code_of_conduct.rst
new file mode 100644
index 0000000..d72a256
--- /dev/null
+++ b/docs/source/contributing/code_of_conduct.rst
@@ -0,0 +1,1 @@
+.. mdinclude:: ../../../CODE_OF_CONDUCT.md
diff --git a/docs/source/contributing/development.rst b/docs/source/contributing/development.rst
index 423a4d4..6e5902e 100644
--- a/docs/source/contributing/development.rst
+++ b/docs/source/contributing/development.rst
@@ -1,15 +1,43 @@
-Development
-===========
+Developments 
+============
 
-Clone the project
------------------
+.. note::
+
+   Before starting new code, we highly recommend opening an issue on
+   `GitHub <https://github.com/eurodecision/pandas-cleaner/issues>`_ to discuss potential changes.
+
+This page is partly based on https://docs.github.com/en/get-started/quickstart/contributing-to-projects
+Itis recommended to read it if it is your first time contributing to an open source project on github, 
+or if you need more detailed explanations.
+
+Fork the repo
+-------------
+
+1. Navigate to https://github.com/eurodecision/pandas-cleaner
+2. Click ``Fork``
+3. Available options are described on this page https://docs.github.com/en/get-started/quickstart/contributing-to-projects
+   Default ones should be ok
+4. Click on ``Create fork``
+
+
+Clone the fork
+--------------
+
+1. On GitHub, navigate to your fork
+2. Click on ``Code``
+3. Clone the fork with your preferred method
+
+Set up the development environment
+----------------------------------
+
+Navigate to your local version of the fork
 
 .. code-block:: bash
 
-   git clone git@edgitlab.eurodecision.com:data/pandas-cleaner.git
+   cd pandas-cleaner
 
 Virtual environment
--------------------
+~~~~~~~~~~~~~~~~~~~
 
 Create a virtual environment
 
@@ -30,22 +58,105 @@ On windows
    source venv/scripts/activate``
 
 Install dependencies
---------------------
+~~~~~~~~~~~~~~~~~~~~
 
 Pandas-cleaner depends on a few python packages, mainly pandas.
-The list of the dependencies is provided in the requirements.txt file.
+The list of the dependencies needed for development is provided in the requirements.txt file.
 These dependencies can be easily installed using pip :
 
 .. code-block:: bash
 
    pip install -r requirements.txt
 
-Unit tests
-----------
+Install the package
+~~~~~~~~~~~~~~~~~~~
+
+.. code-block:: bash
+
+    pip install -e .
+
+
+Code guidelines
+---------------
+
++ Please use `pep8 <https://pypi.python.org/pypi/pep8>`_ and `flake8 <http://flake8.pycqa.org/>`_ Python style guidelines.
+
+  .. code-block:: bash
+
+     pylint src
+     flake8 src
+
++ Use `NumPy style <https://numpydoc.readthedocs.io/en/latest/format.html#docstring-standard>`_ for docstrings. 
+
++ Changes must be accompanied by updated documentation and examples.
+
+  .. code-block::
+
+     make -C docs html
+
+  You can see it by opening ``docs/build/html/index.html`` in your browser.
+  
++ After making changes, ensure all tests pass and that your new code is covered by tests.
+  You can run the unit tests using the command:
+
+  .. code-block:: bash
+
+     pytest
 
-If you downloaded the source code and you have installed pytest, you can run the unit tests using the command:
+  and check the coverage
+
+  .. code-block:: bash
+
+     pytest --cov
+
+  Optionnally, create a html report 
+
+  .. code-block:: bash
+
+     pytest --cov --cov-report html
+
+  You can see it by opening ``htmlcov/index.html`` in your browser.
+
++ If your changes require new dependencies, check they are added in the ``requirements.txt`` and the ``setup.py``
+
+
+Pushing changes
+---------------
+
+When you're ready, stage and commit your changes. 
 
 .. code-block:: bash
 
-   python3 -m pytest pdcleaner/tests
+   git add .
+   git commit -m "a short description of the change"
+
+and push the modifications to your forked project
+
+.. code-block:: bash
+
+   git push
+
+Pull Request
+------------
+
+If you want to propose your changes into the main project.
+
+1. On the page of your fork, click ``Contribute`` and then ``Open a pull request``.
+
+GitHub will bring you to a page that shows the differences between your fork 
+and the main repository. 
+
+2. Click ``Create pull request``.
+
+GitHub will bring you to a page where you can enter a title and a description of your changes.
+
+.. note::
+
+    It's important to provide as much useful information and a rationale for why you're making this pull request
+    in the first place. The pandas-cleaner team needs to be able to determine whether your change is useful. 
+
+3. Finally, click ``Create pull request``.
 
+The pandas-cleaner team will review your contribution and provide a feedback.
+If every requirement is valid, your changes will be merged in the development branch and released
+in the next release version.
\ No newline at end of file
diff --git a/docs/source/contributing/documentation.rst b/docs/source/contributing/documentation.rst
deleted file mode 100644
index 2e49ab7..0000000
--- a/docs/source/contributing/documentation.rst
+++ /dev/null
@@ -1,2 +0,0 @@
-Contributing to documentation
-=============================
diff --git a/docs/source/contributing/enhancements.rst b/docs/source/contributing/enhancements.rst
deleted file mode 100644
index 12481c9..0000000
--- a/docs/source/contributing/enhancements.rst
+++ /dev/null
@@ -1,3 +0,0 @@
-Enhancement requests
-====================
-
diff --git a/docs/source/contributing/index.rst b/docs/source/contributing/index.rst
index b9bb92a..f43af5a 100644
--- a/docs/source/contributing/index.rst
+++ b/docs/source/contributing/index.rst
@@ -2,9 +2,9 @@ Contributing
 ============
 
 .. toctree::
-    :maxdepth: 2
+    :maxdepth: 1
+
+    issues
+    development
+    code_of_conduct
 
-    bugs
-    documentation
-    enhancements
-    development
\ No newline at end of file
diff --git a/docs/source/contributing/issues.rst b/docs/source/contributing/issues.rst
new file mode 100644
index 0000000..f2c31d5
--- /dev/null
+++ b/docs/source/contributing/issues.rst
@@ -0,0 +1,25 @@
+Issues
+======
+
+Issue reporting, feedback, proposal, design or any other comment are greatly appreciated!
+Do not hesitate to create an issue through `GitHub issues <https://github.com/eurodecision/pandas-cleaner/issues>`_.
+
+
+Bugs
+----
+
+Please report relevant information and preferably code that exhibits the problem.
+
+The pandas-cleaner team will analyse and try to reproduce the bug to provide feedback.
+If confirmed, we will add a priority to the issue and add it in our backlog. Feel free to propose a pull request to fix it.
+
+Enhancements or feature requests
+--------------------------------
+
+The pandas-cleaner team will analyse your proposal and return to you as soon as possible.
+
+
+Code contribution
+-----------------
+
+Please see :ref:`Developments` for details.
\ No newline at end of file
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 308eb0b..08e7b76 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -96,8 +96,3 @@ Clean the detected errors from the series using the chosen method among `drop`,
    reference/index
    contributing/index
    release/index
-
-Project's home page
--------------------
-
-You can visit the `project's home page <https://edgitlab.eurodecision.com/data/pandas-cleaner>`_.
diff --git a/docs/source/reference/plotting/alternatives.rst b/docs/source/reference/plotting/alternatives.rst
new file mode 100644
index 0000000..da42671
--- /dev/null
+++ b/docs/source/reference/plotting/alternatives.rst
@@ -0,0 +1,5 @@
+Alternatives representations detector
+=====================================
+
+.. automodule:: pdcleaner.plots.alternatives
+   :members:
\ No newline at end of file
diff --git a/docs/source/reference/plotting/index.rst b/docs/source/reference/plotting/index.rst
index 762c7da..7a99ee7 100644
--- a/docs/source/reference/plotting/index.rst
+++ b/docs/source/reference/plotting/index.rst
@@ -6,5 +6,5 @@ Plotting methods
 
    numseries
    freqandcount
-   keycollision
+   alternatives
    multicategories
diff --git a/docs/source/reference/plotting/keycollision.rst b/docs/source/reference/plotting/keycollision.rst
deleted file mode 100644
index d082610..0000000
--- a/docs/source/reference/plotting/keycollision.rst
+++ /dev/null
@@ -1,5 +0,0 @@
-Key collision detector
-======================
-
-.. automodule:: pdcleaner.plots.keycollision
-   :members:
\ No newline at end of file
diff --git a/docs/source/user_guide/10_minutes.rst b/docs/source/user_guide/10_minutes.rst
index a0eb76c..c84a324 100644
--- a/docs/source/user_guide/10_minutes.rst
+++ b/docs/source/user_guide/10_minutes.rst
@@ -135,7 +135,7 @@ detected errors.
 
 .. code:: ipython3
 
-    detector.detected
+    detector.detected()
 
 
 
@@ -340,7 +340,7 @@ This detects the following problematic lines :
 
 .. code:: ipython3
 
-    detector2.detected
+    detector2.detected()
 
 
 
diff --git a/docs/source/user_guide/detector_plot_10min.png b/docs/source/user_guide/detector_plot_10min.png
index 42eeaf1..05071cf 100644
Binary files a/docs/source/user_guide/detector_plot_10min.png and b/docs/source/user_guide/detector_plot_10min.png differ
diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst
index c94c39f..8b810ae 100644
--- a/docs/source/user_guide/index.rst
+++ b/docs/source/user_guide/index.rst
@@ -6,12 +6,12 @@ User guide
 
     install
     10_minutes
-    example_dataset
-    handling_num_series
-    cleaning_methods
-    handling_gauss_series
-    clean_by_category
-    handling_multivar
-    handling_cat_series
-    handling_multicategories
-    clean_text
+    .. example_dataset
+    .. handling_num_series
+    .. cleaning_methods
+    .. handling_gauss_series
+    .. clean_by_category
+    .. handling_multivar
+    .. handling_cat_series
+    .. handling_multicategories
+    .. clean_text
diff --git a/docs/source/user_guide/install.rst b/docs/source/user_guide/install.rst
index 3a89eed..aeeed4c 100644
--- a/docs/source/user_guide/install.rst
+++ b/docs/source/user_guide/install.rst
@@ -1,24 +1,14 @@
 Installation
 ============
 
-pandas-cleaner is at present time an internal EURODECISION python package.
+pandas-cleaner can be easily installed using pip
 
-To download and install it :
-
-* Go to https://edgitlab.eurodecision.com/eurodecision/releases/-/packages
-* Select the most recent version (or any older according to your needs), say 0.1.1
-
-Two options :
-
-#. Use a gitlab token
+.. code-block:: shell
 
-  * Create and add a token and use the given pip command
-  
-#. Dowload the wheel
+  pip install pandas-cleaner
 
-  * Download `pdcleaner-wversion-number>-py3-none-any.whl`
-  * Install using pip
+Whenever a new release is out there, you can upgrade your version by typing the following line in a terminal window:
 
 .. code-block:: shell
 
-  pip install pdcleaner-wversion-number>-py3-none-any.whl
\ No newline at end of file
+  pip install --upgrade
\ No newline at end of file
diff --git a/log.pylint b/log.pylint
deleted file mode 100644
index 88e23b5..0000000
--- a/log.pylint
+++ /dev/null
@@ -1,532 +0,0 @@
-************* Module pdcleaner
-src\pdcleaner\__init__.py:72:4: R0903: Too few public methods (1/2) (too-few-public-methods)
-src\pdcleaner\__init__.py:142:4: R0903: Too few public methods (1/2) (too-few-public-methods)
-src\pdcleaner\__init__.py:41:0: R0903: Too few public methods (0/2) (too-few-public-methods)
-src\pdcleaner\__init__.py:212:30: W0621: Redefining name 'detector_name' from outer scope (line 233) (redefined-outer-name)
-src\pdcleaner\__init__.py:241:44: W0108: Lambda may not be necessary (unnecessary-lambda)
-************* Module pdcleaner._version
-src\pdcleaner\_version.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-************* Module pdcleaner.cleaning.cleaning
-src\pdcleaner\cleaning\cleaning.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\cleaning\cleaning.py:69:4: R1705: Unnecessary "else" after "return" (no-else-return)
-src\pdcleaner\cleaning\cleaning.py:143:4: R1705: Unnecessary "else" after "return" (no-else-return)
-src\pdcleaner\cleaning\cleaning.py:144:11: W0212: Access to a protected member _get_cacher of a client class (protected-access)
-src\pdcleaner\cleaning\cleaning.py:205:4: R1705: Unnecessary "else" after "return" (no-else-return)
-src\pdcleaner\cleaning\cleaning.py:286:8: E0102: function already defined line 212 (function-redefined)
-src\pdcleaner\cleaning\cleaning.py:286:8: C0103: Argument name "s" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\cleaning\cleaning.py:305:4: R1705: Unnecessary "else" after "return" (no-else-return)
-src\pdcleaner\cleaning\cleaning.py:292:0: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
-src\pdcleaner\cleaning\cleaning.py:2:0: C0411: standard import "import warnings" should be placed before "import pandas as pd" (wrong-import-order)
-************* Module pdcleaner.detection.basic
-src\pdcleaner\detection\basic.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\basic.py:82:4: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\detection\basic.py:119:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\basic.py:125:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\basic.py:131:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\basic.py:135:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\basic.py:250:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\basic.py:251:8: R1705: Unnecessary "else" after "return" (no-else-return)
-src\pdcleaner\detection\basic.py:258:33: W0108: Lambda may not be necessary (unnecessary-lambda)
-src\pdcleaner\detection\basic.py:3:0: C0411: standard import "import warnings" should be placed before "import numpy as np" (wrong-import-order)
-src\pdcleaner\detection\basic.py:4:0: C0411: standard import "import numbers" should be placed before "import numpy as np" (wrong-import-order)
-************* Module pdcleaner.detection.by_category
-src\pdcleaner\detection\by_category.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\by_category.py:64:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\by_category.py:68:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\by_category.py:75:8: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-************* Module pdcleaner.detection.categorical
-src\pdcleaner\detection\categorical.py:393:0: C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
-src\pdcleaner\detection\categorical.py:514:0: C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
-src\pdcleaner\detection\categorical.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\categorical.py:69:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:164:4: C0103: Attribute name "n" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\detection\categorical.py:164:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:168:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:269:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:273:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:368:4: R0913: Too many arguments (7/5) (too-many-arguments)
-src\pdcleaner\detection\categorical.py:397:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:401:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:405:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:409:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:530:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:534:8: C0103: Variable name "d" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\detection\categorical.py:541:4: C0103: Argument name "s" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\detection\categorical.py:552:23: W0108: Lambda may not be necessary (unnecessary-lambda)
-src\pdcleaner\detection\categorical.py:556:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\categorical.py:556:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
-************* Module pdcleaner.detection.gaussian
-src\pdcleaner\detection\gaussian.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\gaussian.py:76:4: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\detection\gaussian.py:111:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:115:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:119:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:123:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:171:4: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\detection\gaussian.py:209:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:213:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:294:4: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\detection\gaussian.py:321:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:325:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:329:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:411:4: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\detection\gaussian.py:438:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:442:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:446:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\gaussian.py:2:0: C0411: standard import "import numbers" should be placed before "import numpy as np" (wrong-import-order)
-src\pdcleaner\detection\gaussian.py:3:0: C0411: standard import "import warnings" should be placed before "import numpy as np" (wrong-import-order)
-************* Module pdcleaner.detection.multicategories
-src\pdcleaner\detection\multicategories.py:65:0: C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
-src\pdcleaner\detection\multicategories.py:66:0: C0325: Unnecessary parens after 'if' keyword (superfluous-parens)
-src\pdcleaner\detection\multicategories.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\multicategories.py:84:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multicategories.py:88:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multicategories.py:92:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multicategories.py:93:8: R1705: Unnecessary "elif" after "return" (no-else-return)
-src\pdcleaner\detection\multicategories.py:92:4: R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)
-src\pdcleaner\detection\multicategories.py:99:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multicategories.py:104:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multicategories.py:108:4: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\detection\multicategories.py:108:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multicategories.py:120:8: C0103: Variable name "s" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\detection\multicategories.py:134:8: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\detection\multicategories.py:2:0: C0411: standard import "import numbers" should be placed before "import pandas as pd" (wrong-import-order)
-************* Module pdcleaner.detection.multivariate
-src\pdcleaner\detection\multivariate.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\multivariate.py:103:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multivariate.py:107:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\multivariate.py:127:12: W0707: Consider explicitly re-raising using the 'from' keyword (raise-missing-from)
-************* Module pdcleaner.detection._base
-src\pdcleaner\detection\_base.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\detection\_base.py:18:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\_base.py:27:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\_base.py:30:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\_base.py:35:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\_base.py:41:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\_base.py:53:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\detection\_base.py:59:4: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.plots.keycollision
-src\pdcleaner\plots\keycollision.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\plots\keycollision.py:8:0: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\plots\keycollision.py:70:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\plots\keycollision.py:89:8: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\plots\keycollision.py:108:8: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-************* Module pdcleaner.plots.multicategories
-src\pdcleaner\plots\multicategories.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\plots\multicategories.py:49:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\plots\multicategories.py:60:4: C0103: Variable name "c2" doesn't conform to snake_case naming style (invalid-name)
-************* Module pdcleaner.plots.numseries
-src\pdcleaner\plots\numseries.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\plots\numseries.py:11:0: R0913: Too many arguments (6/5) (too-many-arguments)
-src\pdcleaner\plots\numseries.py:11:0: R0914: Too many local variables (16/15) (too-many-locals)
-src\pdcleaner\plots\numseries.py:57:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\plots\numseries.py:11:0: R0912: Too many branches (18/12) (too-many-branches)
-************* Module pdcleaner.tests.conftest
-src\pdcleaner\tests\conftest.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\tests\conftest.py:145:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\conftest.py:196:4: C0103: Variable name "x" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\conftest.py:197:4: C0103: Variable name "y1" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\conftest.py:198:4: C0103: Variable name "y2" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\conftest.py:199:4: C0103: Variable name "y3" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\conftest.py:200:4: C0103: Variable name "x4" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\conftest.py:201:4: C0103: Variable name "y4" doesn't conform to snake_case naming style (invalid-name)
-************* Module pdcleaner.tests.test_bounded
-src\pdcleaner\tests\test_bounded.py:9:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:16:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:23:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:36:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:42:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:49:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:92:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:98:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:104:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:110:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_bounded.py:116:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_by_category
-src\pdcleaner\tests\test_by_category.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\tests\test_by_category.py:5:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_cat_associations
-src\pdcleaner\tests\test_cat_associations.py:16:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:23:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:39:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:45:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:51:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:57:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:63:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:69:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:74:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:79:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:84:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:91:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:99:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_associations.py:108:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_cat_keycollision
-src\pdcleaner\tests\test_cat_keycollision.py:50:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_cat_keycollision.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_keycollision.py:17:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_keycollision.py:22:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_keycollision.py:27:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_keycollision.py:33:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_keycollision.py:39:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_keycollision.py:46:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_cat_pattern
-src\pdcleaner\tests\test_cat_pattern.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_pattern.py:17:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_pattern.py:22:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_pattern.py:27:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_pattern.py:36:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_pattern.py:42:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_pattern.py:52:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_cat_values
-src\pdcleaner\tests\test_cat_values.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:19:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:24:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:36:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:46:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:51:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:56:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:61:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:67:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:73:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:78:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:88:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:93:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:98:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:103:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:109:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:115:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_cat_values.py:120:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_clean
-src\pdcleaner\tests\test_clean.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\tests\test_clean.py:10:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:17:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:24:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:31:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:38:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:45:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:52:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:59:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:66:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:76:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:83:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:90:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:97:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:107:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:119:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:131:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:138:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:148:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:156:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:165:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:173:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_clean.py:181:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_custom_detector
-src\pdcleaner\tests\test_custom_detector.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\tests\test_custom_detector.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:14:4: C0115: Missing class docstring (missing-class-docstring)
-src\pdcleaner\tests\test_custom_detector.py:17:8: W0102: Dangerous default value [] as argument (dangerous-default-value)
-src\pdcleaner\tests\test_custom_detector.py:29:8: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:14:4: W0612: Unused variable 'MyValuesSeriesDetector' (unused-variable)
-src\pdcleaner\tests\test_custom_detector.py:44:0: C0115: Missing class docstring (missing-class-docstring)
-src\pdcleaner\tests\test_custom_detector.py:46:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:46:4: R0201: Method could be a function (no-self-use)
-src\pdcleaner\tests\test_custom_detector.py:51:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:51:52: W0621: Redefining name 'add_custom_detector' from outer scope (line 12) (redefined-outer-name)
-src\pdcleaner\tests\test_custom_detector.py:51:52: W0613: Unused argument 'add_custom_detector' (unused-argument)
-src\pdcleaner\tests\test_custom_detector.py:51:4: R0201: Method could be a function (no-self-use)
-src\pdcleaner\tests\test_custom_detector.py:57:0: C0115: Missing class docstring (missing-class-docstring)
-src\pdcleaner\tests\test_custom_detector.py:58:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:62:12: C0115: Missing class docstring (missing-class-docstring)
-src\pdcleaner\tests\test_custom_detector.py:63:16: W0102: Dangerous default value [] as argument (dangerous-default-value)
-src\pdcleaner\tests\test_custom_detector.py:75:16: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:62:12: W0612: Unused variable 'NoNameValuesSeriesDetector' (unused-variable)
-src\pdcleaner\tests\test_custom_detector.py:57:0: R0903: Too few public methods (1/2) (too-few-public-methods)
-src\pdcleaner\tests\test_custom_detector.py:85:0: C0115: Missing class docstring (missing-class-docstring)
-src\pdcleaner\tests\test_custom_detector.py:86:4: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:91:12: C0115: Missing class docstring (missing-class-docstring)
-src\pdcleaner\tests\test_custom_detector.py:94:16: W0102: Dangerous default value [] as argument (dangerous-default-value)
-src\pdcleaner\tests\test_custom_detector.py:106:16: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_custom_detector.py:91:12: W0612: Unused variable 'NoNameValuesSeriesDetector' (unused-variable)
-src\pdcleaner\tests\test_custom_detector.py:85:0: R0903: Too few public methods (1/2) (too-few-public-methods)
-************* Module pdcleaner.tests.test_detect_api
-src\pdcleaner\tests\test_detect_api.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_api.py:13:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_detect_special_index_series
-src\pdcleaner\tests\test_detect_special_index_series.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_special_index_series.py:17:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_special_index_series.py:26:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_special_index_series.py:33:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_special_index_series.py:40:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_special_index_series.py:47:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_detect_with_outliers_obj
-src\pdcleaner\tests\test_detect_with_outliers_obj.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_with_outliers_obj.py:14:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_with_outliers_obj.py:23:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_with_outliers_obj.py:29:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_detect_with_outliers_obj.py:37:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_df_utils
-src\pdcleaner\tests\test_df_utils.py:15:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:20:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:25:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:35:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:40:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:45:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:50:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:55:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:60:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:65:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:70:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:75:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_df_utils.py:80:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_iqr
-src\pdcleaner\tests\test_iqr.py:47:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:48:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:49:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:61:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:62:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:63:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:64:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:65:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:71:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:72:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:73:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:74:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:75:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:84:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:85:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:86:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:87:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:94:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:95:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:96:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:103:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:104:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:105:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_iqr.py:10:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_iqr.py:16:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_iqr.py:22:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_iqr.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_keycollision_plot
-src\pdcleaner\tests\test_keycollision_plot.py:38:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_keycollision_plot.py:41:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_keycollision_plot.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:15:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:22:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:29:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:36:0: C0103: Argument name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_keycollision_plot.py:36:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:44:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:47:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_keycollision_plot.py:54:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:57:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_keycollision_plot.py:64:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:67:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_keycollision_plot.py:74:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:77:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_keycollision_plot.py:84:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:87:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_keycollision_plot.py:94:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_keycollision_plot.py:97:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-************* Module pdcleaner.tests.test_multivar_numerics
-src\pdcleaner\tests\test_multivar_numerics.py:12:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:16:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:17:4: C0103: Variable name "s" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:23:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:29:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:30:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:35:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:36:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:42:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:43:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:49:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:50:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:56:0: C0103: Function name "test_anscombe_I" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:56:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:57:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:63:0: C0103: Function name "test_anscombe_II" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:63:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:64:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:69:0: C0103: Function name "test_anscombe_III" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:69:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:70:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:76:0: C0103: Function name "test_anscombe_IV" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:76:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:77:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:83:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:84:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:93:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:94:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:100:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:101:4: C0103: Variable name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_multivar_numerics.py:109:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_multivar_numerics.py:113:8: W0106: Expression "dataframe.cleaner.detect('ndoutliers').index" is assigned to nothing (expression-not-assigned)
-************* Module pdcleaner.tests.test_plot
-src\pdcleaner\tests\test_plot.py:24:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:25:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:26:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:32:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:33:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:34:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:48:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:49:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:50:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:56:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:57:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:58:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:65:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:66:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:67:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:74:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:75:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:76:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:83:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:84:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:85:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:92:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:93:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:94:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:173:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:175:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:184:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:186:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:199:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:201:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:215:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:217:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:239:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:242:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:257:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:260:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:279:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:302:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:305:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:313:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:316:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot.py:22:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:38:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:46:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:54:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:62:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:71:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:80:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:89:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:101:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:113:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:134:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:151:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:299:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot.py:310:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_plot_multicategories_associations
-src\pdcleaner\tests\test_plot_multicategories_associations.py:11:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:18:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:8:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:10:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:15:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:17:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:22:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:24:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:25:11: R1718: Consider using a set comprehension (consider-using-set-comprehension)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:30:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:32:4: C0103: Variable name "ax" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\tests\test_plot_multicategories_associations.py:33:11: R1718: Consider using a set comprehension (consider-using-set-comprehension)
-************* Module pdcleaner.tests.test_quantile_detector
-src\pdcleaner\tests\test_quantile_detector.py:49:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_quantile_detector.py:50:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_quantile_detector.py:62:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_quantile_detector.py:63:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_quantile_detector.py:64:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_quantile_detector.py:65:0: C0325: Unnecessary parens after 'assert' keyword (superfluous-parens)
-src\pdcleaner\tests\test_quantile_detector.py:9:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_quantile_detector.py:16:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_quantile_detector.py:23:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_quantile_detector.py:29:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_series_type
-src\pdcleaner\tests\test_series_type.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\tests\test_series_type.py:7:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_series_type.py:44:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_utils_valid_dtype
-src\pdcleaner\tests\test_utils_valid_dtype.py:1:0: C0114: Missing module docstring (missing-module-docstring)
-src\pdcleaner\tests\test_utils_valid_dtype.py:4:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_utils_valid_dtype.py:12:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.tests.test_zscore
-src\pdcleaner\tests\test_zscore.py:10:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:15:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:20:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:28:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:42:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:48:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:54:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:59:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:64:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:74:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:85:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:125:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:130:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:136:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:144:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:158:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:164:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:170:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:175:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:180:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:192:0: C0116: Missing function or method docstring (missing-function-docstring)
-src\pdcleaner\tests\test_zscore.py:203:0: C0116: Missing function or method docstring (missing-function-docstring)
-************* Module pdcleaner.utils.df_utils
-src\pdcleaner\utils\df_utils.py:14:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\utils\df_utils.py:31:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\utils\df_utils.py:37:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\utils\df_utils.py:44:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\utils\df_utils.py:50:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\utils\df_utils.py:56:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-src\pdcleaner\utils\df_utils.py:65:0: C0103: Argument name "df" doesn't conform to snake_case naming style (invalid-name)
-************* Module pdcleaner.utils.utils
-src\pdcleaner\utils\utils.py:28:4: R1705: Unnecessary "else" after "return" (no-else-return)
-************* Module pdcleaner.utils.__init__
-src\pdcleaner\utils\__init__.py:1:0: R0401: Cyclic import (pdcleaner -> pdcleaner.utils.utils) (cyclic-import)
-src\pdcleaner\utils\__init__.py:1:0: R0401: Cyclic import (pdcleaner -> pdcleaner.detection.basic -> pdcleaner.utils.utils) (cyclic-import)
-src\pdcleaner\utils\__init__.py:1:0: R0401: Cyclic import (pdcleaner -> pdcleaner.detection.gaussian -> pdcleaner.detection.basic -> pdcleaner.utils.utils) (cyclic-import)
-src\pdcleaner\utils\__init__.py:1:0: R0401: Cyclic import (pdcleaner -> pdcleaner.plots.keycollision -> pdcleaner.utils.utils) (cyclic-import)
-src\pdcleaner\utils\__init__.py:1:0: R0401: Cyclic import (pdcleaner -> pdcleaner.plots.multicategories -> pdcleaner.utils.utils) (cyclic-import)
-src\pdcleaner\utils\__init__.py:1:0: R0401: Cyclic import (pdcleaner -> pdcleaner.plots.numseries -> pdcleaner.utils.utils) (cyclic-import)
-src\pdcleaner\utils\__init__.py:1:0: R0801: Similar lines in 4 files
-==pdcleaner.detection.categorical:59
-==pdcleaner.tests.test_custom_detector:19
-==pdcleaner.tests.test_custom_detector:65
-==pdcleaner.tests.test_custom_detector:96
-            if not detector_obj:
-                self._values_list = values_list
-            else:
-                self._values_list = detector_obj.values_list
-
-            if len(self._values_list) == 0:
-                raise ValueError("The list of authorized values is empty")
-
-        @property
-        def values_list(self):
-            return self._values_list
-
-        @property
-        def index(self): (duplicate-code)
-src\pdcleaner\utils\__init__.py:1:0: R0801: Similar lines in 2 files
-==pdcleaner.tests.test_cat_keycollision:3
-==pdcleaner.tests.test_cat_pattern:3
-import pytest
-import pandas as pd
-from pandas.testing import assert_series_equal
-
-
-# TestFingerPrintKeyCollision:
-
-
-def test_numerical_series_raise(series_with_outlier):
-    with pytest.raises(TypeError, match="applies to categorical/string Series"): (duplicate-code)
-
-------------------------------------------------------------------
-Your code has been rated at 7.76/10 (previous run: 7.73/10, +0.02)
-
diff --git a/setup.py b/setup.py
index eb9b62d..9f97dd8 100644
--- a/setup.py
+++ b/setup.py
@@ -3,10 +3,10 @@
 
 # c.f. https://packaging.python.org/tutorials/packaging-projects/
 
-with open("README.rst", "r", encoding="utf-8") as fh:
+with open("README.md", "r", encoding="utf-8") as fh:
     long_description = fh.read()
 
-VERSIONFILE = "pdcleaner/__version__.py"
+VERSIONFILE = "src/pdcleaner/__version__.py"
 verstrline = open(VERSIONFILE, "rt").read()
 VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
 mo = re.search(VSRE, verstrline, re.M)
@@ -26,7 +26,7 @@
     url="https://github.com/eurodecision/pandas-cleaner",
     project_urls={
         "Documentation":
-        "https://github.com/eurodecision/pandas-cleaner/blob/master/README.rst",
+        "https://github.com/eurodecision/pandas-cleaner/blob/master/README.md",
         "Source Code":
         "https://github.com/eurodecision/pandas-cleaner",
         "Bug Tracker":
@@ -43,7 +43,8 @@
         "Topic :: Scientific/Engineering",
     ],
 
-    packages=setuptools.find_packages(where="."),
+    packages=setuptools.find_packages(where="src"),
+    package_dir={"":"src"},
     python_requires=">=3.6",
     setup_requires=["wheel"],
     install_requires=[
diff --git a/sonar-project.properties b/sonar-project.properties
deleted file mode 100644
index 646c0e0..0000000
--- a/sonar-project.properties
+++ /dev/null
@@ -1,18 +0,0 @@
-sonar.projectKey=pandas-cleaner
-
-sonar.projectName=pandas-cleaner
-sonar.projectVersion=0.1.2
-
-sonar.sources=pdcleaner
-sonar.tests=pdcleaner/tests
-
-sonar.exclusions=pdcleaner/tests/**, **/venv*/**
-sonar.coverage.exclusions=pdcleaner/tests/**, pdcleaner/_version.py
-sonar.cpd.exclusions=pdcleaner/tests/**
-sonar.test.exclusions=pdcleaner/tests/**
-
-sonar.python.coverage.reportPaths=coverage.xml
-sonar.python.pylint.reportPaths=pylint.log
-sonar.python.flake8.reportPaths=flake8.log
-sonar.python.bandit.reportPaths=bandit.json
-sonar.python.xunit.reportPath=test_result.xml
diff --git a/pdcleaner/__init__.py b/src/pdcleaner/__init__.py
similarity index 93%
rename from pdcleaner/__init__.py
rename to src/pdcleaner/__init__.py
index 49f78ea..c0d2344 100644
--- a/pdcleaner/__init__.py
+++ b/src/pdcleaner/__init__.py
@@ -32,7 +32,7 @@
 # Import plotting methods
 
 from pdcleaner.plots.numseries import *
-from pdcleaner.plots.keycollision import *
+from pdcleaner.plots.alternatives import *
 from pdcleaner.plots.multicategories import *
 from pdcleaner.plots.freqandcount import *
 
@@ -121,10 +121,10 @@ def __call__(self, *args, **kwargs):
 
             if isinstance(args[0], _Detector):
                 method = args[0].name
-                detector_obj = args[0]
+                detector = args[0]
             elif isinstance(args[0], str):
                 method = args[0]
-                detector_obj = None
+                detector = None
             else:
                 raise TypeError(f"{args[0]} is not "
                                 "a valid argument for detect")
@@ -139,7 +139,7 @@ def __call__(self, *args, **kwargs):
                 if is_nums_and_cat_df(self._obj):
                     detector_instance = \
                         detection_classes['by_category'](self._obj,
-                                                         detector_obj=detector_obj,
+                                                         detector=detector,
                                                          method=method,
                                                          method_kwargs=kwargs)
                 else:
@@ -148,7 +148,7 @@ def __call__(self, *args, **kwargs):
             else:
                 detector_instance = \
                     detection_classes[method](self._obj,
-                                              detector_obj=detector_obj,
+                                              detector=detector,
                                               **kwargs)
 
             return detector_instance
@@ -171,13 +171,13 @@ class CleanerAccessor():
         def __init__(self, obj):
             self._obj = obj
 
-        def __call__(self, method, detector_obj, **kwargs):
+        def __call__(self, method, detector, **kwargs):
             """The function called when CleanerAccessor class is called.
             Mainly, when cleaner.clean is invoked
 
             Args:
               method (str): The cleaning method to be used.
-              detector_obj (_Detector) : The detector used to spot the errors
+              detector (_Detector) : The detector used to spot the errors
               **kwargs: keyword arguments passed to the cleaning method.
 
             Returns:
@@ -200,17 +200,17 @@ def __call__(self, method, detector_obj, **kwargs):
 
             cleaned_obj = \
                 series_cleaning_methods[method](self,
-                                                detector_obj=detector_obj,
+                                                detector=detector,
                                                 **kwargs)
             return cleaned_obj
 
-    def detected(self, detector_obj):
+    def detected(self, detector):
         """Returns the errors detected by a detector"""
-        return self._obj[detector_obj.is_error()]
+        return self._obj[detector.is_error()]
 
-    def valid(self, detector_obj):
+    def valid(self, detector):
         """Returns the values considered as valid (not errors) by a detector"""
-        return self._obj[detector_obj.not_error()]
+        return self._obj[detector.not_error()]
 
 
 # Register detection methods
@@ -257,7 +257,7 @@ def method(self, **kwargs):
 
 # Register cleaning functions
 
-list_series_cleaning_methods = ['clip', 'drop', 'to_na', 'replace', 'bykeys', 'cast', 'strip']
+list_series_cleaning_methods = ['clip', 'drop', 'to_na', 'replace', 'alternatives', 'cast', 'strip']
 series_cleaning_methods = {}
 
 for cleaning_member in getmembers(cleaning, isfunction):
diff --git a/pdcleaner/__version__.py b/src/pdcleaner/__version__.py
similarity index 51%
rename from pdcleaner/__version__.py
rename to src/pdcleaner/__version__.py
index 29b522b..6b6d42f 100644
--- a/pdcleaner/__version__.py
+++ b/src/pdcleaner/__version__.py
@@ -1,3 +1,3 @@
 """Package version"""
 
-__version__ = "0.0.1"
+__version__ = "0.0.2"
diff --git a/pdcleaner/cleaning/__init__.py b/src/pdcleaner/cleaning/__init__.py
similarity index 100%
rename from pdcleaner/cleaning/__init__.py
rename to src/pdcleaner/cleaning/__init__.py
diff --git a/pdcleaner/cleaning/cleaning.py b/src/pdcleaner/cleaning/cleaning.py
similarity index 64%
rename from pdcleaner/cleaning/cleaning.py
rename to src/pdcleaner/cleaning/cleaning.py
index ab80caa..934a57c 100644
--- a/pdcleaner/cleaning/cleaning.py
+++ b/src/pdcleaner/cleaning/cleaning.py
@@ -9,13 +9,13 @@
 import pandas as pd
 
 
-def clip(self, detector_obj, inplace=False):
+def clip(self, detector, inplace=False):
     """
     Clean numerical series by clipping between lower and upper values
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
         and provide upper and lower limits
 
@@ -33,15 +33,15 @@ def clip(self, detector_obj, inplace=False):
     Examples
     --------
 
-    >>> my_series = pd.Series([np.nan,
+    >>> series = pd.Series([np.nan,
                                0,
                                -5,
                                4,
                                6,
                                100,
                                ])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=0, upper=10)
-    >>> my_series.cleaner.clean.clip(my_detector)
+    >>> detector = series.cleaner.detect.bounded(lower=0, upper=10)
+    >>> series.cleaner.clean.clip(detector)
     0     NaN
     1     0.0
     2     0.0
@@ -52,8 +52,8 @@ def clip(self, detector_obj, inplace=False):
 
     Modify inplace
 
-    >>> my_series.cleaner.clean.clip(my_detector, inplace=True)
-    >>> my_series
+    >>> series.cleaner.clean.clip(detector, inplace=True)
+    >>> series
     0     NaN
     1     0.0
     2     0.0
@@ -62,15 +62,15 @@ def clip(self, detector_obj, inplace=False):
     5    10.0
     dtype: float64
     """
-    series = detector_obj.obj
+    series = detector.obj
 
-    if not hasattr(detector_obj, 'lower') or not hasattr(detector_obj, 'upper'):
+    if not hasattr(detector, 'lower') or not hasattr(detector, 'upper'):
         raise ValueError('The errors detection method does not have lower and upper bounds'
                          ' and can not be used with clip')
 
     # else
-    lower = detector_obj.lower
-    upper = detector_obj.upper
+    lower = detector.lower
+    upper = detector.upper
 
     if inplace:
         series.clip(upper=upper, lower=lower, inplace=True)
@@ -78,13 +78,13 @@ def clip(self, detector_obj, inplace=False):
     return series.clip(upper=upper, lower=lower)
 
 
-def drop(self, detector_obj, inplace=False):
+def drop(self, detector, inplace=False):
     """
     Clean by dropping errors
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
 
     inplace:  bool (Default: False)
@@ -106,15 +106,15 @@ def drop(self, detector_obj, inplace=False):
     Examples
     --------
 
-    >>> my_series = pd.Series([np.nan,
+    >>> series = pd.Series([np.nan,
                                0,
                                -5,
                                4,
                                6,
                                100,
                                ])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=0, upper=10)
-    >>> my_series.cleaner.clean.drop(my_detector)
+    >>> detector = series.cleaner.detect.bounded(lower=0, upper=10)
+    >>> series.cleaner.clean.drop(detector)
     0    NaN
     1    0.0
     3    4.0
@@ -123,8 +123,8 @@ def drop(self, detector_obj, inplace=False):
 
     Modify inplace
 
-    >>> my_series.cleaner.clean.drop(my_detector, inplace=True)
-    >>> my_series
+    >>> series.cleaner.clean.drop(detector, inplace=True)
+    >>> series
     0    NaN
     1    0.0
     3    4.0
@@ -135,36 +135,37 @@ def drop(self, detector_obj, inplace=False):
 
     >>> df = pd.DataFrame({"col1": [np.nan, 0, -5, 4, 6, 100],
     >>>                    "col2": ["a", "b", "c", "d", "e", "f"]})
-    >>> my_df_detector = df["col1"].cleaner.detect.bounded(lower=0, upper=10)
-    >>> df["col1"].cleaner.clean.drop(my_df_detector)
+    >>> df_detector = df["col1"].cleaner.detect.bounded(lower=0, upper=10)
+    >>> df["col1"].cleaner.clean.drop(df_detector)
 
     Cleaning a dataframe inplace with the drop method is not supported
     (issues a warning)
 
     >>> df = pd.DataFrame({"col1": [np.nan, 0, -5, 4, 6, 100],
     >>>                    "col2": ["a", "b", "c", "d", "e", "f"]})
-    >>> my_df_detector = df["col1"].cleaner.detect.bounded(lower=0, upper=10)
-    >>> df["col1"].cleaner.clean.drop(my_df_detector, inplace=True)
+    >>> df_detector = df["col1"].cleaner.detect.bounded(lower=0, upper=10)
+    >>> df["col1"].cleaner.clean.drop(df_detector, inplace=True)
     """
-    series = detector_obj.obj
 
     if inplace:
-        if series._get_cacher() is not None:
-            warnings.warn("Series is a column of a DataFrame. "
-                          "Dropping inplace will not modify the DataFrame.")
 
-        self._obj.drop(detector_obj.index, inplace=True)
+        if isinstance(detector.obj, pd.Series):
+            if detector.obj._get_cacher() is not None:
+                warnings.warn("Series is a column of a DataFrame. "
+                              "Dropping inplace will not modify the DataFrame.")
+
+        self._obj.drop(detector.index, inplace=True)
         return None
-    return self._obj.drop(detector_obj.index)
+    return self._obj.drop(detector.index)
 
 
-def to_na(self, detector_obj, inplace=False):
+def to_na(self, detector, inplace=False):
     """
     Clean by replacing errors by NaN
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
 
     inplace:  bool (Default: False)
@@ -178,15 +179,15 @@ def to_na(self, detector_obj, inplace=False):
     Examples
     --------
 
-    >>> my_series = pd.Series([np.nan,
+    >>> series = pd.Series([np.nan,
                                0,
                                -5,
                                4,
                                6,
                                100,
                                ])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=0, upper=10)
-    >>> my_series.cleaner.clean.to_na(my_detector)
+    >>> detector = series.cleaner.detect.bounded(lower=0, upper=10)
+    >>> series.cleaner.clean.to_na(detector)
     0    NaN
     1    0.0
     2    NaN
@@ -197,8 +198,8 @@ def to_na(self, detector_obj, inplace=False):
 
     Replace inplace
 
-    >>> my_series.cleaner.clean.to_na(my_detector, inplace=True)
-    >>> my_series
+    >>> series.cleaner.clean.to_na(detector, inplace=True)
+    >>> series
     0    NaN
     1    0.0
     2    NaN
@@ -207,21 +208,21 @@ def to_na(self, detector_obj, inplace=False):
     5    NaN
     dtype: float64
     """
-    series = detector_obj.obj
+    series = detector.obj
 
     if inplace:
-        series.where(detector_obj.not_error(), np.nan, inplace=True)
+        series.where(detector.not_error(), np.nan, inplace=True)
         return None
-    return series.where(detector_obj.not_error(), np.nan)
+    return series.where(detector.not_error(), np.nan)
 
 
-def replace(self, detector_obj, value=None, inplace=False):
+def replace(self, detector, value=None, inplace=False):
     """
     Clean by replacing errors by a value
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
     value: string, numeric, dict or callable
         The replacement strategy.
@@ -246,15 +247,15 @@ def replace(self, detector_obj, value=None, inplace=False):
     Examples
     --------
 
-    >>> my_series = pd.Series([np.nan,
+    >>> series = pd.Series([np.nan,
                                0,
                                -5,
                                4,
                                6,
                                100,
                                ])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=0, upper=10)
-    >>> my_series.cleaner.clean.replace(my_detector, value=5)
+    >>> detector = series.cleaner.detect.bounded(lower=0, upper=10)
+    >>> series.cleaner.clean.replace(detector, value=5)
     0    NaN
     1    0.0
     2    5.0
@@ -265,7 +266,7 @@ def replace(self, detector_obj, value=None, inplace=False):
 
     Replace using a dictionary
 
-    >>> my_series.cleaner.clean.replace(my_detector, value={100:10})
+    >>> series.cleaner.clean.replace(detector, value={100:10})
     0    NaN
     1    0.0
     2    NaN
@@ -276,7 +277,7 @@ def replace(self, detector_obj, value=None, inplace=False):
 
     Replace using a lambda (the lambda applies to the series of erroneous entries)
 
-    >>> my_series.cleaner.clean.replace(my_detector,
+    >>> series.cleaner.clean.replace(detector,
     >>>                                 value=lambda s: s.clip(lower=0) / 10 )
     0    NaN
     1    0.0
@@ -286,7 +287,7 @@ def replace(self, detector_obj, value=None, inplace=False):
     5   10.0
     dtype: float64
     """
-    series = detector_obj.obj
+    series = detector.obj
 
     if isinstance(value, dict):
         value_dict = value
@@ -295,21 +296,21 @@ def dict2func(series_):
             return series_.map(value_dict)
         value = dict2func
 
-    return series.where(detector_obj.not_error(), value, inplace=inplace)
+    return series.where(detector.not_error(), value, inplace=inplace)
 
 
-def bykeys(self, detector_obj, inplace=False):
+def alternatives(self, detector, inplace=False):
     """
     Clean by merging values that have been identified as alternative representations
     of the same object by a key collision detector.
 
     Note
     ----
-    This method can only applied with a 'keycollision' detector.
+    This method can only applied with a 'alternatives' detector.
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
     inplace:  bool (Default: False)
         Whether to perform the operation in place on the data.
@@ -325,7 +326,7 @@ def bykeys(self, detector_obj, inplace=False):
 
     >>> series = pd.Series(['Linus Torvalds','linus.torvalds','Torvalds, Linus',
     >>>                     'Linus Torvalds', 'Bill Gates'])
-    >>> detector = series.cleaner.detect.keycollision()
+    >>> detector = series.cleaner.detect.alternatives()
     >>> print(detector.is_error())
     0    False
     1     True
@@ -336,7 +337,7 @@ def bykeys(self, detector_obj, inplace=False):
 
     Clean by standardizing
 
-    >>> print(series.cleaner.clean('bykeys', detector))
+    >>> print(series.cleaner.clean('alternatives', detector))
     0    Linus Torvalds
     1    Linus Torvalds
     2    Linus Torvalds
@@ -345,24 +346,24 @@ def bykeys(self, detector_obj, inplace=False):
     dtype: object
     """
 
-    if not hasattr(detector_obj, 'dict_keys'):
+    if not hasattr(detector, 'dict_keys'):
         raise ValueError('The errors detection method does not have a keys dictionary')
 
     series = self._obj
 
-    keys = detector_obj.fingerprints(series)
+    keys = detector.fingerprints(series)
 
     if inplace:
-        dict_replace = pd.Series(keys.map(detector_obj.dict_keys).values,
+        dict_replace = pd.Series(keys.map(detector.dict_keys).values,
                                  index=series
                                  ).to_dict()
 
         series.replace(dict_replace, inplace=True)
         return None
-    return keys.map(detector_obj.dict_keys)
+    return keys.map(detector.dict_keys)
 
 
-def cast(self, detector_obj, **kwargs):
+def cast(self, detector, **kwargs):
     """
     Clean by casting value into the specific target type. When the value is not castable, it is
     transformed to NaN. This method works only with the castable detector.
@@ -372,7 +373,7 @@ def cast(self, detector_obj, **kwargs):
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
 
     Returns
@@ -382,9 +383,9 @@ def cast(self, detector_obj, **kwargs):
     Examples
     --------
 
-    >>> my_series = pd.Series(['100 000', '154,5', '9 000', '250,12'], dtype='object')
-    >>> my_detector = my_series.cleaner.detect.castable(target='float', thousands=' ', decimal=',')
-    >>> my_series.cleaner.clean('cast', my_detector)
+    >>> series = pd.Series(['100 000', '154,5', '9 000', '250,12'], dtype='object')
+    >>> detector = series.cleaner.detect.castable(target='float', thousands=' ', decimal=',')
+    >>> series.cleaner.clean('cast', detector)
     0    100000
     1    154.5
     2    9000
@@ -393,8 +394,8 @@ def cast(self, detector_obj, **kwargs):
 
     Casting into int
 
-    >>> my_detector = my_series.cleaner.detect.castable(target='int', thousands=' ', decimal=',')
-    >>> my_series.cleaner.clean('cast', my_detector)
+    >>> detector = series.cleaner.detect.castable(target='int', thousands=' ', decimal=',')
+    >>> series.cleaner.clean('cast', detector)
     0    100000
     1      <NA>
     2      9000
@@ -403,9 +404,9 @@ def cast(self, detector_obj, **kwargs):
 
     Casting into date
 
-    >>> my_series = pd.Series(['1.05', '154', '15/05/2022', 'Alice'], dtype='object')
-    >>> my_detector = my_series.cleaner.detect.castable(target='date')
-    >>> my_series.cleaner.clean('cast', my_detector, format="%d/%m/%Y")
+    >>> series = pd.Series(['1.05', '154', '15/05/2022', 'Alice'], dtype='object')
+    >>> detector = series.cleaner.detect.castable(target='date')
+    >>> series.cleaner.clean('cast', detector, format="%d/%m/%Y")
     0    NaT
     1    NaT
     2    2022-05-15
@@ -413,37 +414,37 @@ def cast(self, detector_obj, **kwargs):
     dtype: datetime64[ns]
     """
 
-    if detector_obj.name != 'castable':
+    if detector.name != 'castable':
         raise ValueError('This cleaning method works only with the castable detector')
 
-    series = detector_obj.obj
-    series = series.where(detector_obj.not_error(), np.nan)
+    series = detector.obj
+    series = series.where(detector.not_error(), np.nan)
 
-    if detector_obj.target == "int":
-        series = detector_obj.check_separators(series)
+    if detector.target == "int":
+        series = detector.check_separators(series)
         series = pd.to_numeric(series, errors="coerce").astype('Int32')
 
-    if detector_obj.target == "float":
-        series = detector_obj.check_separators(series)
+    if detector.target == "float":
+        series = detector.check_separators(series)
         series = pd.to_numeric(series, errors="coerce")
 
-    if detector_obj.target == "date":
+    if detector.target == "date":
         series = pd.to_datetime(series, errors="coerce", **kwargs)
 
-    if detector_obj.target == "boolean":
-        series = series.map(detector_obj.bool_values)
+    if detector.target == "boolean":
+        series = series.map(detector.bool_values)
 
     return series
 
 
-def strip(self, detector_obj):
+def strip(self, detector):
     """
     Clean by removing extraspaces detected by the 'spaces' detector. This method only works with
     this detector.
 
     Parameters
     ----------
-    detector_obj: a Detector object,
+    detector: a Detector object,
         The detector obj that will identify entries to clean
 
     Returns
@@ -452,9 +453,9 @@ def strip(self, detector_obj):
 
     Examples
     --------
-    >>> my_series = pd.Series(['Paris','Paris ',' Lille', ' Lille ', 'Troyes'])
-    >>> my_detector = my_series.cleaner.detect.spaces(side='right')
-    >>> my_series.cleaner.clean.strip(my_detector)
+    >>> series = pd.Series(['Paris','Paris ',' Lille', ' Lille ', 'Troyes'])
+    >>> detector = series.cleaner.detect.spaces(side='trailing')
+    >>> series.cleaner.clean.strip(detector)
     0    Paris
     1    Paris
     2     Lille
@@ -462,8 +463,8 @@ def strip(self, detector_obj):
     4    Troyes
     dtype: object
 
-    >>> my_detector = my_series.cleaner.detect.spaces(side='both')
-    >>> my_series.cleaner.clean.strip(my_detector)
+    >>> detector = series.cleaner.detect.spaces(side='both')
+    >>> series.cleaner.clean.strip(detector)
     0    Paris
     1    Paris
     2    Lille
@@ -472,16 +473,16 @@ def strip(self, detector_obj):
     dtype: object
     """
 
-    if detector_obj.name != 'spaces':
+    if detector.name != 'spaces':
         raise ValueError('This cleaning method works only with the spaces detector')
 
-    series = detector_obj.obj
+    series = detector.obj
 
-    if detector_obj.side == 'left':
+    if detector.side == 'leading':
         series = series.str.lstrip()
-    elif detector_obj.side == 'right':
+    elif detector.side == 'trailing':
         series = series.str.rstrip()
-    elif detector_obj.side == 'both':
+    elif detector.side == 'both':
         series = series.str.strip()
 
     return series
diff --git a/pdcleaner/detection/__init__.py b/src/pdcleaner/detection/__init__.py
similarity index 100%
rename from pdcleaner/detection/__init__.py
rename to src/pdcleaner/detection/__init__.py
diff --git a/pdcleaner/detection/_base.py b/src/pdcleaner/detection/_base.py
similarity index 99%
rename from pdcleaner/detection/_base.py
rename to src/pdcleaner/detection/_base.py
index 0406aff..d7ae4d7 100644
--- a/pdcleaner/detection/_base.py
+++ b/src/pdcleaner/detection/_base.py
@@ -25,12 +25,10 @@ def obj(self):
         """The object (Series or DataFrame) containing the data to which the detection is applied"""
         return self._obj
 
-    @property
     def detected(self):
         """Series or DataFrame containing only the detected errors"""
         return self._obj.loc[self.index]
 
-    @property
     def valid(self):
         """Series or DataFrame containing only the valid values"""
         return self._obj[self.not_error()]
diff --git a/pdcleaner/detection/basic.py b/src/pdcleaner/detection/basic.py
similarity index 73%
rename from pdcleaner/detection/basic.py
rename to src/pdcleaner/detection/basic.py
index eaa6d70..34f8417 100644
--- a/pdcleaner/detection/basic.py
+++ b/src/pdcleaner/detection/basic.py
@@ -3,6 +3,7 @@
 """
 #pylint: disable=too-many-arguments
 
+from cmath import isfinite
 import warnings
 import numbers
 
@@ -24,13 +25,13 @@ def _raise_if_invalid_sided_or_inclusive_args(inclusive="both", sided="both"):
                     f"sided must be in {legal_values}")
 
 
-class BoundedSeriesDetector(_NumericalSeriesDetector):
-    r"""'bounded' : Detect values outside of given bounds.
+class bounded(_NumericalSeriesDetector):
+    r"""Detect values outside of given bounds.
 
     Intended to be used by the detect method with the keyword 'bounded'
 
-    >>> series.detect.bounded(...)
-    >>> series.detect('bounded',...)
+    >>> series.cleaner.detect.bounded(...)
+    >>> series.cleaner.detect('bounded',...)
 
 
     This detection method flags values as potential errors wherever the
@@ -60,9 +61,9 @@ class BoundedSeriesDetector(_NumericalSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series([1, 2, 100, 3])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=2, upper=4)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([1, 2, 100, 3])
+    >>> detector = series.cleaner.detect.bounded(lower=2, upper=4)
+    >>> print(detector.is_error())
     0     True
     1    False
     2     True
@@ -71,9 +72,9 @@ class BoundedSeriesDetector(_NumericalSeriesDetector):
 
     With only one bound specified
 
-    >>> my_series = pd.Series([1, 2, 100, 3])
-    >>> my_detector = my_series.cleaner.detect.bounded(upper=4)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([1, 2, 100, 3])
+    >>> detector = series.cleaner.detect.bounded(upper=4)
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -82,9 +83,9 @@ class BoundedSeriesDetector(_NumericalSeriesDetector):
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series([1, np.nan, 100, 3])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=2, upper=4)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([1, np.nan, 100, 3])
+    >>> detector = series.cleaner.detect.bounded(lower=2, upper=4)
+    >>> print(detector.is_error())
     0     True
     1    False
     2     True
@@ -101,7 +102,7 @@ def _raise_if_non_numeric_bounds(self):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  lower=np.NINF,
                  upper=np.inf,
                  inclusive="both"
@@ -112,17 +113,17 @@ def __init__(self,
         raise_if_not_in(inclusive, legal_values,
                         f"inclusive must be in {legal_values}")
 
-        if not detector_obj:
+        if not detector:
             self._lower = lower
             self._upper = upper
             self._inclusive = inclusive
             self._sided = "both"
         else:
 
-            self._lower = detector_obj.lower
-            self._upper = detector_obj.upper
-            self._inclusive = detector_obj.inclusive
-            self._sided = detector_obj.sided
+            self._lower = detector.lower
+            self._upper = detector.upper
+            self._inclusive = detector.inclusive
+            self._sided = detector.sided
 
         self._raise_if_non_numeric_bounds()
 
@@ -179,16 +180,17 @@ def _reported(self):
         return ['lower', 'upper', 'inclusive', 'sided']
 
 
-class CheckLenSeriesDetector(_SeriesDetector):
-    r"""'length' : Detect elements with length outside of given bounds.
+class length(_SeriesDetector):
+    r"""Detect elements with length outside of given bounds.
 
     Intended to be used by the detect method with the keyword 'length'
 
-    >>> series.detect.length(...)
-    >>> series.detect('length',...)
+    >>> series.cleaner.detect.length(...)
+    >>> series.cleaner.detect('length',...)
 
     This detection method flags elements as potential errors wherever the corresponding length of
-    Series element is outside the range between lower and upper or fixed value.
+    Series element is outside the range between lower and upper. Alternatively, can be used
+    with a fixed lenght value.
 
     Note
     ----
@@ -196,24 +198,24 @@ class CheckLenSeriesDetector(_SeriesDetector):
 
     Parameters
     ----------
-    mode: string , Default = 'fixed_value'
-        - 'bound' : the length of the elements is bounded by a minimum and maximum value
-        - 'fixed_value' : the length of the elements is equal to a fixed value.
-
     lower : float or None (Default)
-        Lower bound in case of 'min' or 'bound' mode
+        Lower bound
 
     upper : float or None (Default)
-        Upper bound in case of 'max' or 'bound' mode
+        Upper bound
 
-    fix_value : float or None ( Default)
+    value : float or None ( Default)
         Specific length of the element
 
     Raises
     ------
+    TypeError
+        when at least one of lower, upper or value is not a number
+    ValueError
+        when lower or upper is specified at the same time as value or 
+        when none of the three is given
     ValueError
-        when lower or upper is not specified in 'bound' mode and fix_value is not specified in
-        'fixed_value' mode
+        when lower >= upper
 
 
     Examples
@@ -221,9 +223,9 @@ class CheckLenSeriesDetector(_SeriesDetector):
     >>> import pandas as pd
     >>> import pdcleaner
 
-    >>> my_series = pd.Series(['75013','78000' , '931204', '952684'], dtype='string')
-    >>> my_detector = my_series.cleaner.detect.length(mode='fixed_value', fix_value=5)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['75013','78000' , '931204', '952684'], dtype='string')
+    >>> detector = series.cleaner.detect.length(value=5)
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -232,9 +234,9 @@ class CheckLenSeriesDetector(_SeriesDetector):
 
     with two bounds specified
 
-    >>> my_series = pd.Series(['1','001' , '01460', '0011448'], dtype='string')
-    >>> my_detector = my_series.cleaner.detect.length(mode='bound', lower=2, upper=6)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['1','001' , '01460', '0011448'], dtype='string')
+    >>> detector = series.cleaner.detect.length(lower=2, upper=6)
+    >>> print(detector.is_error())
     0    True
     1    False
     2    False
@@ -243,9 +245,9 @@ class CheckLenSeriesDetector(_SeriesDetector):
 
     Can be used with integers
 
-    >>> my_series = pd.Series([1, 1234567 , 1460, np.nan])
-    >>> my_detector = my_series.cleaner.detect.length(mode='bound', upper=6)
-    >>> my_detector.is_error()
+    >>> series = pd.Series([1, 1234567 , 1460, np.nan])
+    >>> detector = series.cleaner.detect.length(upper=6)
+    >>> detector.is_error()
     0    False
     1     True
     2    False
@@ -254,9 +256,9 @@ class CheckLenSeriesDetector(_SeriesDetector):
 
     and with floats
 
-    >>> my_series = pd.Series([1.007, 1.234567 , 1.460], dtype='float64')
-    >>> my_detector = my_series.cleaner.detect.length(mode='bound', upper=6)
-    >>> my_detector.is_error()
+    >>> series = pd.Series([1.007, 1.234567 , 1.460], dtype='float64')
+    >>> detector = series.cleaner.detect.length(upper=6)
+    >>> detector.is_error()
     0    False
     1     True
     2    False
@@ -264,9 +266,9 @@ class CheckLenSeriesDetector(_SeriesDetector):
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['1','001' , '01460', np.nan], dtype='string')
-    >>> my_detector = my_series.cleaner.detect.length(mode='bound', upper=6)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['1','001' , '01460', np.nan], dtype='string')
+    >>> detector = series.cleaner.detect.length(upper=6)
+    >>> print(detector.is_error())
     0     False
     1     False
     2     False
@@ -281,16 +283,15 @@ def _raise_if_non_numeric_bounds(self):
             raise TypeError("Lower bound must be a number")
         if not isinstance(self.upper, numbers.Number):
             raise TypeError("Upper bound must be a number")
-        if not isinstance(self.fix_value, numbers.Number):
-            raise TypeError("Fix value must be a number")
+        if not isinstance(self.value, numbers.Number):
+            raise TypeError("Argument value must be a number")
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
-                 mode="fixed_value",
+                 detector=None,
                  lower=np.NINF,
                  upper=np.inf,
-                 fix_value=np.inf,
+                 value=np.inf,
                  inclusive="both"
                  ):
         super().__init__(obj)
@@ -299,36 +300,32 @@ def __init__(self,
         raise_if_not_in(inclusive, legal_values,
                         f"inclusive must be in {legal_values}")
 
-        legal_values = ["fixed_value", "bound"]
-        raise_if_not_in(mode, legal_values,
-                        f"mode must be in {legal_values}")
-
-        if not detector_obj:
-            self._mode = mode
+        if not detector:
             self._lower = lower
             self._upper = upper
-            self._fix_value = fix_value
+            self._value = value
             self._inclusive = inclusive
         else:
-            self._mode = detector_obj.mode
-            self._lower = detector_obj.lower
-            self._upper = detector_obj.upper
-            self._fix_value = detector_obj.fix_value
-            self._inclusive = detector_obj.inclusive
+            self._lower = detector.lower
+            self._upper = detector.upper
+            self._value = detector.value
+            self._inclusive = detector.inclusive
 
         self._raise_if_non_numeric_bounds()
 
-        if self._mode == 'fixed_value':
-            if np.isinf(self._fix_value):
-                raise ValueError("fix_value must be specified in fixed_value mode")
-            if np.isfinite(self._lower) or np.isfinite(self._upper):
-                warnings.warn("Upper or Lower bound is not necessary in fixed_value mode")
+        if(not np.isfinite(self._value)
+           and not np.isfinite(self._lower)
+           and not np.isfinite(self._upper)
+           ):
+            raise ValueError("At least one argument must be provided")
 
-        if self._mode == 'bound':
-            if np.isinf(self._lower) & np.isinf(self._upper):
-                raise ValueError("lower or upper must be specified in bound mode")
-            if np.isfinite(self._fix_value):
-                warnings.warn("Fix_value is not necessary in bound mode")
+        if np.isfinite(self._value) and (np.isfinite(self._upper) or np.isfinite(self._lower)):
+            raise ValueError("Incompatible arguments: value and upper or lower")
+
+        if np.isfinite(self._value):
+            self._mode = 'fixed_value'
+        else:
+            self._mode = 'bound'
 
         if self._lower >= self._upper:
             raise ValueError("Lower bound is >= upper bound")
@@ -349,9 +346,9 @@ def upper(self) -> float:
         return self._upper
 
     @property
-    def fix_value(self) -> float:
+    def value(self) -> float:
         """Fix length value"""
-        return self._fix_value
+        return self._value
 
     @property
     def inclusive(self) -> str:
@@ -362,7 +359,7 @@ def inclusive(self) -> str:
     def index(self) -> pd.Index:
         """Indices of the rows detected as errors"""
         if self.mode == "fixed_value":
-            mask = ~(self._obj.apply(lambda x: len(str(x)) == self.fix_value))
+            mask = ~(self._obj.apply(lambda x: len(str(x)) == self.value))
         elif self.mode == "bound":
             if self.inclusive == "both":
                 mask = ~(self._obj.apply(lambda x: self.lower <= len(str(x)) <= self.upper))
@@ -380,16 +377,16 @@ def index(self) -> pd.Index:
     @property
     def _reported(self):
         """Properties displayed by the report() method"""
-        return ['mode', 'lower', 'upper', 'fix_value', 'inclusive']
+        return ['mode', 'lower', 'upper', 'value', 'inclusive']
 
 
-class MissingValuesDetector(_Detector):
-    r"""'missing' : Detect elements containing missing values
+class missing(_Detector):
+    r"""Detect elements containing missing values
 
     Intended to be used by the detect method with the keyword 'missing'
 
-    >>> df.detect.missing(...)
-    >>> df.detect('missing',...)
+    >>> df.cleaner.detect.missing(...)
+    >>> df.cleaner.detect('missing',...)
 
     Parameters
     ----------
@@ -410,8 +407,8 @@ class MissingValuesDetector(_Detector):
 
     >>> df = pd.DataFrame({'col1' : ['Alice', 'Bob', 'Charles'],
                            'col2' : [15, np.nan, 11] })
-    >>> my_detector = df.cleaner.detect.missing(how='any')
-    >>> print(my_detector.is_error())
+    >>> detector = df.cleaner.detect.missing(how='any')
+    >>> print(detector.is_error())
     0    False
     1    True
     2    False
@@ -421,8 +418,8 @@ class MissingValuesDetector(_Detector):
 
     >>> df = pd.DataFrame({'col1' : ['Alice', np.nan, 'Charles'],
                            'col2' : [np.nan, np.nan, np.nan] })
-    >>> my_detector = df.cleaner.detect.missing(how='all')
-    >>> print(my_detector.is_error())
+    >>> detector = df.cleaner.detect.missing(how='all')
+    >>> print(detector.is_error())
     0    False
     1    True
     2    False
@@ -430,9 +427,9 @@ class MissingValuesDetector(_Detector):
 
     Can be used with series. 'how' parameter is not necessary
 
-    >>> my_series = pd.Series(['Alice', 'Bob', np.nan, 'Charles'])
-    >>> my_detector = my_series.cleaner.detect('missing')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['Alice', 'Bob', np.nan, 'Charles'])
+    >>> detector = series.cleaner.detect('missing')
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -444,7 +441,7 @@ class MissingValuesDetector(_Detector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  how='any',
                  ):
         super().__init__(obj)
@@ -452,10 +449,10 @@ def __init__(self,
         legal_values = ["any", "all"]
         raise_if_not_in(how, legal_values, f"how parameter must be {' or '.join(legal_values)}")
 
-        if not detector_obj:
+        if not detector:
             self._how = how
         else:
-            self._how = detector_obj.how
+            self._how = detector.how
 
         self._type = type(obj)
 
@@ -488,14 +485,14 @@ def _reported(self):
         return ['how']
 
 
-class DuplicatedDetector(_Detector):
-    r""" 'duplicated': Detect duplicated elements
+class duplicated(_Detector):
+    r"""Detect duplicated elements
 
     Intended to be used by the detect method with the keyword 'duplicated'. Can be used with
     series or dataframe
 
-    >>> df.detect.duplicated(...)
-    >>> df.detect('duplicated',...)
+    >>> df.cleaner.detect.duplicated(...)
+    >>> df.cleaner.detect('duplicated',...)
 
     Parameters
     ----------
@@ -521,8 +518,8 @@ class DuplicatedDetector(_Detector):
 
     >>> df = pd.DataFrame({'col1' : ['Alice', 'Bob', 'Alice', 'Bob', 'Alice'],
                            'col2' : [15, 13, 15, 10, 13] })
-    >>> my_detector = df.cleaner.detect.duplicated(subset=['col1', 'col2'], keep='first')
-    >>> print(my_detector.is_error())
+    >>> detector = df.cleaner.detect.duplicated(subset=['col1', 'col2'], keep='first')
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -530,8 +527,8 @@ class DuplicatedDetector(_Detector):
     4    False
     dtype: bool
 
-    >>> my_detector = df.cleaner.detect.duplicated(subset=['col1'], keep='last')
-    >>> print(my_detector.is_error())
+    >>> detector = df.cleaner.detect.duplicated(subset=['col1'], keep='last')
+    >>> print(detector.is_error())
     0     True
     1     True
     2     True
@@ -544,18 +541,18 @@ class DuplicatedDetector(_Detector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  subset=None,
                  keep='first'
                  ):
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             self._subset = subset
             self._keep = keep
         else:
-            self._subset = detector_obj.subset
-            self._keep = detector_obj.keep
+            self._subset = detector.subset
+            self._keep = detector.keep
 
     @property
     def subset(self) -> list:
@@ -583,13 +580,13 @@ def _reported(self):
         return ['subset', 'keep']
 
 
-class CustomDetector(_Detector):
-    r"""'custom' : Detect errors using an user-defined callable
+class custom(_Detector):
+    r"""Detect errors using an user-defined callable
 
     Intended to be used by the detect method with the keyword 'custom'
 
-    >>> df.detect.custom(...)
-    >>> df.detect('custom',...)
+    >>> df.cleaner.detect.custom(...)
+    >>> df.cleaner.detect('custom',...)
 
     Parameters
     ----------
@@ -649,16 +646,16 @@ class CustomDetector(_Detector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  error_func=None,
                  ):
 
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             self._error_func = error_func
         else:
-            self._error_func = detector_obj.error_func
+            self._error_func = detector.error_func
 
         if self.error_func is None:
             raise ValueError('error_func must be defined')
@@ -699,13 +696,13 @@ def _reported(self):
         return []
 
 
-class QuantilesSeriesDetector(BoundedSeriesDetector):
-    r"""'quantiles': Detect errors values in a Series using quantiles.
+class quantiles(bounded):
+    r"""Detect errors values in a Series using quantiles.
 
     Intended to be used by the detect method with the keyword 'quantiles'
 
-    >>> series.detect.quantiles(...)
-    >>> series.detect('quantiles',...)
+    >>> series.cleaner.detect.quantiles(...)
+    >>> series.cleaner.detect('quantiles',...)
 
     This detection method flags values as errors wherever the corresponding
     Series element is outside the range between the values at given quantiles
@@ -743,7 +740,7 @@ class QuantilesSeriesDetector(BoundedSeriesDetector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  lowerq=0,
                  upperq=1,
                  inclusive="both"
@@ -757,7 +754,7 @@ def __init__(self,
 
         _raise_if_invalid_sided_or_inclusive_args(inclusive=inclusive)
 
-        if not detector_obj:
+        if not detector:
             self._lowerq = lowerq
             self._upperq = upperq
             self._lower = self._obj.quantile(self.lowerq)
@@ -765,12 +762,12 @@ def __init__(self,
             self._inclusive = inclusive
             self._sided = "both"
         else:
-            self._lowerq = detector_obj.lowerq
-            self._upperq = detector_obj.upperq
-            self._lower = detector_obj.lower
-            self._upper = detector_obj.upper
-            self._inclusive = detector_obj.inclusive
-            self._sided = detector_obj._sided
+            self._lowerq = detector.lowerq
+            self._upperq = detector.upperq
+            self._lower = detector.lower
+            self._upper = detector.upper
+            self._inclusive = detector.inclusive
+            self._sided = detector._sided
 
         if (self._lowerq == 0) & (self._upperq == 1):
             warnings.warn("Neither lower or upper quantile specified")
diff --git a/pdcleaner/detection/by_category.py b/src/pdcleaner/detection/by_category.py
similarity index 96%
rename from pdcleaner/detection/by_category.py
rename to src/pdcleaner/detection/by_category.py
index df2cedb..bbb5668 100644
--- a/pdcleaner/detection/by_category.py
+++ b/src/pdcleaner/detection/by_category.py
@@ -40,7 +40,7 @@ class ByCategoryDataFrameDetector(_NumericalAndCategoricalDataFramesDetector):
             'col2' : ['I'] * 11 + ["II"] * 10
             })
     >>> detector = df.cleaner.detect('iqr')
-    >>> print(detector.detected)
+    >>> print(detector.detected())
         col1 col2
     10    5    1
     """
@@ -49,14 +49,14 @@ class ByCategoryDataFrameDetector(_NumericalAndCategoricalDataFramesDetector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  method=None,
                  method_kwargs=None
                  ):
 
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             self._method = method
             self._method_kwargs = method_kwargs
         else:
diff --git a/pdcleaner/detection/datetimes.py b/src/pdcleaner/detection/datetimes.py
similarity index 81%
rename from pdcleaner/detection/datetimes.py
rename to src/pdcleaner/detection/datetimes.py
index 092e79a..b55cad7 100644
--- a/pdcleaner/detection/datetimes.py
+++ b/src/pdcleaner/detection/datetimes.py
@@ -9,13 +9,13 @@
 from pdcleaner.utils.utils import raise_if_not_in
 
 
-class DateRangeDetector(_DateTypeSeriesDetector):
-    r""" 'date_range': Detect if date value is between a given range.
+class date_range(_DateTypeSeriesDetector):
+    r"""Detect if date value is between a given range.
 
     Intended to be used by the detect method with the keyword 'date_range'
 
-    >>> series.detect.date_range(...)
-    >>> series.detect('date_range',...)
+    >>> series.cleaner.detect.date_range(...)
+    >>> series.cleaner.detect('date_range',...)
 
     This detection method flags values as potential errors wherever the corresponding Series
     element is outside the date range.
@@ -37,10 +37,10 @@ class DateRangeDetector(_DateTypeSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['2022-10-01', '2021-06-11', '2019-04-03',' 2020-09-25'])
-    >>> my_series= pd.to_datetime(my_series)
-    >>> my_detector = my_series.cleaner.detect.date_range(lower='2020-06-15', upper='2022-08-05')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['2022-10-01', '2021-06-11', '2019-04-03',' 2020-09-25'])
+    >>> series= pd.to_datetime(series)
+    >>> detector = series.cleaner.detect.date_range(lower='2020-06-15', upper='2022-08-05')
+    >>> print(detector.is_error())
     0     True
     1    False
     2     True
@@ -49,8 +49,8 @@ class DateRangeDetector(_DateTypeSeriesDetector):
 
     With only one bound specified
 
-    >>> my_detector = my_series.cleaner.detect.date_range(upper='2022-08-05')
-    >>> print(my_detector.is_error())
+    >>> detector = series.cleaner.detect.date_range(upper='2022-08-05')
+    >>> print(detector.is_error())
     0     True
     1    False
     2    False
@@ -70,7 +70,7 @@ def is_date(date_str):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  lower=pd.Timestamp.min,
                  upper=pd.Timestamp.max,
                  inclusive="both"
@@ -82,14 +82,14 @@ def __init__(self,
         raise_if_not_in(inclusive, legal_values,
                         f"inclusive must be in {legal_values}")
 
-        if not detector_obj:
+        if not detector:
             self._lower = lower
             self._upper = upper
             self._inclusive = inclusive
         else:
-            self._lower = detector_obj.lower
-            self._upper = detector_obj.upper
-            self._inclusive = detector_obj.inclusive
+            self._lower = detector.lower
+            self._upper = detector.upper
+            self._inclusive = detector.inclusive
 
         if self._lower != pd.Timestamp.min:
             if not self.is_date(self._lower):
diff --git a/pdcleaner/detection/gaussian.py b/src/pdcleaner/detection/gaussian.py
similarity index 94%
rename from pdcleaner/detection/gaussian.py
rename to src/pdcleaner/detection/gaussian.py
index a372ee2..3c59fd6 100644
--- a/pdcleaner/detection/gaussian.py
+++ b/src/pdcleaner/detection/gaussian.py
@@ -10,7 +10,7 @@
 
 from scipy import stats
 
-from pdcleaner.detection.basic import BoundedSeriesDetector
+from pdcleaner.detection.basic import bounded as _bounded
 from pdcleaner.detection.basic import _raise_if_invalid_sided_or_inclusive_args
 from pdcleaner.utils.utils import raise_if_not_in
 
@@ -41,14 +41,14 @@ def _inverse_yeojohnson(xt: float, lambda_: float = 1) -> float:
     return X
 
 
-class _GaussianSeriesDetector(BoundedSeriesDetector):
+class _GaussianSeriesDetector(_bounded):
     r"Base class for outliers detection based on a normal/gaussian distribution assumption."
 
     name = 'gaussian'
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  threshold=1.5,
                  inclusive="both",
                  sided="both",
@@ -79,7 +79,7 @@ def __init__(self,
         if pvalue <= 0:
             raise ValueError('pvalue must be positive')
 
-        if not detector_obj:
+        if not detector:
             self._threshold = threshold
             self._inclusive = inclusive
             self._sided = sided
@@ -92,13 +92,13 @@ def __init__(self,
             else:
                 self._isnormal = False
         else:
-            self._threshold = detector_obj.threshold
-            self._inclusive = detector_obj.inclusive
-            self._sided = detector_obj._sided
-            self._normaltest = detector_obj.normaltest
-            self._pvalue = detector_obj.pvalue
-            self._transform = detector_obj.transform
-            self._isnormal = detector_obj.isnormal
+            self._threshold = detector.threshold
+            self._inclusive = detector.inclusive
+            self._sided = detector._sided
+            self._normaltest = detector.normaltest
+            self._pvalue = detector.pvalue
+            self._transform = detector.transform
+            self._isnormal = detector.isnormal
 
         if not isinstance(self._threshold, numbers.Number):
             print(self._threshold)
@@ -181,13 +181,13 @@ def _report_comments(self) -> str:
         return self._msg
 
 
-class IqrSeriesDetector(_GaussianSeriesDetector):
-    r"""'iqr': Detect outliers as potential errors in a Series using the IQR method.
+class iqr(_GaussianSeriesDetector):
+    r"""Detect outliers as potential errors in a Series using the IQR method.
 
     Intended to be used by the detect method with the keyword 'iqr'
 
-    >>> series.detect.iqr(...)
-    >>> series.detect('iqr',...)
+    >>> series.cleaner.detect.iqr(...)
+    >>> series.cleaner.detect('iqr',...)
 
     This detection method flag values as errors wherever the corresponding Series element
     is outside the range defined by:
@@ -276,9 +276,9 @@ class IqrSeriesDetector(_GaussianSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series([1,2,100,3])
-    >>> my_detector = my_series.cleaner.detect.iqr()
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([1,2,100,3])
+    >>> detector = series.cleaner.detect.iqr()
+    >>> print(detector.is_error())
         0    False
         1    False
         2     True
@@ -334,7 +334,7 @@ class IqrSeriesDetector(_GaussianSeriesDetector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  threshold=1.5,
                  inclusive="both",
                  sided="both",
@@ -344,7 +344,7 @@ def __init__(self,
                  ):
 
         super().__init__(obj,
-                         detector_obj=detector_obj,
+                         detector=detector,
                          threshold=threshold,
                          inclusive=inclusive,
                          sided=sided,
@@ -353,7 +353,7 @@ def __init__(self,
                          transform=transform,
                          )
 
-        if not detector_obj:
+        if not detector:
             if transform is None or self.isnormal:
                 self._q25 = self._obj.quantile(.25)
                 self._q75 = self._obj.quantile(.75)
@@ -361,8 +361,8 @@ def __init__(self,
                 self._q25 = self._transformed.quantile(.25)
                 self._q75 = self._transformed.quantile(.75)
         else:
-            self._q25 = detector_obj.q25
-            self._q75 = detector_obj.q75
+            self._q25 = detector.q25
+            self._q75 = detector.q75
 
         self._iqr = self.q75 - self.q25
 
@@ -403,13 +403,13 @@ def _add_report(self):
         return title, params
 
 
-class ZScoreSeriesDetector(_GaussianSeriesDetector):
-    r"""'zscore': Detect outliers as potential errors in a Series using the Z-score method.
+class zscore(_GaussianSeriesDetector):
+    r"""Detect outliers as potential errors in a Series using the Z-score method.
 
     Intended to be used by the detect method with the keyword 'zscore'
 
-    >>> series.detect.zscore(...)
-    >>> series.detect('zscore',...)
+    >>> series.cleaner.detect.zscore(...)
+    >>> series.cleaner.detect('zscore',...)
 
     This detection method flag values as errors wherever the corresponding
     Series element has a Z-score above a given threshold.
@@ -561,7 +561,7 @@ class ZScoreSeriesDetector(_GaussianSeriesDetector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  threshold=1.96,
                  inclusive="both",
                  sided="both",
@@ -571,7 +571,7 @@ def __init__(self,
                  ):
 
         super().__init__(obj,
-                         detector_obj=detector_obj,
+                         detector=detector,
                          threshold=threshold,
                          inclusive=inclusive,
                          sided=sided,
@@ -580,7 +580,7 @@ def __init__(self,
                          transform=transform,
                          )
 
-        if not detector_obj:
+        if not detector:
             if self.transform is None or self.isnormal:
                 self._mean = self._obj.mean()
                 self._std = self._obj.std()
@@ -588,8 +588,8 @@ def __init__(self,
                 self._mean = self._transformed.mean()
                 self._std = self._transformed.std()
         else:
-            self._mean = detector_obj.mean
-            self._std = detector_obj.std
+            self._mean = detector.mean
+            self._std = detector.std
 
         self._lower = self.mean - self.threshold * self.std
         self._upper = self.mean + self.threshold * self.std
@@ -624,13 +624,13 @@ def _add_report(self):
         return title, params
 
 
-class ModZScoreSeriesDetector(_GaussianSeriesDetector):
-    r"""'modzscore': Detect outliers as potential errors in a Series using the modified Z-score.
+class modzscore(_GaussianSeriesDetector):
+    r"""Detect outliers as potential errors in a Series using the modified Z-score.
 
     Intended to be used by the detect method with the keyword 'modzscore'
 
-    >>> series.detect.modzscore(...)
-    >>> series.detect('modzscore',...)
+    >>> series.cleaner.detect.modzscore(...)
+    >>> series.cleaner.detect('modzscore',...)
 
     This detection method flag values as errors wherever the corresponding
     Series element has a modified Z-score above a given threshold.
@@ -781,7 +781,7 @@ class ModZScoreSeriesDetector(_GaussianSeriesDetector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  threshold=3.5,
                  inclusive="both",
                  sided="both",
@@ -791,7 +791,7 @@ def __init__(self,
                  ):
 
         super().__init__(obj,
-                         detector_obj=detector_obj,
+                         detector=detector,
                          threshold=threshold,
                          inclusive=inclusive,
                          sided=sided,
@@ -800,7 +800,7 @@ def __init__(self,
                          transform=transform,
                          )
 
-        if not detector_obj:
+        if not detector:
             if self.transform is None or self.isnormal:
                 self._median = self._obj.median()
                 self._mad = ((self._obj - self._obj.median()).abs()).median()
@@ -808,8 +808,8 @@ def __init__(self,
                 self._median = self._transformed.median()
                 self._mad = ((self._transformed - self._transformed.median()).abs()).median()
         else:
-            self._median = detector_obj.median
-            self._mad = detector_obj.mad
+            self._median = detector.median
+            self._mad = detector.mad
 
         self._lower = self.median - self.threshold / 0.6475 * self.mad
         self._upper = self.median + self.threshold / .6475 * self.mad
diff --git a/pdcleaner/detection/multivariate.py b/src/pdcleaner/detection/multivariate.py
similarity index 89%
rename from pdcleaner/detection/multivariate.py
rename to src/pdcleaner/detection/multivariate.py
index 1dee29f..9f32a0d 100644
--- a/pdcleaner/detection/multivariate.py
+++ b/src/pdcleaner/detection/multivariate.py
@@ -6,13 +6,13 @@
 
 import pandas as pd
 
-from sklearn.cluster import DBSCAN
+from sklearn.cluster import DBSCAN as _DBSCAN
 
 
 from pdcleaner.detection._base import _QuantiDataFramesDetector
 
 
-class NDOutliersDataFramesDetector(_QuantiDataFramesDetector):
+class outliers(_QuantiDataFramesDetector):
     r"""Detects outliers in a  numeric DataFrame using a clustering DBScan algorithm
 
     This detection methods flags outliers in N-dimensional numerical datasets.
@@ -59,8 +59,8 @@ class NDOutliersDataFramesDetector(_QuantiDataFramesDetector):
     >>> df = pd.DataFrame({'x': [1, 1.1, 4],
                            'y': [1.1, 1, 4],
                            'z': [1, 1.1, 4]})
-    >>> detector = df.cleaner.detect.ndoutliers()
-    >>> print(my_detector.is_error())
+    >>> detector = df.cleaner.detect.outliers()
+    >>> print(detector.is_error())
         0    False
         1    False
         2     True
@@ -72,20 +72,20 @@ class NDOutliersDataFramesDetector(_QuantiDataFramesDetector):
     >>> df = pd.DataFrame({'x': [1, 1.1, 4, np.nan],
                            'y': [1.1, 1, 4, 5],
                            'z': [1, 1.1, 4, 5]})
-    >>> detector = df.cleaner.detect.ndoutliers()
-    >>> print(my_detector.is_error())
+    >>> detector = df.cleaner.detect.outliers()
+    >>> print(detector.is_error())
         0    False
         1    False
         2     True
         3    False
         dtype: bool
     """
-    name = 'ndoutliers'
+    name = 'outliers'
 
-    def __init__(self, obj, detector_obj=None, eps=None, min_samples=2):
+    def __init__(self, obj, detector=None, eps=None, min_samples=2):
         super().__init__(obj)
 
-        if detector_obj:
+        if detector:
             raise ValueError("This detection method can not be used "
                              "with an existing detector as an input.")
 
@@ -95,7 +95,7 @@ def __init__(self, obj, detector_obj=None, eps=None, min_samples=2):
         if not isinstance(min_samples, int):
             raise TypeError("min_samples must be an integer")
 
-        if not detector_obj:
+        if not detector:
             if eps is None:
                 self._eps = ((self._obj - self._obj.mean())
                              / self._obj.std()).std().max()
@@ -124,7 +124,7 @@ def index(self) -> pd.Index:
         df_norm.dropna(inplace=True)
 
         try:
-            mask = (DBSCAN(eps=self._eps,
+            mask = (_DBSCAN(eps=self._eps,
                            min_samples=self._min_samples
                            )
                     .fit(df_norm)
diff --git a/pdcleaner/detection/strings.py b/src/pdcleaner/detection/strings.py
similarity index 70%
rename from pdcleaner/detection/strings.py
rename to src/pdcleaner/detection/strings.py
index 913991c..21198f1 100644
--- a/pdcleaner/detection/strings.py
+++ b/src/pdcleaner/detection/strings.py
@@ -10,8 +10,8 @@
 from pdcleaner.utils.utils import raise_if_not_in
 
 
-class PatternSeriesDetector(_ObjectTypeSeriesDetector):
-    r"""'pattern': Detect strings that do not match a given pattern.
+class pattern(_ObjectTypeSeriesDetector):
+    r"""Detect strings that do not match a given pattern.
 
     This detection method flags values as potential errors wherever the
     corresponding Series element does not match a given character sequence
@@ -56,18 +56,18 @@ class PatternSeriesDetector(_ObjectTypeSeriesDetector):
 
     Strings are to be not lower cases letters only
 
-    >>> my_series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
-    >>> my_detector = my_series.cleaner.detect.pattern(pattern=r"[a-z]*", mode='fullmatch')
-    >>> print(my_detector.detected)
+    >>> series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
+    >>> detector = series.cleaner.detect.pattern(pattern=r"[a-z]*", mode='fullmatch')
+    >>> print(detector.detected())
     0    Cat
     4     14
     dtype: object
 
     Strings must contain a "d"
 
-    >>> my_series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
-    >>> my_detector = my_series.cleaner.detect.values(pattern=r"d", mode='contains')
-    >>> print(my_detector.detected)
+    >>> series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
+    >>> detector = series.cleaner.detect.values(pattern=r"d", mode='contains')
+    >>> print(detector.detected())
     0    Cat
     1    cat
     4     14
@@ -76,9 +76,9 @@ class PatternSeriesDetector(_ObjectTypeSeriesDetector):
 
     Strings should be 'cat' or 'dog' whenever the case
 
-    >>> my_series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
-    >>> my_detector = my_series.cleaner.detect.values(pattern=r"cat|dog", mode='match', case=False)
-    >>> print(my_detector.detected)
+    >>> series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
+    >>> detector = series.cleaner.detect.values(pattern=r"cat|dog", mode='match', case=False)
+    >>> print(detector.detected())
     3    bird
     4      14
     6
@@ -87,12 +87,12 @@ class PatternSeriesDetector(_ObjectTypeSeriesDetector):
     One can also use a compiled regex. In this case, the arguments `case` and `flag`
     are ignored
 
-    >>> my_series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
+    >>> series = pd.Series(['Cat','cat','dog','bird','14',np.nan,""])
     >>> import re
     >>> regex = re.compile(r"[a-z]*")
-    >>> my_detector = my_series.cleaner.detect.pattern(pattern=regex, mode='fullmatch', case=True)
+    >>> detector = series.cleaner.detect.pattern(pattern=regex, mode='fullmatch', case=True)
     ... UserWarning: case and flag are ignored with a compiled regex
-    >>> print(my_detector.detected)
+    >>> print(detector.detected())
     0    Cat
     4     14
     dtype: object
@@ -101,7 +101,7 @@ class PatternSeriesDetector(_ObjectTypeSeriesDetector):
     name = 'pattern'
 
     def __init__(self, obj,
-                 detector_obj=None,
+                 detector=None,
                  pattern="",
                  mode="match",
                  case=True,
@@ -109,16 +109,16 @@ def __init__(self, obj,
                  ):
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             self._pattern = pattern
             self._mode = mode
             self._case = case
             self._flags = flags
         else:
-            self._pattern = detector_obj.pattern
-            self._mode = detector_obj.mode
-            self._case = detector_obj.case
-            self._flags = detector_obj.flags
+            self._pattern = detector.pattern
+            self._mode = detector.mode
+            self._case = detector.case
+            self._flags = detector.flags
 
         if self._pattern == "":
             raise ValueError("The pattern is empty")
@@ -183,8 +183,8 @@ def _reported(self):
         return ['pattern', 'mode', 'case', 'flags']
 
 
-class KeyCollisionSeriesDetector(_ObjectTypeSeriesDetector):
-    r"""'keycollision': Detect strings that might be alternative representations of the same thing.
+class alternatives(_ObjectTypeSeriesDetector):
+    r"""Detect strings that might be alternative representations of the same thing.
 
     This detection method is typically useful for people names or for brands.
     It works on a clustering approach by grouping strings that might be alternative
@@ -199,9 +199,14 @@ class KeyCollisionSeriesDetector(_ObjectTypeSeriesDetector):
     As for now, the only available method is the fingerprinting method, explained in [1].
     In the aforementioned example, all strings would have the same key: 'linus torvalds'
 
-    The detector flags values with a given key but not the most frequent formulation as errors.
+    Depending on the value of the keyword ``keep``, the detector flags as errors values:
+    
+    + that are noy not the most frequent formulation (if ``keep=='mode'``, by default)
 
-    A dictionary associating the keys and the most frequent associated values is produced.
+    + that are not similar to the first one encountered (``if keep=='first'``). This can prove
+      useful when new data with a slightly different formatting are added to a dataset.
+
+    A dictionary associating the keys and the valid associated values is produced.
     {'linus torvalds': 'Linus Torvalds', ...}
 
     Reference
@@ -212,11 +217,15 @@ class KeyCollisionSeriesDetector(_ObjectTypeSeriesDetector):
     ----------
     keys: str (Default = 'fingerprint')
         method for generating the keys. Only 'fingerprint' currently available
+    keep: str (Default = 'mode')
+        which alternative representation shoud be kept ? The most frequent (``mode``) or the ``first`` one?
 
     Raises
     ------
     ValueError
-        when keys is not 'fingerprint'
+        when ``keys`` is not 'fingerprint'
+    ValueError
+        if ``keep`` is neither ``mode`` nor ``first``
 
     Note
     ----
@@ -225,33 +234,33 @@ class KeyCollisionSeriesDetector(_ObjectTypeSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['Linus Torvalds','linus.torvalds','Torvalds, Linus',
+    >>> series = pd.Series(['Linus Torvalds','linus.torvalds','Torvalds, Linus',
                                'Linus Torvalds', 'Bill Gates', ])
-    >>> my_detector = my_series.cleaner.detect.keycollision()
-    >>> print(my_detector.is_error())
+    >>> detector = series.cleaner.detect.alternatives()
+    >>> print(detector.is_error())
     0    False
     1    True
     2    True
     3    False
     4    False
     dtype: bool
-    >>> print(my_detector.dict_keys)
+    >>> print(detector.dict_keys)
     {'linus torvalds': 'Linus Torvalds', 'bill gates': 'Bill Gates'}
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['Linus Torvalds','linus.torvalds','Torvalds, Linus', np.nan ])
-    >>> my_detector = my_series.cleaner.detect.keycollision()
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['Linus Torvalds','linus.torvalds','Torvalds, Linus', np.nan ])
+    >>> detector = series.cleaner.detect.alternatives()
+    >>> print(detector.is_error())
     0    False
     1    True
     2    False
     3    False
     dtype: bool
     """
-    name = 'keycollision'
+    name = 'alternatives'
 
-    def __init__(self, obj, detector_obj=None, keys='fingerprint'):
+    def __init__(self, obj, detector=None, keys='fingerprint', keep='mode'):
         super().__init__(obj)
 
         if not isinstance(keys, str):
@@ -260,12 +269,22 @@ def __init__(self, obj, detector_obj=None, keys='fingerprint'):
         if keys not in ['fingerprint']:
             raise ValueError('Not a valid method. Only fingerprint method is implemented')
 
-        if not detector_obj:
+        if keep not in ['mode', 'first']:
+            raise ValueError("keep should have the value 'mode' or 'first'")
+
+        if not detector:
+            self._keep = keep
             self._keys = keys
             self._dict_keys = self.dict_keys
         else:
-            self._keys = detector_obj.keys
-            self._dict_keys = detector_obj.dict_keys
+            self._keep = detector.keep
+            self._keys = detector.keys
+            self._dict_keys = detector.dict_keys
+
+    @property
+    def keep(self):
+        """Returns the value of the keyword keep"""
+        return self._keep
 
     @property
     def keys(self):
@@ -274,14 +293,18 @@ def keys(self):
 
     @property
     def dict_keys(self) -> dict:
-        """  A python dictionary associating the key with the most frequent formulation
-
+        """  A python dictionary associating the key with keep formulation
         can be used for replacements"""
 
         keys = self.calc_keys(method=self._keys)
 
         df = pd.DataFrame({'orig': self._obj.astype(str), 'keys': keys})
-        group = df.groupby('keys').agg(lambda s: s.value_counts().idxmax())
+
+
+        if self._keep == 'mode':
+            group = df.groupby('keys').agg(lambda s: s.value_counts().idxmax())
+        else: # self._keep = 'first'
+            group = df.groupby('keys').first()
 
         return pd.Series(group.orig.values, index=group.index).to_dict()
 
@@ -323,23 +346,23 @@ def index(self) -> pd.Index:
     @property
     def _reported(self):
         """Properties displayed by the report() method"""
-        return ['keys']
+        return ['keys', 'keep']
 
 
-class ExtraSpacesDetector(_ObjectTypeSeriesDetector):
-    r"""'spaces' : Detect elements whith extra spaces before and/or after the value.
+class spaces(_ObjectTypeSeriesDetector):
+    r"""Detect elements whith extra spaces before and/or after the value.
 
     Intended to be used by the detect method with the keyword 'spaces'
 
-    >>> series.detect.spaces(...)
-    >>> series.detect('spaces',...)
+    >>> series.cleaner.detect.spaces(...)
+    >>> series.cleaner.detect('spaces',...)
 
     This detection method flags elements as potential errors wherever they
     contain an extra space at begininng or at the end.
 
     Parameters
     ----------
-    side: {'left', 'right', 'both'} (Default = 'both')
+    side: {'leading', 'trailing', 'both'} (Default = 'both')
         The side where extraspaces will be detected
 
     Raises
@@ -353,9 +376,9 @@ class ExtraSpacesDetector(_ObjectTypeSeriesDetector):
 
     Examples
     --------
-    >>> my_series = pd.Series(['Paris','Paris ',' Lille', ' Lille ', 'Troyes'])
-    >>> my_detector = my_series.cleaner.detect.spaces(side='left')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['Paris','Paris ',' Lille', ' Lille ', 'Troyes'])
+    >>> detector = series.cleaner.detect.spaces(side='leading')
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -363,8 +386,8 @@ class ExtraSpacesDetector(_ObjectTypeSeriesDetector):
     4    False
     dtype: bool
 
-    >>> my_detector = my_series.cleaner.detect.spaces(side='right')
-    >>> print(my_detector.is_error())
+    >>> detector = series.cleaner.detect.spaces(side='trailing')
+    >>> print(detector.is_error())
     0    False
     1     True
     2    False
@@ -372,8 +395,8 @@ class ExtraSpacesDetector(_ObjectTypeSeriesDetector):
     4    False
     dtype: bool
 
-    >>> my_detector = my_series.cleaner.detect.spaces(side='both')
-    >>> print(my_detector.is_error())
+    >>> detector = series.cleaner.detect.spaces(side='both')
+    >>> print(detector.is_error())
     0    False
     1     True
     2     True
@@ -385,18 +408,18 @@ class ExtraSpacesDetector(_ObjectTypeSeriesDetector):
 
     def __init__(self,
                  obj,
-                 detector_obj=None,
+                 detector=None,
                  side='both'
                  ):
         super().__init__(obj)
 
-        legal_values = ["left", "right", "both"]
+        legal_values = ["leading", "trailing", "both"]
         raise_if_not_in(side, legal_values, f"Parameter side must be {' or '.join(legal_values)}")
 
-        if not detector_obj:
+        if not detector:
             self._side = side
         else:
-            self._side = detector_obj.side
+            self._side = detector.side
 
     @property
     def side(self) -> str:
@@ -406,9 +429,9 @@ def side(self) -> str:
     @property
     def index(self) -> pd.Index:
         """Indices of the rows detected as errors"""
-        if self.side == "left":
+        if self.side == "leading":
             mask = self._obj.apply(lambda x: x.startswith(" "))
-        elif self.side == "right":
+        elif self.side == "trailing":
             mask = self._obj.apply(lambda x: x.endswith(" "))
         elif self.side == "both":
             mask = self._obj.apply(lambda x: (x.startswith(" ") or x.endswith(" ")))
diff --git a/pdcleaner/detection/types.py b/src/pdcleaner/detection/types.py
similarity index 71%
rename from pdcleaner/detection/types.py
rename to src/pdcleaner/detection/types.py
index bd28b33..e46cad1 100644
--- a/pdcleaner/detection/types.py
+++ b/src/pdcleaner/detection/types.py
@@ -9,13 +9,13 @@
 from pdcleaner.utils.utils import raise_if_not_in
 
 
-class TypeErrorsSeriesDetector(_SeriesDetector):
-    r"""'types' : Detect elements with type errors.
+class types(_SeriesDetector):
+    r"""Detect elements with type errors.
 
     Intended to be used by the detect method with the keyword 'types'
 
-    >>> series.detect.types(...)
-    >>> series.detect('types',...)
+    >>> series.cleaner.detect.types(...)
+    >>> series.cleaner.detect('types',...)
 
     This detection method flags elements as potential errors wherever the
     corresponding python type is different than the one specified.
@@ -43,10 +43,10 @@ class TypeErrorsSeriesDetector(_SeriesDetector):
     >>> import pandas as pd
     >>> import pdcleaner
 
-    >>> my_series = pd.Series([1, 2, 100, 3], dtype='float64')
-    >>> my_series[1] = 'One'
-    >>> my_detector = my_series.cleaner.detect.dtype(ptype=float)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([1, 2, 100, 3], dtype='float64')
+    >>> series[1] = 'One'
+    >>> detector = series.cleaner.detect.dtype(ptype=float)
+    >>> print(detector.is_error())
     0    False
     1     True
     2    False
@@ -55,11 +55,11 @@ class TypeErrorsSeriesDetector(_SeriesDetector):
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series([1., 2., np.nan, 3.])
-    >>> my_series[1] = 'One'
-    >>> my_series[2] = np.nan
-    >>> my_detector = my_series.cleaner.detect.type(ptype=int)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([1., 2., np.nan, 3.])
+    >>> series[1] = 'One'
+    >>> series[2] = np.nan
+    >>> detector = series.cleaner.detect.type(ptype=int)
+    >>> print(detector.is_error())
     0    False
     1     True
     2    False
@@ -69,13 +69,13 @@ class TypeErrorsSeriesDetector(_SeriesDetector):
     If no type is specified, find elements whose types differ
     from the first one
 
-    >>> my_series = pd.Series(['A', 2, np.nan, 'D'])
-    >>> my_detector = my_series.cleaner.detect('type')
-    >>> type(my_series[0])
+    >>> series = pd.Series(['A', 2, np.nan, 'D'])
+    >>> detector = series.cleaner.detect('type')
+    >>> type(series[0])
     str
-    >>>print(my_detector.ptype)
+    >>>print(detector.ptype)
     str
-    >>> print(my_detector.is_error())
+    >>> print(detector.is_error())
     0    False
     1     True
     2    False
@@ -84,24 +84,24 @@ class TypeErrorsSeriesDetector(_SeriesDetector):
 
     The first detector detects the right type as str
 
-    >>> my_series = pd.Series(['A', 2, np.nan, 'D'])
-    >>> my_series_test = pd.Series([1, 'Two'])
-    >>> my_detector = my_series.cleaner.detect('type')
-    >>> my_second_detector = my_series_test.cleaner.detect(my_detector)
-    >>> print(my_second_detector.is_error())
+    >>> series = pd.Series(['A', 2, np.nan, 'D'])
+    >>> series_test = pd.Series([1, 'Two'])
+    >>> detector = series.cleaner.detect('type')
+    >>> second_detector = series_test.cleaner.detect(detector)
+    >>> print(second_detector.is_error())
     0     True
     1    False
     dtype: bool
     """
     name = 'types'
 
-    def __init__(self, obj, detector_obj=None, ptype=None):
+    def __init__(self, obj, detector=None, ptype=None):
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             self._ptype = ptype
         else:
-            self._ptype = detector_obj.ptype
+            self._ptype = detector.ptype
 
         if not isinstance(self.ptype, type):
             raise TypeError("ptype bound must be a python built-in type")
@@ -131,24 +131,27 @@ def _reported(self):
         return ['ptype']
 
 
-class CastableSeriesDetector(_SeriesDetector):
-    r"""'castable' : Detect elements that cannot be casted into target type.
+class castable(_SeriesDetector):
+    r"""Detect elements that cannot be casted into target type.
 
     Intended to be used by the detect method with the keyword 'castable'
 
-    >>> series.detect.castable(...)
-    >>> series.detect('castable',...)
+    >>> series.cleaner.detect.castable(...)
+    >>> series.cleaner.detect('castable',...)
 
     This detection method flags elements in an object Series as errors
     when they can not be converted (casted) into a given type.
 
     For example,
-    + '1.2' is not castable as an integer
-    + 'ABC' is not castable as a number/float
-    + '2022-02-28' is castable as a date, but '2022-02-31' is not
+
+    + ``1.2`` is not castable as an integer
+
+    + ``ABC`` is not castable as a number/float
+
+    + ``2022-02-28`` is castable as a date, but ``2022-02-31`` is not
 
     The expected thousands and decimal separators can be customized, so that,
-    for example: '100,000.0' can be seen as 100000.
+    for example: ``100,000.0`` can be seen as 100000.
 
     Note
     ----
@@ -172,7 +175,8 @@ class CastableSeriesDetector(_SeriesDetector):
     ------
     ValueError
         When target is not among the allowed values, or target is not defined.
-        When detector is applied to float, int series
+    ValueError
+        When detector is applied to ``float`` or ``int`` series
 
 
     Examples
@@ -180,9 +184,9 @@ class CastableSeriesDetector(_SeriesDetector):
     >>> import pandas as pd
     >>> import pdcleaner
 
-    >>> my_series = pd.Series(['1','2.0','1.2','A','100', '22/05/1975'], dtype='object')
-    >>> my_detector = my_series.cleaner.detect('castable', target='int')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['1','2.0','1.2','A','100', '22/05/1975'], dtype='object')
+    >>> detector = series.cleaner.detect('castable', target='int')
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -191,8 +195,8 @@ class CastableSeriesDetector(_SeriesDetector):
     5     True
     dtype: bool
 
-    >>> my_detector = my_series.cleaner.detect('castable', target='date')
-    >>> print(my_detector.is_error())
+    >>> detector = series.cleaner.detect('castable', target='date')
+    >>> print(detector.is_error())
     0     True
     1     True
     2     True
@@ -201,8 +205,8 @@ class CastableSeriesDetector(_SeriesDetector):
     5    False
     dtype: bool
 
-    >>> my_detector = my_series.cleaner.detect('castable', target='number')
-    >>> my_detector.is_error()
+    >>> detector = series.cleaner.detect('castable', target='number')
+    >>> detector.is_error()
     0    False
     1    False
     2    False
@@ -211,10 +215,10 @@ class CastableSeriesDetector(_SeriesDetector):
     5     True
     dtype: bool
 
-    >>> my_series = pd.Series(['Yes','No','No','Yes','Ok', 'Nok'], dtype='object')
-    >>> my_detector = my_series.cleaner.detect('castable', target='boolean',
+    >>> series = pd.Series(['Yes','No','No','Yes','Ok', 'Nok'], dtype='object')
+    >>> detector = series.cleaner.detect('castable', target='boolean',
                                                 bool_values={"Yes":True, "No":False})
-    >>> my_detector.is_error()
+    >>> detector.is_error()
     0    False
     1    False
     2    False
@@ -225,9 +229,9 @@ class CastableSeriesDetector(_SeriesDetector):
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['1','2.0','1.2','A','100', np.nan], dtype='object')
-    >>> my_detector = my_series.cleaner.detect('castable', target='number')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['1','2.0','1.2','A','100', np.nan], dtype='object')
+    >>> detector = series.cleaner.detect('castable', target='number')
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -239,22 +243,22 @@ class CastableSeriesDetector(_SeriesDetector):
     """
     name = 'castable'
 
-    def __init__(self, obj, detector_obj=None, target=None, **kwargs):
+    def __init__(self, obj, detector=None, target=None, **kwargs):
         super().__init__(obj)
 
         if obj.dtype != 'object':
             raise TypeError("This detector is only for object series.")
 
-        if not detector_obj:
+        if not detector:
             self._target = target
             self._thousands = kwargs.get('thousands')
             self._decimal = kwargs.get('decimal')
             self._bool_values = kwargs.get('bool_values')
         else:
-            self._target = detector_obj.target
-            self._thousands = detector_obj.thousands
-            self._decimal = detector_obj.decimal
-            self._bool_values = detector_obj.bool_values
+            self._target = detector.target
+            self._thousands = detector.thousands
+            self._decimal = detector.decimal
+            self._bool_values = detector.bool_values
 
         if self._target is None:
             raise ValueError("Target parameter must be defined")
diff --git a/pdcleaner/detection/values.py b/src/pdcleaner/detection/values.py
similarity index 71%
rename from pdcleaner/detection/values.py
rename to src/pdcleaner/detection/values.py
index 1de4f5c..c8e0e8f 100644
--- a/pdcleaner/detection/values.py
+++ b/src/pdcleaner/detection/values.py
@@ -7,8 +7,13 @@
 from pdcleaner.detection._base import _SeriesDetector, _TwoColsCategoricalDataFramesDetector
 
 
-class EnumSeriesDetector(_SeriesDetector):
-    r"""'enum': Detect class values not in a given list.
+class enum(_SeriesDetector):
+    r"""Detect class values not in a given list.
+
+    Intended to be used by the detect method with the keyword 'enum'.
+
+    >>> series.cleaner.detect.enum(...)
+    >>> series.cleaner.detect('enum',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element is not in the given values list.
@@ -36,9 +41,9 @@ class EnumSeriesDetector(_SeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['cat','cat','dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.enum(values=['cat','dog'])
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat','cat','dog','bird'])
+    >>> detector = series.cleaner.detect.enum(values=['cat','dog'])
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -47,17 +52,17 @@ class EnumSeriesDetector(_SeriesDetector):
 
     The detector can also be used with numerical values:
 
-    >>> my_series = pd.Series([5, 5.0, 10, 3])
-    >>> my_detector = my_series.cleaner.detect.enum(values=[5,3])
-    >>> print(my_detector.detected)
+    >>> series = pd.Series([5, 5.0, 10, 3])
+    >>> detector = series.cleaner.detect.enum(values=[5,3])
+    >>> print(detector.detected())
     2    10.0
     dtype: float64
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['cat',np.nan,'dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.enum(values=['cat','dog'])
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat',np.nan,'dog','bird'])
+    >>> detector = series.cleaner.detect.enum(values=['cat','dog'])
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -66,10 +71,10 @@ class EnumSeriesDetector(_SeriesDetector):
 
     Use `forbidden=True` to detect values in the list as errors
 
-    >>> my_series = pd.Series(['cat','cat','dog','bird'])
-    >>> my_detector = \
-        my_series.cleaner.detect.enum(values=['cat','dog'], forbidden=True)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat','cat','dog','bird'])
+    >>> detector = \
+        series.cleaner.detect.enum(values=['cat','dog'], forbidden=True)
+    >>> print(detector.is_error())
     0     True
     1     True
     2     True
@@ -80,7 +85,7 @@ class EnumSeriesDetector(_SeriesDetector):
     name = 'enum'
 
     def __init__(self, obj,
-                 detector_obj=None,
+                 detector=None,
                  values=None,
                  forbidden=False):
 
@@ -89,12 +94,12 @@ def __init__(self, obj,
         if values is None:
             values = []
 
-        if not detector_obj:
+        if not detector:
             self._values = values
             self._forbidden = forbidden
         else:
-            self._values = detector_obj.values
-            self._forbidden = detector_obj.forbidden
+            self._values = detector.values
+            self._forbidden = detector.forbidden
 
         if len(self._values) == 0:
             raise ValueError("The list of authorized values is empty")
@@ -123,13 +128,17 @@ def index(self) -> pd.Index:
         return self._obj[mask].index
 
 
-class ValueSeriesDetector(_SeriesDetector):
-    r"""'value': Detect class values different from a value.
+class value(_SeriesDetector):
+    r"""Detect class values different from a value.
+
+    Intended to be used by the detect method with the keyword 'value'.
+
+    >>> series.cleaner.detect.value(...)
+    >>> series.cleaner.detect('value',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element is different or not from a given value.
 
-
     Note
     ----
 
@@ -154,9 +163,9 @@ class ValueSeriesDetector(_SeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['cat','cat','dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.value(value='cat')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat','cat','dog','bird'])
+    >>> detector = series.cleaner.detect.value(value='cat')
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -165,25 +174,25 @@ class ValueSeriesDetector(_SeriesDetector):
 
     By default, the type of value and data is checked and must be identical
 
-    >>> my_series = pd.Series([5, 5.0])
-    >>> my_detector = my_series.cleaner.detect.value(value=5)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([5, 5.0])
+    >>> detector = series.cleaner.detect.value(value=5)
+    >>> print(detector.is_error())
     0    False
     1    True
     dtype: bool
 
-    >>> my_series = pd.Series([5, 5.0])
-    >>> my_detector = my_series.cleaner.detect.value(value=5, check_type=False)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series([5, 5.0])
+    >>> detector = series.cleaner.detect.value(value=5, check_type=False)
+    >>> print(detector.is_error())
     0    False
     1    False
     dtype: bool
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['cat',np.nan,'dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.value(value='cat')
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat',np.nan,'dog','bird'])
+    >>> detector = series.cleaner.detect.value(value='cat')
+    >>> print(detector.is_error())
     0    False
     1    False
     2     True
@@ -203,7 +212,7 @@ class ValueSeriesDetector(_SeriesDetector):
     name = 'value'
 
     def __init__(self, obj,
-                 detector_obj=None,
+                 detector=None,
                  value=None,
                  check_type=True,
                  forbidden=False
@@ -211,14 +220,14 @@ def __init__(self, obj,
 
         super().__init__(obj)
 
-        if detector_obj is None:
+        if detector is None:
             self._value = value
             self._check_type = check_type
             self._forbidden = forbidden
         else:
-            self._value = detector_obj.value
-            self._check_type = detector_obj.check_type
-            self._forbidden = detector_obj.forbidden
+            self._value = detector.value
+            self._check_type = detector.check_type
+            self._forbidden = detector.forbidden
 
         if self.value is None:
             raise ValueError("The authorized value is not defined")
@@ -260,8 +269,13 @@ def _reported(self):
         return ['value', 'check_type', 'forbidden']
 
 
-class ValueCountsSeriesDetector(_SeriesDetector):
-    r"""'counts': Detect class values that appear at max n times.
+class counts(_SeriesDetector):
+    r"""Detect class values that appear at max n times.
+
+    Intended to be used by the detect method with the keyword 'counts'.
+
+    >>> series.cleaner.detect.counts(...)
+    >>> series.cleaner.detect('counts',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element appears less or = than n times in the Series.
@@ -287,11 +301,11 @@ class ValueCountsSeriesDetector(_SeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['cat','cat','dog','dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.counts(n=1)
-    >>> print(my_detector.values)
+    >>> series = pd.Series(['cat','cat','dog','dog','bird'])
+    >>> detector = series.cleaner.detect.counts(n=1)
+    >>> print(detector.values)
     ['cat','dog']
-    >>> print(my_detector.is_error())
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -302,9 +316,9 @@ class ValueCountsSeriesDetector(_SeriesDetector):
     Use resulting object to apply to another series: only the
     previously detected valid values are considered valid.
 
-    >>> my_series_test = pd.Series(['dog','bird','mouse','cat'])
-    >>> my_detector_test = my_series.cleaner.detect(my_detector)
-    >>> print(my_detector_test.is_error())
+    >>> series_test = pd.Series(['dog','bird','mouse','cat'])
+    >>> detector_test = series.cleaner.detect(detector)
+    >>> print(detector_test.is_error())
     0    False
     1     True
     2     True
@@ -313,9 +327,9 @@ class ValueCountsSeriesDetector(_SeriesDetector):
 
     The detector can also be used with numerical values:
 
-    >>> my_series_test = pd.Series([5, 3, 3.0, 100, 5])
-    >>> my_detector_test = my_series_test.cleaner.detect.counts(n=1)
-    >>> print(my_detector_test.is_error())
+    >>> series_test = pd.Series([5, 3, 3.0, 100, 5])
+    >>> detector_test = series_test.cleaner.detect.counts(n=1)
+    >>> print(detector_test.is_error())
     0    False
     1    False
     2    False
@@ -325,9 +339,9 @@ class ValueCountsSeriesDetector(_SeriesDetector):
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['cat',np.nan,'dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.counts(n=1)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat',np.nan,'dog','bird'])
+    >>> detector = series.cleaner.detect.counts(n=1)
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -336,15 +350,15 @@ class ValueCountsSeriesDetector(_SeriesDetector):
     """
     name = 'counts'
 
-    def __init__(self, obj, detector_obj=None, n=1):
+    def __init__(self, obj, detector=None, n=1):
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             self._n = n
             self._values = self.values
         else:
-            self._n = detector_obj.n
-            self._values = detector_obj._values
+            self._n = detector.n
+            self._values = detector._values
 
         if not isinstance(n, int):
             raise TypeError('n must be a >0 integer')
@@ -379,8 +393,13 @@ def _reported(self):
         return ['n']
 
 
-class ValuesFreqSeriesDetector(_SeriesDetector):
-    r"""'freq': Detect class values that appear less than a given freq.
+class freq(_SeriesDetector):
+    r"""Detect class values that appear less than a given freq.
+
+    Intended to be used by the detect method with the keyword 'freq'.
+
+    >>> series.cleaner.detect.freq(...)
+    >>> series.cleaner.detect('freq',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element appears less than a given frequency (ratio
@@ -408,11 +427,11 @@ class ValuesFreqSeriesDetector(_SeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['cat','cat','dog','dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.freq(freq=.25)
-    >>> print(my_detector.values)
+    >>> series = pd.Series(['cat','cat','dog','dog','bird'])
+    >>> detector = series.cleaner.detect.freq(freq=.25)
+    >>> print(detector.values)
     ['cat','dog']
-    >>> print(my_detector.is_error())
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -423,9 +442,9 @@ class ValuesFreqSeriesDetector(_SeriesDetector):
     Use resulting object to apply to another series: only the
     previously detected valid values are considered valid.
 
-    >>> my_series_test = pd.Series(['dog','bird','mouse','cat'])
-    >>> my_detector_test = my_series.cleaner.detect(my_detector)
-    >>> print(my_detector_test.is_error())
+    >>> series_test = pd.Series(['dog','bird','mouse','cat'])
+    >>> detector_test = series.cleaner.detect(detector)
+    >>> print(detector_test.is_error())
     0    False
     1     True
     2     True
@@ -434,9 +453,9 @@ class ValuesFreqSeriesDetector(_SeriesDetector):
 
     The detector can also be used with numerical values:
 
-    >>> my_series_test = pd.Series([5, 3, 3.0, 100, 5])
-    >>> my_detector_test = my_series_test.cleaner.detect.freq(freq=0.25)
-    >>> print(my_detector_test.is_error())
+    >>> series_test = pd.Series([5, 3, 3.0, 100, 5])
+    >>> detector_test = series_test.cleaner.detect.freq(freq=0.25)
+    >>> print(detector_test.is_error())
     0    False
     1    False
     2    False
@@ -446,9 +465,9 @@ class ValuesFreqSeriesDetector(_SeriesDetector):
 
     Missing values are not treated as errors.
 
-    >>> my_series = pd.Series(['cat','cat', np.nan, 'dog', 'dog','bird'])
-    >>> my_detector = my_series.cleaner.detect.counts(n=1)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['cat','cat', np.nan, 'dog', 'dog','bird'])
+    >>> detector = series.cleaner.detect.counts(n=1)
+    >>> print(detector.is_error())
     0    False
     1    False
     2    False
@@ -459,17 +478,17 @@ class ValuesFreqSeriesDetector(_SeriesDetector):
     """
     name = 'freq'
 
-    def __init__(self, obj, detector_obj=None, freq=0.1):
+    def __init__(self, obj, detector=None, freq=0.1):
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             if not isinstance(freq, float):
                 raise TypeError('freq must be a float')
             self._freq = freq
             self._values = self.values
         else:
-            self._freq = detector_obj.freq
-            self._values = detector_obj._values
+            self._freq = detector.freq
+            self._values = detector._values
 
         if (self.freq <= 0) or (self.freq >= 1):
             raise TypeError('freq must be in the range ]0;1[')
@@ -501,9 +520,14 @@ def _reported(self):
         return ['freq']
 
 
-class CategoriesAssociationsDataFramesDetector(_TwoColsCategoricalDataFramesDetector):
+class associations(_TwoColsCategoricalDataFramesDetector):
     r"""Detects least frequent associations between two category columns
 
+    Intended to be used by the detect method with the keyword 'associations'
+
+    >>> dataframe.cleaner.detect.associations(...)
+    >>> dataframe.cleaner.detect('associations',...)
+
     Parameters
     ----------
     count: int
@@ -535,12 +559,12 @@ class CategoriesAssociationsDataFramesDetector(_TwoColsCategoricalDataFramesDete
         })
 
     >>> detector = df.cleaner.detect.associations(freq=0.05)
-    >>> print(detector.detected)
+    >>> print(detector.detected())
         col1 col2
     19    B    a
 
     >>> detector = df.cleaner.detect.associations(count=3)
-    >>> print(detector.detected)
+    >>> print(detector.detected())
         col1 col2
     8     A    c
     9     A    c
@@ -549,10 +573,10 @@ class CategoriesAssociationsDataFramesDetector(_TwoColsCategoricalDataFramesDete
 
     name = "associations"
 
-    def __init__(self, obj, detector_obj=None, count=None, freq=None):
+    def __init__(self, obj, detector=None, count=None, freq=None):
         super().__init__(obj)
 
-        if not detector_obj:
+        if not detector:
             if ((freq is None) and (count is None)) or ((freq is not None) and (count is not None)):
                 raise ValueError("Either freq or count must be provided")
 
@@ -573,9 +597,9 @@ def __init__(self, obj, detector_obj=None, count=None, freq=None):
                                                    self.limit,
                                                    )
         else:
-            self._count = detector_obj.count
-            self._freq = detector_obj.freq
-            self._valid_associations = detector_obj.valid_associations
+            self._count = detector.count
+            self._freq = detector.freq
+            self._valid_associations = detector.valid_associations
 
     @property
     def count(self):
@@ -621,15 +645,18 @@ def _calculate_valid_associations(df: pd.DataFrame,
                                )
 
         gt_than_limit = (crosstab > limit).stack().reset_index()
-        errors = df.merge(gt_than_limit, on=[col1, col2]).iloc[:, -1]
-
-        return (df[errors]
-                .drop_duplicates()
-                .reset_index()
-                .iloc[:, -2:]
-                .apply(tuple, axis=1)
-                .tolist()
-                )
+        errors = df.merge(gt_than_limit, on=[col1, col2], how='left').iloc[:, -1].fillna(False)
+
+        assoc = (
+            df[errors]
+            .drop_duplicates()
+            .reset_index()
+            .iloc[:, -2:]
+        )
+
+        valid_associations = list(map(tuple, assoc.values))
+
+        return valid_associations
 
     @property
     def index(self) -> pd.Index:
diff --git a/pdcleaner/detection/web.py b/src/pdcleaner/detection/web.py
similarity index 69%
rename from pdcleaner/detection/web.py
rename to src/pdcleaner/detection/web.py
index 55a1db1..af5d070 100644
--- a/pdcleaner/detection/web.py
+++ b/src/pdcleaner/detection/web.py
@@ -9,17 +9,17 @@
 
 import pandas as pd
 
-from pdcleaner.detection.strings import PatternSeriesDetector
+from pdcleaner.detection.strings import pattern as _pattern
 from pdcleaner.detection._base import _ObjectTypeSeriesDetector
 
 
-class EmailSeriesDetector(PatternSeriesDetector):
+class email(_pattern):
     r"""'email': Detect strings that do not match an email.
 
     Intended to be used by the detect method with the keyword 'email'
 
-    >>> series.detect.email(...)
-    >>> series.detect('email',...)
+    >>> series.cleaner.detect.email(...)
+    >>> series.cleaner.detect('email',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element does not match an email.
@@ -31,9 +31,9 @@ class EmailSeriesDetector(PatternSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['john_856_doe@gmail.com','john_doe','np.nan','john?doe@gmail.com'])
-    >>> my_detector = my_series.cleaner.detect.email()
-    >>> print(my_detector.detected)
+    >>> series = pd.Series(['john_856_doe@gmail.com','john_doe','np.nan','john?doe@gmail.com'])
+    >>> detector = series.cleaner.detect.email()
+    >>> print(detector.detected())
     1              john_doe
     2                np.nan
     3    john?doe@gmail.com
@@ -42,9 +42,9 @@ class EmailSeriesDetector(PatternSeriesDetector):
 
     name = 'email'
 
-    def __init__(self, obj, detector_obj=None):
+    def __init__(self, obj, detector=None):
         pattern_email = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
-        super().__init__(obj, detector_obj, pattern=pattern_email, mode="fullmatch")
+        super().__init__(obj, detector, pattern=pattern_email, mode="fullmatch")
 
     @property
     def _reported(self):
@@ -52,13 +52,13 @@ def _reported(self):
         return []
 
 
-class UrlSeriesDetector(PatternSeriesDetector):
-    r"""'url': Detect strings that do not match a url.
+class url(_pattern):
+    r"""Detect strings that do not match a url.
 
     Intended to be used by the detect method with the keyword 'url'
 
-    >>> series.detect.url(...)
-    >>> series.detect('url',...)
+    >>> series.cleaner.detect.url(...)
+    >>> series.cleaner.detect('url',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element does not match a url.
@@ -77,19 +77,19 @@ class UrlSeriesDetector(PatternSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series([
+    >>> series = pd.Series([
         'google.com','https://www.google.com/', 'https://127.0.0.1:80', 'dummy'])
-    >>> my_detector = my_series.cleaner.detect.url()
-    >>> print(my_detector.detected)
+    >>> detector = series.cleaner.detect.url()
+    >>> print(detector.detected())
     0    google.com
     3         dummy
     dtype: object
 
     If protocol is not mandatory
 
-    >>> my_series = pd.Series(['google.com','https://www.google.com/'])
-    >>> my_detector = my_series.cleaner.detect('url', check_protocol=False)
-    >>> print(my_detector.is_error())
+    >>> series = pd.Series(['google.com','https://www.google.com/'])
+    >>> detector = series.cleaner.detect('url', check_protocol=False)
+    >>> print(detector.is_error())
     0   False
     1   False
     dtype: bool
@@ -97,12 +97,12 @@ class UrlSeriesDetector(PatternSeriesDetector):
 
     name = 'url'
 
-    def __init__(self, obj, detector_obj=None, check_protocol=True):
+    def __init__(self, obj, detector=None, check_protocol=True):
 
-        if detector_obj is None:
+        if detector is None:
             self._check_protocol = check_protocol
         else:
-            self._check_protocol = detector_obj.check_protocol
+            self._check_protocol = detector.check_protocol
 
         pattern_url = re.compile(
             (r'^(?:http|ftp)s?://' if check_protocol else
@@ -114,7 +114,7 @@ def __init__(self, obj, detector_obj=None, check_protocol=True):
             r'(?::\d+)?'  # optional port
             r'(?:/?|[/?]\S+)$', re.IGNORECASE)
 
-        super().__init__(obj, detector_obj, pattern=pattern_url, mode="fullmatch")
+        super().__init__(obj, detector, pattern=pattern_url, mode="fullmatch")
 
     @property
     def check_protocol(self):
@@ -128,13 +128,13 @@ def _reported(self):
         return ['check_protocol']
 
 
-class PingSeriesDetector(_ObjectTypeSeriesDetector):
-    r"""'ping': Detect strings that do not match a reachable url.
+class ping(_ObjectTypeSeriesDetector):
+    r"""Detect strings that do not match a reachable url.
 
     Intended to be used by the detect method with the keyword 'ping'
 
-    >>> series.detect.ping(...)
-    >>> series.detect('ping',...)
+    >>> series.cleaner.detect.ping(...)
+    >>> series.cleaner.detect('ping',...)
 
     This detection method flags values as potential errors wherever the
     corresponding Series element does not match a reachable url.
@@ -146,9 +146,9 @@ class PingSeriesDetector(_ObjectTypeSeriesDetector):
     Examples
     --------
 
-    >>> my_series = pd.Series(['google.com','https://www.google.com/', 'dummy'])
-    >>> my_detector = my_series.cleaner.detect.ping()
-    >>> print(my_detector.detected)
+    >>> series = pd.Series(['google.com','https://www.google.com/', 'dummy'])
+    >>> detector = series.cleaner.detect.ping()
+    >>> print(detector.detected())
     0    google.com
     2         dummy
     dtype: object
@@ -156,7 +156,7 @@ class PingSeriesDetector(_ObjectTypeSeriesDetector):
 
     name = 'ping'
 
-    def __init__(self, obj, detector_obj=None):
+    def __init__(self, obj, detector=None):
         # pylint: disable=unused-argument
         super().__init__(obj)
 
diff --git a/pdcleaner/plots/__init__.py b/src/pdcleaner/plots/__init__.py
similarity index 100%
rename from pdcleaner/plots/__init__.py
rename to src/pdcleaner/plots/__init__.py
diff --git a/pdcleaner/plots/keycollision.py b/src/pdcleaner/plots/alternatives.py
similarity index 87%
rename from pdcleaner/plots/keycollision.py
rename to src/pdcleaner/plots/alternatives.py
index f0d8a91..f13141c 100644
--- a/pdcleaner/plots/keycollision.py
+++ b/src/pdcleaner/plots/alternatives.py
@@ -1,10 +1,10 @@
 import pandas as pd
 
 from pdcleaner.utils.utils import add_method
-from pdcleaner.detection.strings import KeyCollisionSeriesDetector
+from pdcleaner.detection.strings import alternatives
 
 
-@add_method(KeyCollisionSeriesDetector, 'plot')
+@add_method(alternatives, 'plot')
 def plot(self, cmap=None, not_displayed_color='red', nfirst=0, nlast=0, figsize=None):
     """plot a countplot of values frequency grouped by keys, with options to compact the graph
 
@@ -35,29 +35,29 @@ def plot(self, cmap=None, not_displayed_color='red', nfirst=0, nlast=0, figsize=
     Examples
     --------
 
-    >>> my_series = pd.Series(['Linus Torvalds',
+    >>> series = pd.Series(['Linus Torvalds',
                                'Torvalds, Linus',
                                'Linus Torvalds',
                                'Bill Gates',
                                'Bill Gates',
                                'Steve Jobs',
                                ])
-    >>> my_detector = my_series.cleaner.detect.keycollision()
-    >>> my_detector.plot()
+    >>> detector = series.cleaner.detect.alternatives()
+    >>> detector.plot()
 
-    .. image:: ../../_static/plot_keycollision_1.png
+    .. image:: ../../_static/plot_alternatives_1.png
 
     Display only the two most frequents
 
-    >>> my_detector.plot(nfirst=2)
+    >>> detector.plot(nfirst=2)
 
-    .. image:: ../../_static/plot_keycollision_nfirst_2.png
+    .. image:: ../../_static/plot_alternatives_nfirst_2.png
 
     Display only the least frequent
 
-    >>> my_detector.plot(nlast=1)
+    >>> detector.plot(nlast=1)
 
-    .. image:: ../../_static/plot_keycollision_nlast_1.png
+    .. image:: ../../_static/plot_alternatives_nlast_1.png
     """
 
     if not isinstance(nfirst, int):
diff --git a/pdcleaner/plots/freqandcount.py b/src/pdcleaner/plots/freqandcount.py
similarity index 90%
rename from pdcleaner/plots/freqandcount.py
rename to src/pdcleaner/plots/freqandcount.py
index 11a4058..f92b12f 100644
--- a/pdcleaner/plots/freqandcount.py
+++ b/src/pdcleaner/plots/freqandcount.py
@@ -5,11 +5,11 @@
 import seaborn as sns
 
 from pdcleaner.utils.utils import add_method
-from pdcleaner.detection.values import ValueCountsSeriesDetector, ValuesFreqSeriesDetector
+from pdcleaner.detection.values import counts, freq
 
 
-@add_method(ValueCountsSeriesDetector, 'plot')
-@add_method(ValuesFreqSeriesDetector, 'plot')
+@add_method(counts, 'plot')
+@add_method(freq, 'plot')
 def plot(self,
          nfirst=0,
          nlast=0,
@@ -50,8 +50,8 @@ def plot(self,
 
     Examples
     --------
-    >>> my_series = pd.Series(['cat','cat','dog', 'dog','dog','bird'])
-    >>> detector = my_series.cleaner.detect.freq(freq=.2)
+    >>> series = pd.Series(['cat','cat','dog', 'dog','dog','bird'])
+    >>> detector = series.cleaner.detect.freq(freq=.2)
     >>> detector.plot()
 
     .. image:: ../../_static/plot_freq.png
diff --git a/pdcleaner/plots/multicategories.py b/src/pdcleaner/plots/multicategories.py
similarity index 94%
rename from pdcleaner/plots/multicategories.py
rename to src/pdcleaner/plots/multicategories.py
index 00c0883..e18145b 100644
--- a/pdcleaner/plots/multicategories.py
+++ b/src/pdcleaner/plots/multicategories.py
@@ -4,10 +4,10 @@
 
 from pdcleaner.utils.utils import add_method
 from pdcleaner.detection.values \
-    import CategoriesAssociationsDataFramesDetector
+    import associations
 
 
-@add_method(CategoriesAssociationsDataFramesDetector, 'plot')
+@add_method(associations, 'plot')
 def plot(self, color='green', errors_color='red', fmt=".0f"):
     """plot a colored matrix (heatmap) représentation of categories associations.
 
@@ -41,7 +41,7 @@ def plot(self, color='green', errors_color='red', fmt=".0f"):
 
     .. image:: ../../_static/plot_association.png
     """
-    data = self.obj
+    data = self.obj.copy()
 
     crosstab = pd.crosstab(index=data.iloc[:, 0],
                            columns=[data.iloc[:, 1]]
diff --git a/pdcleaner/plots/numseries.py b/src/pdcleaner/plots/numseries.py
similarity index 95%
rename from pdcleaner/plots/numseries.py
rename to src/pdcleaner/plots/numseries.py
index 3060f04..6c8e737 100644
--- a/pdcleaner/plots/numseries.py
+++ b/src/pdcleaner/plots/numseries.py
@@ -1,3 +1,5 @@
+import warnings
+
 import numpy as np
 import pandas as pd
 import matplotlib.pyplot as plt
@@ -6,6 +8,7 @@
 from pdcleaner.utils.utils import add_method
 from pdcleaner.detection._base import _NumericalSeriesDetector
 
+MAX_SIZE = int(5e4)
 
 @add_method(_NumericalSeriesDetector, 'plot')
 def plot(self,
@@ -49,9 +52,9 @@ def plot(self,
     Examples
     --------
 
-    >>> my_series = pd.Series([-5, 1, 2 , 3, 8, 12])
-    >>> my_detector = my_series.cleaner.detect.bounded(lower=0, upper=10)
-    >>> my_detector.plot()
+    >>> series = pd.Series([-5, 1, 2 , 3, 8, 12])
+    >>> detector = series.cleaner.detect.bounded(lower=0, upper=10)
+    >>> detector.plot()
 
     .. image:: ../../_static/plot_numseries.png
     """
@@ -72,6 +75,10 @@ def plot(self,
 
     linestyle = ':'
 
+    if len(df) > MAX_SIZE:
+        df = df.sample(n=MAX_SIZE)
+        warnings.warn(f"Plot has been limited to {MAX_SIZE} rows for performance issues")
+
     sns.scatterplot(data=df,
                     x=df.index,
                     y='data',
diff --git a/pdcleaner/utils/__init__.py b/src/pdcleaner/utils/__init__.py
similarity index 100%
rename from pdcleaner/utils/__init__.py
rename to src/pdcleaner/utils/__init__.py
diff --git a/pdcleaner/utils/df_utils.py b/src/pdcleaner/utils/df_utils.py
similarity index 100%
rename from pdcleaner/utils/df_utils.py
rename to src/pdcleaner/utils/df_utils.py
diff --git a/pdcleaner/utils/report_utils.py b/src/pdcleaner/utils/report_utils.py
similarity index 100%
rename from pdcleaner/utils/report_utils.py
rename to src/pdcleaner/utils/report_utils.py
diff --git a/pdcleaner/utils/utils.py b/src/pdcleaner/utils/utils.py
similarity index 100%
rename from pdcleaner/utils/utils.py
rename to src/pdcleaner/utils/utils.py
diff --git a/tutorials/create_data.ipynb b/tutorials/create_data.ipynb
deleted file mode 100644
index 2732e3e..0000000
--- a/tutorials/create_data.ipynb
+++ /dev/null
@@ -1,437 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "code",
-   "execution_count": 1,
-   "id": "792aed13",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "extended path variable\n"
-     ]
-    }
-   ],
-   "source": [
-    "%reload_ext autoreload\n",
-    "%autoreload 2\n",
-    "\n",
-    "try:\n",
-    "    import pdcleaner\n",
-    "except ModuleNotFoundError:\n",
-    "    print(\"extended path variable\")\n",
-    "    import sys\n",
-    "    sys.path.append('..')\n",
-    "    import pdcleaner"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 2,
-   "id": "2888639d",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import random\n",
-    "\n",
-    "import numpy as np\n",
-    "import pandas as pd\n",
-    "\n",
-    "\n",
-    "np.random.seed(seed=0)\n",
-    "random.seed(0)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "7b2a8e94",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def compute_sphere_volume(diameter):\n",
-    "        return np.pi / 6  * (diameter**3)\n",
-    "\n",
-    "def generate_bounded_normal(n, distribution_info, precision=None):\n",
-    "    if \"min\" not in distribution_info:\n",
-    "        distribution_info[\"min\"] = np.NINF\n",
-    "    if \"max\" not in distribution_info:\n",
-    "        distribution_info[\"max\"] = np.inf\n",
-    "\n",
-    "    normal_values = np.random.normal(distribution_info[\"mu\"], distribution_info[\"sigma\"], n)\n",
-    "    bounded_values = np.clip(normal_values, distribution_info[\"min\"], distribution_info[\"max\"])\n",
-    "\n",
-    "    if precision:\n",
-    "        return bounded_values.round(precision)\n",
-    "    return bounded_values\n",
-    "    \n",
-    "def generate_with_expr(base_series, expr, sigma_noise=None, precision=None):\n",
-    "    values = base_series.apply(expr)\n",
-    "    if sigma_noise:\n",
-    "        noise = np.random.normal(0, sigma_noise, len(values))\n",
-    "        values = values + noise\n",
-    "    if precision:\n",
-    "        return values.round(precision)\n",
-    "    return values\n",
-    "    \n",
-    "def generate_category(category_name, n_samples, price_info, diameter_info, density, volume_noise=None):\n",
-    "    \"\"\"\n",
-    "    n_samples, price_info, diameter_info, weight_info\n",
-    "    \"\"\"\n",
-    "    \n",
-    "    df = pd.DataFrame( [[category_name, np.nan, np.nan, np.nan]] * n_samples,\n",
-    "            columns=[\"category\", \"price(euro)\", \"diameter(cm)\", \"weight(kg)\"])\n",
-    "    \n",
-    "    df[\"price(euro)\"] = generate_bounded_normal(n_samples, price_info, 2)\n",
-    "    df[\"diameter(cm)\"] = generate_bounded_normal(n_samples, diameter_info, 1)\n",
-    "    volme_series = generate_with_expr(df[\"diameter(cm)\"], compute_sphere_volume, sigma_noise=volume_noise)\n",
-    "    df[\"weight(kg)\"] = (1e-3 * density * volme_series).round(3).clip(lower=0.)\n",
-    "    \n",
-    "    return df\n",
-    "\n",
-    "#diameter in cm, weight in kg"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "id": "af453f5e",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "#pomme\n",
-    "n = 100\n",
-    "price_info = {\"sigma\":1.5, \"mu\":3., \"min\":0.49, \"max\":7.99}\n",
-    "diameter_info = {\"sigma\":1, \"mu\":7, \"min\":1., \"max\":12}\n",
-    "mv = 0.84 #masse volumique en g/cm3\n",
-    "df_pomme = generate_category(\"pomme\", n, price_info, diameter_info, mv, volume_noise=15)\n",
-    "\n",
-    "#cerise\n",
-    "n = 100\n",
-    "price_info = {\"sigma\":2.5, \"mu\":9., \"min\":4.99, \"max\":14.99}\n",
-    "diameter_info = {\"sigma\":0.7, \"mu\":2.5, \"min\":1., \"max\":4.}\n",
-    "mv = 0.64\n",
-    "df_cerise = generate_category(\"cerise\", n, price_info, diameter_info, mv, volume_noise=1)\n",
-    "\n",
-    "#navet\n",
-    "n = 30\n",
-    "price_info = {\"sigma\":1., \"mu\":2.2, \"min\":0.29, \"max\":4.99}\n",
-    "diameter_info = {\"sigma\":4., \"mu\":8., \"min\":4., \"max\":16.}\n",
-    "mv = 0.6\n",
-    "df_navet = generate_category(\"navet\", n, price_info, diameter_info, mv, volume_noise=20)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "1fe520fa",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price</th>\n",
-       "      <th>diameter</th>\n",
-       "      <th>weight</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>0</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>1.82</td>\n",
-       "      <td>13.4</td>\n",
-       "      <td>0.760</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>1</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.53</td>\n",
-       "      <td>6.5</td>\n",
-       "      <td>0.095</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>2</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.96</td>\n",
-       "      <td>6.9</td>\n",
-       "      <td>0.153</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>3</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.23</td>\n",
-       "      <td>6.3</td>\n",
-       "      <td>0.112</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>4</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.18</td>\n",
-       "      <td>8.9</td>\n",
-       "      <td>0.304</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>...</th>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>95</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>1.53</td>\n",
-       "      <td>8.9</td>\n",
-       "      <td>0.290</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>96</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.05</td>\n",
-       "      <td>5.9</td>\n",
-       "      <td>0.070</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>97</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>11.85</td>\n",
-       "      <td>2.1</td>\n",
-       "      <td>0.003</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>98</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>0.49</td>\n",
-       "      <td>7.1</td>\n",
-       "      <td>0.157</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>99</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>8.12</td>\n",
-       "      <td>3.3</td>\n",
-       "      <td>0.012</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "<p>100 rows × 4 columns</p>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "   category  price  diameter  weight\n",
-       "0     navet   1.82      13.4   0.760\n",
-       "1     pomme   2.53       6.5   0.095\n",
-       "2     pomme   2.96       6.9   0.153\n",
-       "3     pomme   2.23       6.3   0.112\n",
-       "4     pomme   3.18       8.9   0.304\n",
-       "..      ...    ...       ...     ...\n",
-       "95    pomme   1.53       8.9   0.290\n",
-       "96    pomme   2.05       5.9   0.070\n",
-       "97   cerise  11.85       2.1   0.003\n",
-       "98    pomme   0.49       7.1   0.157\n",
-       "99   cerise   8.12       3.3   0.012\n",
-       "\n",
-       "[100 rows x 4 columns]"
-      ]
-     },
-     "execution_count": 5,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "n_samples = 100\n",
-    "all_data = pd.concat([df_pomme, df_cerise, df_navet])\n",
-    "data = all_data.sample(n=n_samples).reset_index(drop=True)\n",
-    "data"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "961ef846",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "pomme     49\n",
-       "cerise    36\n",
-       "navet     15\n",
-       "Name: category, dtype: int64"
-      ]
-     },
-     "execution_count": 6,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "data.category.value_counts()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "4bb76874",
-   "metadata": {},
-   "source": [
-    "rajouter une colonne de donnée à distribution normale : teneur en pesticide en mg/kg\n",
-    "\n",
-    "https://eur-lex.europa.eu/legal-content/FR/TXT/?uri=LEGISSUM%3Al21289"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "fb1ffac5",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Int64Index([30, 9, 15, 74, 75, 38, 20, 41, 85, 22], dtype='int64')\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "array([<AxesSubplot:ylabel='data'>,\n",
-       "       <AxesSubplot:xlabel='Count', ylabel='data'>,\n",
-       "       <AxesSubplot:xlabel='Density', ylabel='data'>,\n",
-       "       <AxesSubplot:ylabel='data'>], dtype=object)"
-      ]
-     },
-     "execution_count": 7,
-     "metadata": {},
-     "output_type": "execute_result"
-    },
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       "<Figure size 432x288 with 4 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "pesticide_info = {\"sigma\":0.0015, \"mu\":0.006}\n",
-    "data[\"pesticide_content(mg/kg)\"] = generate_bounded_normal(data.shape[0], pesticide_info, precision=5)\n",
-    "#noisy bio products with 0 pesticides\n",
-    "random_indices = data.sample(10).index\n",
-    "print(random_indices)\n",
-    "data.loc[random_indices, \"pesticide_content(mg/kg)\"] = 0.\n",
-    "\n",
-    "data[\"pesticide_content(mg/kg)\"].cleaner.detect(\"iqr\", threshold=1.5).plot()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "id": "7eaf8a94",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "granny        26\n",
-       "golden        23\n",
-       "amarelles     19\n",
-       "bigarreaux    17\n",
-       "de Milan       8\n",
-       "de Nancy       7\n",
-       "Name: variety, dtype: int64"
-      ]
-     },
-     "execution_count": 8,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "def generate_varieties(category_series):\n",
-    "    dict_varieties = {\n",
-    "        \"pomme\" : [\"golden\", \"granny\"],\n",
-    "        \"cerise\" : [\"amarelles\", \"bigarreaux\"],\n",
-    "        \"navet\" : [\"de Milan\", \"de Nancy\"]\n",
-    "    }\n",
-    "    \n",
-    "    return category_series.apply(lambda x : random.choice(dict_varieties[x]))\n",
-    "\n",
-    "data[\"variety\"] =  generate_varieties(data.category)\n",
-    "data.variety.value_counts()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "8d94b277",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "data.to_csv(\"data/clean_data.csv\")"
-   ]
-  }
- ],
- "metadata": {
-  "kernelspec": {
-   "display_name": "Python 3",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.0"
-  },
-  "toc": {
-   "base_numbering": 1,
-   "nav_menu": {},
-   "number_sections": true,
-   "sideBar": true,
-   "skip_h1_title": false,
-   "title_cell": "Table of Contents",
-   "title_sidebar": "Contents",
-   "toc_cell": false,
-   "toc_position": {},
-   "toc_section_display": true,
-   "toc_window_display": false
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}
diff --git a/tutorials/data/clean_data.csv b/tutorials/data/clean_data.csv
deleted file mode 100644
index de7d0e1..0000000
--- a/tutorials/data/clean_data.csv
+++ /dev/null
@@ -1,101 +0,0 @@
-,category,price,diameter,weight,pesticide_content,variety
-0,navet,1.82,13.4,0.76,0.00525,de Nancy
-1,pomme,2.53,6.5,0.095,0.00571,granny
-2,pomme,2.96,6.9,0.153,0.0086,golden
-3,pomme,2.23,6.3,0.112,0.00473,granny
-4,pomme,3.18,8.9,0.304,0.0039,granny
-5,pomme,4.85,7.6,0.212,0.00567,granny
-6,pomme,4.43,6.6,0.126,0.00465,granny
-7,pomme,0.55,6.0,0.102,0.00594,granny
-8,cerise,7.3,2.7,0.006,0.0071,bigarreaux
-9,cerise,7.24,2.1,0.002,0.0,amarelles
-10,cerise,6.54,3.6,0.015,0.00992,amarelles
-11,cerise,7.1,2.4,0.005,0.00807,bigarreaux
-12,cerise,8.67,1.5,0.002,0.0064,amarelles
-13,cerise,8.28,2.6,0.007,0.00707,amarelles
-14,cerise,6.44,2.2,0.004,0.0056,bigarreaux
-15,navet,0.69,14.2,0.904,0.0,de Milan
-16,navet,0.97,9.8,0.262,0.0056,de Nancy
-17,pomme,4.17,8.1,0.247,0.00453,golden
-18,navet,2.44,6.5,0.087,0.00656,de Milan
-19,pomme,2.4,5.7,0.074,0.00831,granny
-20,pomme,3.47,7.6,0.222,0.0,granny
-21,pomme,3.45,5.9,0.073,0.00693,golden
-22,pomme,5.18,7.9,0.221,0.0,granny
-23,pomme,3.31,7.0,0.18,0.00205,granny
-24,cerise,13.15,1.7,0.002,0.00714,bigarreaux
-25,pomme,4.58,8.5,0.287,0.00651,golden
-26,cerise,9.69,1.0,0.0,0.00706,bigarreaux
-27,pomme,6.36,8.0,0.233,0.00573,granny
-28,cerise,9.12,3.7,0.017,0.00501,bigarreaux
-29,pomme,4.14,6.1,0.11,0.00528,golden
-30,cerise,9.01,1.8,0.002,0.0,amarelles
-31,cerise,7.28,2.4,0.004,0.00303,amarelles
-32,pomme,3.57,7.5,0.179,0.00611,granny
-33,pomme,2.73,7.1,0.173,0.00605,golden
-34,cerise,4.99,3.1,0.01,0.00552,bigarreaux
-35,navet,2.81,12.1,0.533,0.00474,de Nancy
-36,pomme,3.08,7.0,0.177,0.00721,golden
-37,pomme,2.24,9.4,0.361,0.00508,granny
-38,navet,1.82,4.0,0.034,0.0,de Milan
-39,navet,2.2,4.2,0.052,0.00642,de Milan
-40,pomme,3.69,5.5,0.074,0.00611,golden
-41,navet,2.42,12.1,0.545,0.0,de Milan
-42,pomme,3.07,6.6,0.128,0.00442,golden
-43,pomme,5.65,8.9,0.305,0.0016,granny
-44,pomme,5.8,5.8,0.094,0.00576,golden
-45,navet,2.53,7.7,0.156,0.00632,de Milan
-46,pomme,1.15,6.3,0.115,0.00822,granny
-47,pomme,2.48,6.4,0.101,0.00404,granny
-48,cerise,14.64,1.0,0.001,0.00569,amarelles
-49,cerise,10.61,3.4,0.013,0.00615,bigarreaux
-50,pomme,1.67,6.3,0.103,0.00502,granny
-51,pomme,0.87,7.4,0.173,0.00451,golden
-52,navet,0.79,6.2,0.069,0.00488,de Nancy
-53,pomme,4.71,7.9,0.241,0.00504,golden
-54,cerise,12.67,1.8,0.001,0.00569,bigarreaux
-55,navet,0.54,9.0,0.242,0.00504,de Nancy
-56,navet,0.46,7.6,0.131,0.00517,de Milan
-57,cerise,9.85,2.6,0.005,0.0072,bigarreaux
-58,cerise,12.41,2.8,0.008,0.00796,bigarreaux
-59,cerise,8.7,3.0,0.01,0.00501,amarelles
-60,cerise,8.96,2.1,0.003,0.00487,bigarreaux
-61,navet,2.6,6.8,0.103,0.00852,de Milan
-62,cerise,10.52,2.7,0.006,0.00364,amarelles
-63,cerise,11.13,2.4,0.005,0.00673,amarelles
-64,cerise,8.01,1.9,0.003,0.00554,amarelles
-65,navet,1.9,10.1,0.334,0.00368,de Nancy
-66,pomme,3.22,8.9,0.322,0.00497,granny
-67,pomme,3.6,6.0,0.087,0.00577,golden
-68,pomme,1.66,6.9,0.151,0.00291,golden
-69,cerise,6.52,2.1,0.002,0.00594,amarelles
-70,pomme,4.77,5.9,0.077,0.00538,golden
-71,cerise,8.22,2.6,0.005,0.00541,amarelles
-72,pomme,4.09,7.9,0.222,0.00486,golden
-73,cerise,7.85,2.7,0.006,0.00494,bigarreaux
-74,pomme,1.23,6.2,0.101,0.0,granny
-75,cerise,5.07,1.9,0.002,0.0,amarelles
-76,cerise,6.11,2.4,0.005,0.00445,amarelles
-77,pomme,0.82,6.9,0.145,0.00538,granny
-78,cerise,10.42,1.8,0.002,0.00395,bigarreaux
-79,cerise,7.8,2.6,0.005,0.00777,bigarreaux
-80,pomme,4.83,7.3,0.165,0.00342,granny
-81,pomme,2.46,6.6,0.134,0.0077,granny
-82,cerise,4.99,3.0,0.008,0.0069,amarelles
-83,navet,0.9,13.5,0.75,0.0067,de Nancy
-84,pomme,4.46,5.8,0.072,0.00404,golden
-85,pomme,1.69,6.2,0.111,0.0,granny
-86,cerise,6.77,2.6,0.005,0.00419,bigarreaux
-87,pomme,3.62,8.5,0.269,0.00597,golden
-88,pomme,4.3,7.3,0.165,0.00814,golden
-89,pomme,1.78,7.9,0.209,0.00704,golden
-90,cerise,7.87,1.7,0.001,0.00658,bigarreaux
-91,pomme,2.69,6.8,0.143,0.00627,golden
-92,cerise,8.38,2.0,0.003,0.00832,amarelles
-93,pomme,2.46,8.9,0.304,0.00848,granny
-94,pomme,3.58,8.7,0.282,0.00735,golden
-95,pomme,1.53,8.9,0.29,0.00741,granny
-96,pomme,2.05,5.9,0.07,0.00732,granny
-97,cerise,11.85,2.1,0.003,0.00502,amarelles
-98,pomme,0.49,7.1,0.157,0.00622,golden
-99,cerise,8.12,3.3,0.012,0.00632,amarelles
diff --git a/tutorials/data/fruits_data.csv b/tutorials/data/fruits_data.csv
deleted file mode 100644
index a637084..0000000
--- a/tutorials/data/fruits_data.csv
+++ /dev/null
@@ -1,101 +0,0 @@
-,category,price(euro),diameter(cm),weight(kg),pesticide_content(mg/kg),variety
-0,navet,,13.4,0.76,0.00525,de Nancy
-1,pomme,-2.53,6.5,0.095,0.00571,"granny,"
-2,pomme,2.96,6.9,0.153,0.0086,golden
-3,Pomme,2.23,63,0.112,0.00473,Granny
-4,pomme,3.18,8.9,0.304,0.0039,granny
-5,pomme,4.85,7.6,212,0.00567,granny
-6,pomme,4.43,6.6,0.126,0.00465,granny
-7,pomme,55,6,0.102,0.00594,granny
-8,cerise,7.3,2.7,0.006,0.0071,bigarrau
-9,cerise,7.24,2.1,0.002,0,amarelles
-10,cerise,6.54,3.6,0.015,0.00992,amarelles
-11,cerise,7.1,2.4,0.005,0.00807,bigarreaux
-12,cerise,8.67,1.5,0.002,0.0064,amarelles
-13,cerise,4.85,7.6,0.212,0.00567,granny
-14,cerise,644,22,4,56,bigarreaux
-15,navet,0.69,14.2,0.904,0,de Milan
-16,navet,0.97,9.8,0.262,0.0056,de Nancy
-17,pomme,4.17,8.1,0.247,0.00453,golden
-18,navet,2.44,6.5,0.087,0.00656,"de, Milan"
-19,pomme,2.4,5.7,0.074,0.00831,granny
-20,pomme,3.47,7.6,0.222,0,granny
-21,pomme,3.45,5.9,0.073,0.00693,golden
-22,pomme,5.18,7.9,0.221,0,granny
-23,pomme,3.31,7,0.18,0.00205,granny
-24,cerise,13.15,1.7,0.002,0.00714,bigarreaux
-25,pomme,4.58,8.5,0.287,0.00651,golden
-26,cerise,9.69,1,0,0.00706,bigarreaux
-27,pomme,6.36,8,0.233,0.00573,granny
-28,cerise,9.12,3.7,0.017,0.00501,bigarreaux
-29,pomme,4.14,6.1,0.11,0.00528,golden2
-30,cerise,9.01,1.8,0.002,0,amarelles
-31,cerise,7.28,2.4,0.004,0.00303,amarelles
-32,pomme,3.57,7.5,0.179,0.00611,granny
-33,pomme,2.73,7.1,0.173,0.00605,golden
-34,cerise,4.99,7,0.01,0.00552,bigarreaux
-35,navet,2.81,12.1,0.533,0.00474,de Nancy
-36,pomme,3.08,7,0.177,0.00721,golden
-37,pomme,2.24,9.4,0.7,0.00508,granny
-38,navet,1.82,4,0.034,0,de.Milan
-39,navet,2.2,4.2,0.052,0.00642,de Milan
-40,pomme,3.69,5.5,0.074,0.00611,golden
-41,navet,2.42,12.1,0.545,0,de milan
-42,pomme,3.07,6.6,0.128,0.00442,golden
-43,pomme,-5.65,8.9,0.305,0.0016,granny
-44,pomme,5.8,5.8,0.094,0.00576,golden
-45,navet,2.53,7.7,0.156,0.00632,Milan de
-46,pomme,1.15,6.3,0.115,0.00822,granny
-47,pomme,2.48,6.4,0.101,0.00404,granny
-48,cerise,14.64,1,0.001,0.00569,amarelles
-49,cerise,10.61,3.4,0.013,0.00615,bigarreaux
-50,pomme,1.67,6.3,0.103,0.00502,granny
-51,pomme,0.87,7.4,0.173,0.00451,golden
-52,navet,0.79,6.2,0.069,0.00488,de Nancy
-53,pomme,4.71,7.9,0.241,0.00504,golden
-54,cerise,12.67,1.8,0.001,0.00569,bigarreaux
-55,navet,0.54,9,0.242,0.00504,DE NANCY
-56,navet,0.46,7.6,0.131,0.00517,de Milan
-57,cerise,9.85,2.6,0.005,0.0072,bigarreaux
-58,cerise,12.41,2.8,0.008,0.00796,bigarreaux
-59,cerise,8.7,3,0.01,0.00501,amarelles
-60,cerise,8.96,2.1,0.003,0.00487,bigarreaux
-61,navet,2.6,6.8,-0.103,0.00852,de Milan
-62,cerise,10.52,2.7,0.006,0.00364,amarelles
-63,cerise,11.13,2.4,0.005,0.00673,amarelles
-64,cerise,8.01,1.9,0.003,0.00554,amarelles
-65,navet,1.9,10.1,0.334,0.00368,de Nancy
-66,pomme,3.22,8.9,0.322,0.00497,granny
-67,pomme,3.6,6,0.087,0.00577,golden
-68,pomme,1.66,6.9,-0.151,0.00291,golden
-69,cerise,6.52,2.1,0.002,0.00594,amarelles
-70,pomme,4.77,5.9,0.077,0.00538,golden
-71,cerise,8.22,2.6,0.005,0.00541,amarelles
-72,pomme,4.09,7.9,0.222,0.00486,golden
-73,cerise,7.85,2.7,0.06,0.00494,bigarreaux
-74,pomme,1.23,6.2,0.101,0,granny
-75,cerise,-5.07,1.9,0.002,0,amarelles
-76,cerise,6.11,2.4,0.005,0.000445,amarelles
-77,pomme,0.82,6.9,0.145,0.00538,granny
-78,cerise,10.42,1.8,0.002,0.00395,bigarreaux
-79,cerise,7.8,2.6,0.005,0.00777,bigarreaux
-80,pomme,4.83,7.3,0.165,0.00342,granny
-81,pomme,2.46,6.6,0.134,0.0077,granny
-82,cerise,4.99,3,0.008,0.0069,amarelles
-83,navet,0.9,13.5,0.75,0.0067,de Nancy
-84,pomme,4.46,5.8,0.072,0.00404,golden
-85,pomme,1.69,6.2,0.111,0,granny
-86,cerise,6.77,2.6,0.005,0.00419,bigarreaux
-87,pomme,3.62,8.5,0.269,0.00597,golden
-88,pomme,4.3,7.3,0.165,0.000814,golden
-89,pomme,1.78,7.9,0.209,0.00704,golden
-90,cerise,7.87,1.7,0.001,0.011,bigarreaux
-91,pomme,2.69,6.8,0.143,0.00627,golden
-92,cerise,8.38,2,0.003,0.00832,amarelles
-93,pomme,2.46,8.9,0.304,0.00848,granny
-94,pomme,3.58,8.7,0.282,0.00735,golden
-95,pomme,1.53,8.9,0.29,0.00741,granny
-96,pomme,-2.05,5.9,0.07,0.00732,granny
-97,cerise,11.85,2.1,0.003,0.00502,amarelles
-98,pomme,0.49,7.1,0.157,0.00622,golden
-99,cerise,8.12,3.3,0.012,0.00632,amarelles
diff --git a/tutorials/data/fruits_data.xlsx b/tutorials/data/fruits_data.xlsx
deleted file mode 100644
index d9c8a08..0000000
Binary files a/tutorials/data/fruits_data.xlsx and /dev/null differ
diff --git a/tutorials/tutorial.ipynb b/tutorials/tutorial.ipynb
deleted file mode 100644
index 406afd8..0000000
--- a/tutorials/tutorial.ipynb
+++ /dev/null
@@ -1,3067 +0,0 @@
-{
- "cells": [
-  {
-   "cell_type": "markdown",
-   "id": "af35f83a",
-   "metadata": {},
-   "source": [
-    "# Pandas Cleaner Tutorial "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "326897f3",
-   "metadata": {},
-   "source": [
-    "Welcome To pandas-cleaner tutorial. \n",
-    "\n",
-    "This notebook presents the main features offered by the pandas-cleaner package through simple examples."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 68,
-   "id": "fd068446",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "%reload_ext autoreload\n",
-    "%autoreload 2\n",
-    "\n",
-    "try:\n",
-    "    import pdcleaner\n",
-    "except ModuleNotFoundError:\n",
-    "    print(\"extended path variable\")\n",
-    "    import sys\n",
-    "    sys.path.append('..')\n",
-    "    import pdcleaner"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 69,
-   "id": "3bf04140",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "import pandas as pd\n",
-    "import numpy as np\n",
-    "import matplotlib.pyplot as plt\n",
-    "\n",
-    "np.random.seed(seed=0)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 75,
-   "id": "d1f7f569-d7c2-4935-8aaa-47affdb1d9c5",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "0     True\n",
-       "1    False\n",
-       "2     True\n",
-       "3    False\n",
-       "dtype: bool"
-      ]
-     },
-     "execution_count": 75,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "my_series = pd.Series(['2022-10-01', '2021-06-11', '2019-04-03',' 2020-09-25'])\n",
-    "my_series= pd.to_datetime(my_series)\n",
-    "my_detector = my_series.cleaner.detect.date_range(lower='2020-06-15', upper='2022-08-05')\n",
-    "my_detector.is_error()\n"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 76,
-   "id": "965b7220-3a14-465f-a713-2eba8ea2af25",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "                               Detection report                               \n",
-      "==============================================================================\n",
-      "Method:                   date_range      Nb samples:                        4\n",
-      "Date:                  March 31,2022      Nb errors:                         2\n",
-      "Time:                       16:29:24      Nb rows with NaN:                  0\n",
-      "------------------------------------------------------------------------------\n",
-      "lower                     2020-06-15      upper                     2022-08-05\n",
-      "inclusive                       both      \n",
-      "==============================================================================\n"
-     ]
-    }
-   ],
-   "source": [
-    "my_detector.report()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 67,
-   "id": "f6bd2db5-6971-4ec2-b4d4-0f459ee63a2a",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "Timestamp('1677-09-21 00:12:43.145224193')"
-      ]
-     },
-     "execution_count": 67,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "import datetime\n",
-    "pd.Timestamp.min"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 66,
-   "id": "388cdb7d-d465-4362-8852-c27c67c1791c",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "pandas.core.indexes.datetimes.DatetimeIndex"
-      ]
-     },
-     "execution_count": 66,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": []
-  },
-  {
-   "cell_type": "markdown",
-   "id": "e8217c44",
-   "metadata": {},
-   "source": [
-    "## The data"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "638b7686",
-   "metadata": {},
-   "source": [
-    "In this tutorial, we will be using a small dataset represnting some round fruits/vegetables. Each entry figures the type of product, its price, its diameter, its weight, its family and its pesticide content. \n",
-    "\n",
-    "The data used in this tutorial is an artificial dataset. To produce the dataset, we, first, created an initial dataset using the notebook *create_data.ipynb* (c.f. *clean_data.csv*). Then, additional errors were manually introduced to produce *data.csv*. "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 3,
-   "id": "e199bc69",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "data = pd.read_csv(\"data/fruits_data.csv\", index_col=0)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 4,
-   "id": "22d93d8d",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price(euro)</th>\n",
-       "      <th>diameter(cm)</th>\n",
-       "      <th>weight(kg)</th>\n",
-       "      <th>pesticide_content(mg/kg)</th>\n",
-       "      <th>variety</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>0</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>NaN</td>\n",
-       "      <td>13.4</td>\n",
-       "      <td>0.760</td>\n",
-       "      <td>0.00525</td>\n",
-       "      <td>de Nancy</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>1</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>-2.53</td>\n",
-       "      <td>6.5</td>\n",
-       "      <td>0.095</td>\n",
-       "      <td>0.00571</td>\n",
-       "      <td>granny,</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>2</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.96</td>\n",
-       "      <td>6.9</td>\n",
-       "      <td>0.153</td>\n",
-       "      <td>0.00860</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>3</th>\n",
-       "      <td>Pomme</td>\n",
-       "      <td>2.23</td>\n",
-       "      <td>63.0</td>\n",
-       "      <td>0.112</td>\n",
-       "      <td>0.00473</td>\n",
-       "      <td>Granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>4</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.18</td>\n",
-       "      <td>8.9</td>\n",
-       "      <td>0.304</td>\n",
-       "      <td>0.00390</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>5</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.85</td>\n",
-       "      <td>7.6</td>\n",
-       "      <td>212.000</td>\n",
-       "      <td>0.00567</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>6</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.43</td>\n",
-       "      <td>6.6</td>\n",
-       "      <td>0.126</td>\n",
-       "      <td>0.00465</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>7</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>55.00</td>\n",
-       "      <td>6.0</td>\n",
-       "      <td>0.102</td>\n",
-       "      <td>0.00594</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>8</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>7.30</td>\n",
-       "      <td>2.7</td>\n",
-       "      <td>0.006</td>\n",
-       "      <td>0.00710</td>\n",
-       "      <td>bigarrau</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>9</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>7.24</td>\n",
-       "      <td>2.1</td>\n",
-       "      <td>0.002</td>\n",
-       "      <td>0.00000</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "  category  price(euro)  diameter(cm)  weight(kg)  pesticide_content(mg/kg)  \\\n",
-       "0    navet          NaN          13.4       0.760                   0.00525   \n",
-       "1    pomme        -2.53           6.5       0.095                   0.00571   \n",
-       "2    pomme         2.96           6.9       0.153                   0.00860   \n",
-       "3    Pomme         2.23          63.0       0.112                   0.00473   \n",
-       "4    pomme         3.18           8.9       0.304                   0.00390   \n",
-       "5    pomme         4.85           7.6     212.000                   0.00567   \n",
-       "6    pomme         4.43           6.6       0.126                   0.00465   \n",
-       "7    pomme        55.00           6.0       0.102                   0.00594   \n",
-       "8   cerise         7.30           2.7       0.006                   0.00710   \n",
-       "9   cerise         7.24           2.1       0.002                   0.00000   \n",
-       "\n",
-       "     variety  \n",
-       "0   de Nancy  \n",
-       "1    granny,  \n",
-       "2     golden  \n",
-       "3     Granny  \n",
-       "4     granny  \n",
-       "5     granny  \n",
-       "6     granny  \n",
-       "7     granny  \n",
-       "8   bigarrau  \n",
-       "9  amarelles  "
-      ]
-     },
-     "execution_count": 4,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "data.head(10)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b9f0f4cb",
-   "metadata": {},
-   "source": [
-    "These few 10 rows of the dataset already contain 9 errors. Can you spot them ?"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "736796a7",
-   "metadata": {},
-   "source": [
-    "Over these few first rows, we observe that there are multiple errors in the dataset.\n",
-    "For instance:\n",
-    "- The first row, describes a turnip (un navet) which is a vegetable and, therefore, should not be included in a dataset of fruits. \n",
-    "- The second row, contains two errors: \n",
-    "    - On one hand, the indicated price is negative.\n",
-    "    - On the other hand, the variety contains a comma.\n",
-    "- The fourth row, contains three errors: \n",
-    "    - First, unlike other entries, \"Pomme\" is spelled with a capital p.\n",
-    "    - Second, this row indicates an apple (une pomme) whose diameter is 63cm which is clearly an error (maybe it was meant to be in mm).\n",
-    "    - Finally, \"Granny\" starts with a capital letter unlike other entries of the variety column.\n",
-    "- Row 6 describes a giant apple whose weight is 212 kg.\n",
-    "- Row 8 indicates a price of 55€ for a kg of apples.\n",
-    "- Finally, \"bigarreaux\" is missplled as \"bigarrau\" in row 9.\n",
-    "    \n",
-    "It is clear that even for such a small dataset, spotting and correcting the errors is hard to do. So, one can only imagine how tedious it can be when large datasets are involved."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "be3d2b36",
-   "metadata": {},
-   "source": [
-    "## Basic Usage"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "08192c79",
-   "metadata": {},
-   "source": [
-    "The package offers three main functionalities :\n",
-    "- Detecting potential errors in pandas dataframes\n",
-    "- Analysing the detected errors\n",
-    "- Cleaning the detected errors"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "58c6c582",
-   "metadata": {},
-   "source": [
-    "The following example considers the previously introduced dataset. \n",
-    "\n",
-    "Here is a typical call sequence to pandas-cleaner:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 5,
-   "id": "288cba5d",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       "<Figure size 432x288 with 4 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    },
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price(euro)</th>\n",
-       "      <th>diameter(cm)</th>\n",
-       "      <th>weight(kg)</th>\n",
-       "      <th>pesticide_content(mg/kg)</th>\n",
-       "      <th>variety</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>0</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>NaN</td>\n",
-       "      <td>13.4</td>\n",
-       "      <td>0.760</td>\n",
-       "      <td>0.00525</td>\n",
-       "      <td>de Nancy</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>2</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.96</td>\n",
-       "      <td>6.9</td>\n",
-       "      <td>0.153</td>\n",
-       "      <td>0.00860</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>3</th>\n",
-       "      <td>Pomme</td>\n",
-       "      <td>2.23</td>\n",
-       "      <td>63.0</td>\n",
-       "      <td>0.112</td>\n",
-       "      <td>0.00473</td>\n",
-       "      <td>Granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>4</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.18</td>\n",
-       "      <td>8.9</td>\n",
-       "      <td>0.304</td>\n",
-       "      <td>0.00390</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>5</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.85</td>\n",
-       "      <td>7.6</td>\n",
-       "      <td>212.000</td>\n",
-       "      <td>0.00567</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>...</th>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>94</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.58</td>\n",
-       "      <td>8.7</td>\n",
-       "      <td>0.282</td>\n",
-       "      <td>0.00735</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>95</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>1.53</td>\n",
-       "      <td>8.9</td>\n",
-       "      <td>0.290</td>\n",
-       "      <td>0.00741</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>97</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>11.85</td>\n",
-       "      <td>2.1</td>\n",
-       "      <td>0.003</td>\n",
-       "      <td>0.00502</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>98</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>0.49</td>\n",
-       "      <td>7.1</td>\n",
-       "      <td>0.157</td>\n",
-       "      <td>0.00622</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>99</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>8.12</td>\n",
-       "      <td>3.3</td>\n",
-       "      <td>0.012</td>\n",
-       "      <td>0.00632</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "<p>94 rows × 6 columns</p>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "   category  price(euro)  diameter(cm)  weight(kg)  pesticide_content(mg/kg)  \\\n",
-       "0     navet          NaN          13.4       0.760                   0.00525   \n",
-       "2     pomme         2.96           6.9       0.153                   0.00860   \n",
-       "3     Pomme         2.23          63.0       0.112                   0.00473   \n",
-       "4     pomme         3.18           8.9       0.304                   0.00390   \n",
-       "5     pomme         4.85           7.6     212.000                   0.00567   \n",
-       "..      ...          ...           ...         ...                       ...   \n",
-       "94    pomme         3.58           8.7       0.282                   0.00735   \n",
-       "95    pomme         1.53           8.9       0.290                   0.00741   \n",
-       "97   cerise        11.85           2.1       0.003                   0.00502   \n",
-       "98    pomme         0.49           7.1       0.157                   0.00622   \n",
-       "99   cerise         8.12           3.3       0.012                   0.00632   \n",
-       "\n",
-       "      variety  \n",
-       "0    de Nancy  \n",
-       "2      golden  \n",
-       "3      Granny  \n",
-       "4      granny  \n",
-       "5      granny  \n",
-       "..        ...  \n",
-       "94     golden  \n",
-       "95     granny  \n",
-       "97  amarelles  \n",
-       "98     golden  \n",
-       "99  amarelles  \n",
-       "\n",
-       "[94 rows x 6 columns]"
-      ]
-     },
-     "execution_count": 5,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# detect errors\n",
-    "detector = data[\"price(euro)\"].cleaner.detect('bounded', lower=0., upper=20.)\n",
-    "#alternatively, detector = data[\"price(euro)\"].cleaner.detect.bounded(lower=0., upper=20.)\n",
-    "\n",
-    "# visualize the errors\n",
-    "detector.plot(compact=True)\n",
-    "plt.show()\n",
-    "\n",
-    "#clean the dataframe\n",
-    "cleaner_df = data.cleaner.clean(detector_obj=detector, method=\"drop\")\n",
-    "#alternativey, cleaner_df = data.cleaner.clean.drop(detector_obj=detector)\n",
-    "cleaner_df"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "fb1ab18b",
-   "metadata": {},
-   "source": [
-    "### Train and Test Data"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ec0c133c",
-   "metadata": {},
-   "source": [
-    "If we have two distinct datasets : a train set and a test set, we can transfer the knowledge we have learnt from the initial train data to clean the test data:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 6,
-   "id": "8d8fbeb5",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "def split_data(all_data_df, train_fraction, random_state=None):\n",
-    "    if not ( 0 < train_fraction < 1):\n",
-    "        raise ValueError(\"train_fraction must be strictly between 0 and 1\")\n",
-    "    \n",
-    "    shuffle_df = all_data_df.sample(frac=1, random_state=random_state)\n",
-    "\n",
-    "    train_size = int(train_fraction * len(all_data_df))\n",
-    "\n",
-    "    train_set = shuffle_df[:train_size].copy(deep=True)\n",
-    "    test_set = shuffle_df[train_size:].copy(deep=True)\n",
-    "    \n",
-    "    return train_set, test_set\n",
-    "\n",
-    "train_df, test_df = split_data(data, train_fraction=0.8, random_state=0)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 7,
-   "id": "240eaa70",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price(euro)</th>\n",
-       "      <th>diameter(cm)</th>\n",
-       "      <th>weight(kg)</th>\n",
-       "      <th>pesticide_content(mg/kg)</th>\n",
-       "      <th>variety</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>26</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>9.69</td>\n",
-       "      <td>1.0</td>\n",
-       "      <td>0.000</td>\n",
-       "      <td>0.00706</td>\n",
-       "      <td>bigarreaux</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>86</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>6.77</td>\n",
-       "      <td>2.6</td>\n",
-       "      <td>0.005</td>\n",
-       "      <td>0.00419</td>\n",
-       "      <td>bigarreaux</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>2</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.96</td>\n",
-       "      <td>6.9</td>\n",
-       "      <td>0.153</td>\n",
-       "      <td>0.00860</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>55</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>0.54</td>\n",
-       "      <td>9.0</td>\n",
-       "      <td>0.242</td>\n",
-       "      <td>0.00504</td>\n",
-       "      <td>DE NANCY</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>75</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>-5.07</td>\n",
-       "      <td>1.9</td>\n",
-       "      <td>0.002</td>\n",
-       "      <td>0.00000</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "   category  price(euro)  diameter(cm)  weight(kg)  pesticide_content(mg/kg)  \\\n",
-       "26   cerise         9.69           1.0       0.000                   0.00706   \n",
-       "86   cerise         6.77           2.6       0.005                   0.00419   \n",
-       "2     pomme         2.96           6.9       0.153                   0.00860   \n",
-       "55    navet         0.54           9.0       0.242                   0.00504   \n",
-       "75   cerise        -5.07           1.9       0.002                   0.00000   \n",
-       "\n",
-       "       variety  \n",
-       "26  bigarreaux  \n",
-       "86  bigarreaux  \n",
-       "2       golden  \n",
-       "55    DE NANCY  \n",
-       "75   amarelles  "
-      ]
-     },
-     "execution_count": 7,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "train_df.head(5)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 8,
-   "id": "de18315f",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price(euro)</th>\n",
-       "      <th>diameter(cm)</th>\n",
-       "      <th>weight(kg)</th>\n",
-       "      <th>pesticide_content(mg/kg)</th>\n",
-       "      <th>variety</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>25</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.58</td>\n",
-       "      <td>8.5</td>\n",
-       "      <td>0.287</td>\n",
-       "      <td>0.00651</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>37</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.24</td>\n",
-       "      <td>9.4</td>\n",
-       "      <td>0.700</td>\n",
-       "      <td>0.00508</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>81</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.46</td>\n",
-       "      <td>6.6</td>\n",
-       "      <td>0.134</td>\n",
-       "      <td>0.00770</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>46</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>1.15</td>\n",
-       "      <td>6.3</td>\n",
-       "      <td>0.115</td>\n",
-       "      <td>0.00822</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>39</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>2.20</td>\n",
-       "      <td>4.2</td>\n",
-       "      <td>0.052</td>\n",
-       "      <td>0.00642</td>\n",
-       "      <td>de Milan</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "   category  price(euro)  diameter(cm)  weight(kg)  pesticide_content(mg/kg)  \\\n",
-       "25    pomme         4.58           8.5       0.287                   0.00651   \n",
-       "37    pomme         2.24           9.4       0.700                   0.00508   \n",
-       "81    pomme         2.46           6.6       0.134                   0.00770   \n",
-       "46    pomme         1.15           6.3       0.115                   0.00822   \n",
-       "39    navet         2.20           4.2       0.052                   0.00642   \n",
-       "\n",
-       "     variety  \n",
-       "25    golden  \n",
-       "37    granny  \n",
-       "81    granny  \n",
-       "46    granny  \n",
-       "39  de Milan  "
-      ]
-     },
-     "execution_count": 8,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "test_df.head(5)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "0ca6c33b",
-   "metadata": {},
-   "source": [
-    "Parametrising (fitting) the detector according to the train data."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 9,
-   "id": "485f3e16",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "shape of train data (80, 6)\n",
-      "computed bounds : 0.0013362499999999998, 0.009406250000000001\n",
-      "75     0.000000\n",
-      "30     0.000000\n",
-      "22     0.000000\n",
-      "76     0.000445\n",
-      "90     0.011000\n",
-      "74     0.000000\n",
-      "41     0.000000\n",
-      "15     0.000000\n",
-      "38     0.000000\n",
-      "10     0.009920\n",
-      "85     0.000000\n",
-      "14    56.000000\n",
-      "20     0.000000\n",
-      "Name: pesticide_content(mg/kg), dtype: float64\n",
-      "new shape of train data (67, 6)\n"
-     ]
-    },
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price(euro)</th>\n",
-       "      <th>diameter(cm)</th>\n",
-       "      <th>weight(kg)</th>\n",
-       "      <th>pesticide_content(mg/kg)</th>\n",
-       "      <th>variety</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>26</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>9.69</td>\n",
-       "      <td>1.0</td>\n",
-       "      <td>0.000</td>\n",
-       "      <td>0.00706</td>\n",
-       "      <td>bigarreaux</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>86</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>6.77</td>\n",
-       "      <td>2.6</td>\n",
-       "      <td>0.005</td>\n",
-       "      <td>0.00419</td>\n",
-       "      <td>bigarreaux</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>2</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.96</td>\n",
-       "      <td>6.9</td>\n",
-       "      <td>0.153</td>\n",
-       "      <td>0.00860</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>55</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>0.54</td>\n",
-       "      <td>9.0</td>\n",
-       "      <td>0.242</td>\n",
-       "      <td>0.00504</td>\n",
-       "      <td>DE NANCY</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>93</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.46</td>\n",
-       "      <td>8.9</td>\n",
-       "      <td>0.304</td>\n",
-       "      <td>0.00848</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>...</th>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "      <td>...</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>98</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>0.49</td>\n",
-       "      <td>7.1</td>\n",
-       "      <td>0.157</td>\n",
-       "      <td>0.00622</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>69</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>6.52</td>\n",
-       "      <td>2.1</td>\n",
-       "      <td>0.002</td>\n",
-       "      <td>0.00594</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>94</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.58</td>\n",
-       "      <td>8.7</td>\n",
-       "      <td>0.282</td>\n",
-       "      <td>0.00735</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>72</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.09</td>\n",
-       "      <td>7.9</td>\n",
-       "      <td>0.222</td>\n",
-       "      <td>0.00486</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>77</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>0.82</td>\n",
-       "      <td>6.9</td>\n",
-       "      <td>0.145</td>\n",
-       "      <td>0.00538</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "<p>67 rows × 6 columns</p>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "   category  price(euro)  diameter(cm)  weight(kg)  pesticide_content(mg/kg)  \\\n",
-       "26   cerise         9.69           1.0       0.000                   0.00706   \n",
-       "86   cerise         6.77           2.6       0.005                   0.00419   \n",
-       "2     pomme         2.96           6.9       0.153                   0.00860   \n",
-       "55    navet         0.54           9.0       0.242                   0.00504   \n",
-       "93    pomme         2.46           8.9       0.304                   0.00848   \n",
-       "..      ...          ...           ...         ...                       ...   \n",
-       "98    pomme         0.49           7.1       0.157                   0.00622   \n",
-       "69   cerise         6.52           2.1       0.002                   0.00594   \n",
-       "94    pomme         3.58           8.7       0.282                   0.00735   \n",
-       "72    pomme         4.09           7.9       0.222                   0.00486   \n",
-       "77    pomme         0.82           6.9       0.145                   0.00538   \n",
-       "\n",
-       "       variety  \n",
-       "26  bigarreaux  \n",
-       "86  bigarreaux  \n",
-       "2       golden  \n",
-       "55    DE NANCY  \n",
-       "93      granny  \n",
-       "..         ...  \n",
-       "98      golden  \n",
-       "69   amarelles  \n",
-       "94      golden  \n",
-       "72      golden  \n",
-       "77      granny  \n",
-       "\n",
-       "[67 rows x 6 columns]"
-      ]
-     },
-     "execution_count": 9,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# on train set\n",
-    "print(f\"shape of train data {train_df.shape}\")\n",
-    "train_detector = train_df[\"pesticide_content(mg/kg)\"].cleaner.detect('iqr')\n",
-    "print(f\"computed bounds : {train_detector.lower}, {train_detector.upper}\")\n",
-    "#print(\"plot...\")\n",
-    "#train_detector.plot()\n",
-    "#plt.show()\n",
-    "print(train_detector.detected)\n",
-    "train_df.cleaner.clean(\"drop\", train_detector, inplace=True)\n",
-    "print(f\"new shape of train data {train_df.shape}\")\n",
-    "train_df"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "9a2c168f",
-   "metadata": {},
-   "source": [
-    "transferring the parameters to the testing detector. "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 10,
-   "id": "f43bd45c",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "shape of test data (20, 6)\n",
-      "plot...\n"
-     ]
-    },
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       "<Figure size 432x288 with 4 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    },
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "88    0.000814\n",
-      "9     0.000000\n",
-      "Name: pesticide_content(mg/kg), dtype: float64\n",
-      "new shape of test data (18, 6)\n"
-     ]
-    },
-    {
-     "data": {
-      "text/html": [
-       "<div>\n",
-       "<style scoped>\n",
-       "    .dataframe tbody tr th:only-of-type {\n",
-       "        vertical-align: middle;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe tbody tr th {\n",
-       "        vertical-align: top;\n",
-       "    }\n",
-       "\n",
-       "    .dataframe thead th {\n",
-       "        text-align: right;\n",
-       "    }\n",
-       "</style>\n",
-       "<table border=\"1\" class=\"dataframe\">\n",
-       "  <thead>\n",
-       "    <tr style=\"text-align: right;\">\n",
-       "      <th></th>\n",
-       "      <th>category</th>\n",
-       "      <th>price(euro)</th>\n",
-       "      <th>diameter(cm)</th>\n",
-       "      <th>weight(kg)</th>\n",
-       "      <th>pesticide_content(mg/kg)</th>\n",
-       "      <th>variety</th>\n",
-       "    </tr>\n",
-       "  </thead>\n",
-       "  <tbody>\n",
-       "    <tr>\n",
-       "      <th>25</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.58</td>\n",
-       "      <td>8.5</td>\n",
-       "      <td>0.287</td>\n",
-       "      <td>0.00651</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>37</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.24</td>\n",
-       "      <td>9.4</td>\n",
-       "      <td>0.700</td>\n",
-       "      <td>0.00508</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>81</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.46</td>\n",
-       "      <td>6.6</td>\n",
-       "      <td>0.134</td>\n",
-       "      <td>0.00770</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>46</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>1.15</td>\n",
-       "      <td>6.3</td>\n",
-       "      <td>0.115</td>\n",
-       "      <td>0.00822</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>39</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>2.20</td>\n",
-       "      <td>4.2</td>\n",
-       "      <td>0.052</td>\n",
-       "      <td>0.00642</td>\n",
-       "      <td>de Milan</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>65</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>1.90</td>\n",
-       "      <td>10.1</td>\n",
-       "      <td>0.334</td>\n",
-       "      <td>0.00368</td>\n",
-       "      <td>de Nancy</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>58</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>12.41</td>\n",
-       "      <td>2.8</td>\n",
-       "      <td>0.008</td>\n",
-       "      <td>0.00796</td>\n",
-       "      <td>bigarreaux</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>12</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>8.67</td>\n",
-       "      <td>1.5</td>\n",
-       "      <td>0.002</td>\n",
-       "      <td>0.00640</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>70</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>4.77</td>\n",
-       "      <td>5.9</td>\n",
-       "      <td>0.077</td>\n",
-       "      <td>0.00538</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>87</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.62</td>\n",
-       "      <td>8.5</td>\n",
-       "      <td>0.269</td>\n",
-       "      <td>0.00597</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>36</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.08</td>\n",
-       "      <td>7.0</td>\n",
-       "      <td>0.177</td>\n",
-       "      <td>0.00721</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>21</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.45</td>\n",
-       "      <td>5.9</td>\n",
-       "      <td>0.073</td>\n",
-       "      <td>0.00693</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>83</th>\n",
-       "      <td>navet</td>\n",
-       "      <td>0.90</td>\n",
-       "      <td>13.5</td>\n",
-       "      <td>0.750</td>\n",
-       "      <td>0.00670</td>\n",
-       "      <td>de Nancy</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>96</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>-2.05</td>\n",
-       "      <td>5.9</td>\n",
-       "      <td>0.070</td>\n",
-       "      <td>0.00732</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>67</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>3.60</td>\n",
-       "      <td>6.0</td>\n",
-       "      <td>0.087</td>\n",
-       "      <td>0.00577</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>64</th>\n",
-       "      <td>cerise</td>\n",
-       "      <td>8.01</td>\n",
-       "      <td>1.9</td>\n",
-       "      <td>0.003</td>\n",
-       "      <td>0.00554</td>\n",
-       "      <td>amarelles</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>47</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>2.48</td>\n",
-       "      <td>6.4</td>\n",
-       "      <td>0.101</td>\n",
-       "      <td>0.00404</td>\n",
-       "      <td>granny</td>\n",
-       "    </tr>\n",
-       "    <tr>\n",
-       "      <th>44</th>\n",
-       "      <td>pomme</td>\n",
-       "      <td>5.80</td>\n",
-       "      <td>5.8</td>\n",
-       "      <td>0.094</td>\n",
-       "      <td>0.00576</td>\n",
-       "      <td>golden</td>\n",
-       "    </tr>\n",
-       "  </tbody>\n",
-       "</table>\n",
-       "</div>"
-      ],
-      "text/plain": [
-       "   category  price(euro)  diameter(cm)  weight(kg)  pesticide_content(mg/kg)  \\\n",
-       "25    pomme         4.58           8.5       0.287                   0.00651   \n",
-       "37    pomme         2.24           9.4       0.700                   0.00508   \n",
-       "81    pomme         2.46           6.6       0.134                   0.00770   \n",
-       "46    pomme         1.15           6.3       0.115                   0.00822   \n",
-       "39    navet         2.20           4.2       0.052                   0.00642   \n",
-       "65    navet         1.90          10.1       0.334                   0.00368   \n",
-       "58   cerise        12.41           2.8       0.008                   0.00796   \n",
-       "12   cerise         8.67           1.5       0.002                   0.00640   \n",
-       "70    pomme         4.77           5.9       0.077                   0.00538   \n",
-       "87    pomme         3.62           8.5       0.269                   0.00597   \n",
-       "36    pomme         3.08           7.0       0.177                   0.00721   \n",
-       "21    pomme         3.45           5.9       0.073                   0.00693   \n",
-       "83    navet         0.90          13.5       0.750                   0.00670   \n",
-       "96    pomme        -2.05           5.9       0.070                   0.00732   \n",
-       "67    pomme         3.60           6.0       0.087                   0.00577   \n",
-       "64   cerise         8.01           1.9       0.003                   0.00554   \n",
-       "47    pomme         2.48           6.4       0.101                   0.00404   \n",
-       "44    pomme         5.80           5.8       0.094                   0.00576   \n",
-       "\n",
-       "       variety  \n",
-       "25      golden  \n",
-       "37      granny  \n",
-       "81      granny  \n",
-       "46      granny  \n",
-       "39    de Milan  \n",
-       "65    de Nancy  \n",
-       "58  bigarreaux  \n",
-       "12   amarelles  \n",
-       "70      golden  \n",
-       "87      golden  \n",
-       "36      golden  \n",
-       "21      golden  \n",
-       "83    de Nancy  \n",
-       "96      granny  \n",
-       "67      golden  \n",
-       "64   amarelles  \n",
-       "47      granny  \n",
-       "44      golden  "
-      ]
-     },
-     "execution_count": 10,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "#on test set\n",
-    "print(f\"shape of test data {test_df.shape}\")\n",
-    "test_detector = test_df[\"pesticide_content(mg/kg)\"].cleaner.detect(train_detector)\n",
-    "print(\"plot...\")\n",
-    "test_detector.plot()\n",
-    "plt.show()\n",
-    "print(test_detector.detected)\n",
-    "test_df.cleaner.clean(\"drop\", test_detector, inplace=True)\n",
-    "print(f\"new shape of test data {test_df.shape}\")\n",
-    "test_df"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "104ccab1",
-   "metadata": {},
-   "source": [
-    "Note that the bounds indicated on the plot concerning test data are the same bounds we have computed on the train set.\n",
-    "\n",
-    "If we had simply created a new 'iqr' detector, the bounds would have been recalculated using only the test data. "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "349525b4",
-   "metadata": {},
-   "source": [
-    "## Detecttion"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "9f290510",
-   "metadata": {},
-   "source": [
-    "Detection refers to identifiying the entries that are invalid in the data. \n",
-    "Multiple Detector objects and detection methods are available in pandas-cleaner to allow for the detection of different types of errors.\n",
-    "\n",
-    "The first step in the detection process is to initialize a detector object that will detect the errors present in the Series. This step is performed using the detect() method. Actually, the detect method simply instantiates a detector objects. The actual detection is performed each time a query is executed.\n",
-    "\n",
-    "Here's how :\n",
-    "```(python)\n",
-    "<series>.cleaner.detect(<detector_name>, <detector_params>)\n",
-    "```\n",
-    "\n",
-    "or alternatively:\n",
-    "```(python)\n",
-    "<series>.cleaner.detect.<detector_name>(<detector_params>)\n",
-    "```\n",
-    "\n",
-    "The method returns an error if the detection method is not recognized.\n",
-    "\n",
-    "Hereafter, we use a bounded detector as a simple illustration example.\n",
-    "\n",
-    "Please note that nan values are considered as legitimate values and are not reported as errors."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "472d0442",
-   "metadata": {},
-   "source": [
-    "### Numerical Data"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6ebe17ba",
-   "metadata": {},
-   "source": [
-    "For now, pandas-cleaner handles two types of numerical data:\n",
-    "- bounded distributions\n",
-    "- Gaussian distributions"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "a7104d94",
-   "metadata": {},
-   "source": [
-    "#### Bounded Values"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "adc97390",
-   "metadata": {},
-   "source": [
-    "The bounded detection method detects values from a series that are out of some specified bounds. By default, the bounds are set to -inf and +inf.\n",
-    "\n",
-    "In the considered dataset, the price column contains different values. We already observed that some of these values are negative. One can suppose that the prices must be in a specific range. Say, for example, between 0 and 30.\n",
-    "\n",
-    "If we set a lower bound to 0 and an upper bound to 30, negative prices will be flagged as errors so are prices higher than 30€."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 11,
-   "id": "57382ab9",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1      -2.53\n",
-       "7      55.00\n",
-       "14    644.00\n",
-       "43     -5.65\n",
-       "75     -5.07\n",
-       "96     -2.05\n",
-       "Name: price(euro), dtype: float64"
-      ]
-     },
-     "execution_count": 11,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "bounded_detector = data[\"price(euro)\"].cleaner.detect('bounded', lower=0., upper=30)\n",
-    "#alternatively:\n",
-    "# bounded_detector = data[\"price(euro)\"].cleaner.detect.bounded(lower=0., upper=30)\n",
-    "\n",
-    "bounded_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "00c12c63",
-   "metadata": {},
-   "source": [
-    "#### Gaussian Distribution"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 12,
-   "id": "87534013",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "s_gaussian = data[\"pesticide_content(mg/kg)\"]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "4411d204",
-   "metadata": {},
-   "source": [
-    "##### IQR\n",
-    "\n",
-    "The IqrSeriesDetector makes use of the IQR (Inter Quantile Range) to detect the allowed values and the erroneous ones.\n",
-    "If we note Q25 as the 25th percentile and Q75 as the 75th percentile, then the values outside of the range \n",
-    "$$ [Q25 - threshhold * IQR \\quad,\\quad Q75 + threshhold * IQR ] $$\n",
-    "are considered as errors. "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 13,
-   "id": "993cecd8",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Q25 : 0.0044875\n",
-      "Q75 : 0.0067075\n",
-      "IQR : 0.0022199999999999998\n",
-      "lowest allowed value : 0.0011575000000000005\n",
-      "highest allowed value : 0.0100375\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "9      0.000000\n",
-       "14    56.000000\n",
-       "15     0.000000\n",
-       "20     0.000000\n",
-       "22     0.000000\n",
-       "30     0.000000\n",
-       "38     0.000000\n",
-       "41     0.000000\n",
-       "74     0.000000\n",
-       "75     0.000000\n",
-       "76     0.000445\n",
-       "85     0.000000\n",
-       "88     0.000814\n",
-       "90     0.011000\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 13,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "iqr_detector = s_gaussian.cleaner.detect('iqr', threshold=1.5)\n",
-    "\n",
-    "print(f\"Q25 : {iqr_detector.q25}\")\n",
-    "print(f\"Q75 : {iqr_detector.q75}\")\n",
-    "print(f\"IQR : {iqr_detector.iqr}\")\n",
-    "\n",
-    "print(f\"lowest allowed value : {iqr_detector.lower}\" )\n",
-    "print(f\"highest allowed value : {iqr_detector.upper}\" )\n",
-    "\n",
-    "iqr_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "1c9d0f4c",
-   "metadata": {},
-   "source": [
-    "##### Quantiles"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ebdc49f5",
-   "metadata": {},
-   "source": [
-    "The QuantilesSeriesDetector considers a lower and an upper quantile as parameters.\n",
-    "Values that are outside of the range determined by the quantiles are considered as errors."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 14,
-   "id": "97fdd9c9",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "lower quantile : 0.1\n",
-      "value at the lower quantile : 0.00040050000000000014\n",
-      "upper quantile : 0.9\n",
-      "value at the upper quantile : 0.007971\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "2      0.00860\n",
-       "9      0.00000\n",
-       "10     0.00992\n",
-       "11     0.00807\n",
-       "14    56.00000\n",
-       "15     0.00000\n",
-       "19     0.00831\n",
-       "20     0.00000\n",
-       "22     0.00000\n",
-       "30     0.00000\n",
-       "38     0.00000\n",
-       "41     0.00000\n",
-       "46     0.00822\n",
-       "61     0.00852\n",
-       "74     0.00000\n",
-       "75     0.00000\n",
-       "85     0.00000\n",
-       "90     0.01100\n",
-       "92     0.00832\n",
-       "93     0.00848\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 14,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "quantiles_detector = s_gaussian.cleaner.detect('quantiles', lowerq=0.1, upperq=0.9)\n",
-    "\n",
-    "print(f\"lower quantile : {quantiles_detector.lowerq}\")\n",
-    "print(f\"value at the lower quantile : {quantiles_detector.lower}\")\n",
-    "print(f\"upper quantile : {quantiles_detector.upperq}\")\n",
-    "print(f\"value at the upper quantile : {quantiles_detector.upper}\")\n",
-    "\n",
-    "quantiles_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b98a9aa8",
-   "metadata": {},
-   "source": [
-    "### Categorical Data"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b491fe1c",
-   "metadata": {},
-   "source": [
-    "Pandas-cleaner offers multiple detection methods that can handle categorical data. these can help detect and treat errors over object data. For the considered dataset, these could be useful to handle errors in the category and variety columns."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 15,
-   "id": "4c901fef",
-   "metadata": {},
-   "outputs": [],
-   "source": [
-    "s_categorical = data[\"category\"]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "74404bf8",
-   "metadata": {},
-   "source": [
-    "#### Values"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b4f1a211",
-   "metadata": {},
-   "source": [
-    "The ValuesSeriesDetector considers a list of allowed values. Entries that are not in the given list are considered as errors.\n",
-    "\n",
-    "For example, the considered dataset is supposed to include only fruits. However, some rows concern turnip (navet) which is a vegetable not a fruit. We can use the ValuesSeriesDetector to only allow specific values for example apples (\"pomme\") and cherries (\"cerise\")"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 16,
-   "id": "bad34d06",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "allowed values : ['pomme', 'cerise']\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "0     navet\n",
-       "3     Pomme\n",
-       "15    navet\n",
-       "16    navet\n",
-       "18    navet\n",
-       "35    navet\n",
-       "38    navet\n",
-       "39    navet\n",
-       "41    navet\n",
-       "45    navet\n",
-       "52    navet\n",
-       "55    navet\n",
-       "56    navet\n",
-       "61    navet\n",
-       "65    navet\n",
-       "83    navet\n",
-       "Name: category, dtype: object"
-      ]
-     },
-     "execution_count": 16,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "values_detector = s_categorical.cleaner.detect('values', values_list=[\"pomme\", \"cerise\"])\n",
-    "\n",
-    "print(f\"allowed values : {values_detector.values_list}\")\n",
-    "\n",
-    "values_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "c41dc9d4",
-   "metadata": {},
-   "source": [
-    "#### Value Counts"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "755ff45d",
-   "metadata": {},
-   "source": [
-    "The ValueCountsSeriesDetector considers that the values that appear only a few times are errors. For that, a minimum occurence value is given. Only values that appear more than the indicated minimum occurence number are considered as not erroneous. This emanates from the assumption that rare data are most likely errors."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 17,
-   "id": "5195d129",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "pomme     48\n",
-       "cerise    36\n",
-       "navet     15\n",
-       "Pomme      1\n",
-       "Name: category, dtype: int64"
-      ]
-     },
-     "execution_count": 17,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# values frequencies\n",
-    "s_categorical.value_counts()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 18,
-   "id": "918d36eb",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "allowed values : ['pomme', 'cerise']\n",
-      "erroneous entries :\n",
-      "0     navet\n",
-      "3     Pomme\n",
-      "15    navet\n",
-      "16    navet\n",
-      "18    navet\n",
-      "35    navet\n",
-      "38    navet\n",
-      "39    navet\n",
-      "41    navet\n",
-      "45    navet\n",
-      "52    navet\n",
-      "55    navet\n",
-      "56    navet\n",
-      "61    navet\n",
-      "65    navet\n",
-      "83    navet\n",
-      "Name: category, dtype: object\n"
-     ]
-    }
-   ],
-   "source": [
-    "counts_detector = s_categorical.cleaner.detect('counts', n=15)\n",
-    "\n",
-    "print(f\"allowed values : {counts_detector.values_list}\")\n",
-    "\n",
-    "print(f\"erroneous entries :\\n{counts_detector.detected}\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "ca269b6f",
-   "metadata": {},
-   "source": [
-    "#### Values Frequency"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "73d6ca4e",
-   "metadata": {},
-   "source": [
-    "The ValuesFreqSeriesDetector considers the frequencies of values in the pandas object. That is the ratio between the number of appearances of a value and the total number of non-missing data.\n",
-    "Given a minimum frequency, values that appear in the dataframe with a lower frequency are considered as errors.  "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 19,
-   "id": "bdc81f3d",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "pomme     0.48\n",
-       "cerise    0.36\n",
-       "navet     0.15\n",
-       "Pomme     0.01\n",
-       "Name: category, dtype: float64"
-      ]
-     },
-     "execution_count": 19,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# values frequencies\n",
-    "s_categorical.value_counts(normalize=True)"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 20,
-   "id": "0d107acd",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "allowed values : ['pomme', 'cerise']\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "0     navet\n",
-       "3     Pomme\n",
-       "15    navet\n",
-       "16    navet\n",
-       "18    navet\n",
-       "35    navet\n",
-       "38    navet\n",
-       "39    navet\n",
-       "41    navet\n",
-       "45    navet\n",
-       "52    navet\n",
-       "55    navet\n",
-       "56    navet\n",
-       "61    navet\n",
-       "65    navet\n",
-       "83    navet\n",
-       "Name: category, dtype: object"
-      ]
-     },
-     "execution_count": 20,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "frequency_detector = s_categorical.cleaner.detect('freq', freq=0.15)\n",
-    "\n",
-    "print(f\"allowed values : {frequency_detector.values_list}\")\n",
-    "\n",
-    "frequency_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "f8be0b78",
-   "metadata": {},
-   "source": [
-    "#### Patterns"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "1ec4168c",
-   "metadata": {},
-   "source": [
-    "The PatternSeriesDetector detects errors based on a regex pattern. Entries that do not match the specified pattern are considered as errors.\n",
-    "\n",
-    "This provides multiple opportunities to test the values present in a series."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "18f617a5",
-   "metadata": {},
-   "source": [
-    "Here we suppose that the variety entries are alphabetic, start with a lower case and may include spacing caracters:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 21,
-   "id": "8773e853",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1       granny,\n",
-       "3        Granny\n",
-       "18    de, Milan\n",
-       "29      golden2\n",
-       "38     de.Milan\n",
-       "45     Milan de\n",
-       "55     DE NANCY\n",
-       "Name: variety, dtype: object"
-      ]
-     },
-     "execution_count": 21,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "pattern_detector_1 = data[\"variety\"].cleaner.detect('pattern', pattern=r\"[a-z][a-zA-Z\\s]*\", mode=\"fullmatch\")\n",
-    "pattern_detector_1.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "33fb1787",
-   "metadata": {},
-   "source": [
-    "Note that multiple matching modes are available and can be parametrised using the **mode** argument. The default mode is *match* which checks if there is a match to the regex at the beginning of the string.\n",
-    "\n",
-    "In the following, we simply change the matching mode and the 'golden2' entry becomes allowed."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 22,
-   "id": "4615edfb",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "3       Granny\n",
-       "45    Milan de\n",
-       "55    DE NANCY\n",
-       "Name: variety, dtype: object"
-      ]
-     },
-     "execution_count": 22,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "pattern_detector_1 = data[\"variety\"].cleaner.detect('pattern', pattern=r\"[a-z][a-zA-Z\\s]*\", mode=\"match\")\n",
-    "pattern_detector_1.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "82d20aa0",
-   "metadata": {},
-   "source": [
-    "the regular expression checks are case sensitive by default. The **case** argument allows to ignore case-sensitivity.\n",
-    "\n",
-    "In the following, changing the case argument to *False* allows to consider the 'Granny' entry as allowed."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 23,
-   "id": "c9bd257d",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1       granny,\n",
-       "18    de, Milan\n",
-       "29      golden2\n",
-       "38     de.Milan\n",
-       "Name: variety, dtype: object"
-      ]
-     },
-     "execution_count": 23,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "pattern_detector_1 = data[\"variety\"].cleaner.detect('pattern', pattern=r\"[a-z][a-z\\s]*\", case=False, mode=\"fullmatch\")\n",
-    "pattern_detector_1.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6ce3a080",
-   "metadata": {},
-   "source": [
-    "#### Key Collision"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "2acf5f61",
-   "metadata": {},
-   "source": [
-    "When dealing with datasets that contain text entries, it is frequent to have either some entries that are misspelled or a few values that are not exactly equal but that refer to the same thing.\n",
-    "\n",
-    "In the considered dataset, the text column *variety* provides an example of such data column. It indicates the variety of the fruit and therefore has a few possible values. To help with data analysis entries referring to a same variety should be indentical. However, the variety \"de Milan\" for example is written differently through the dataset (\"de Milan\", \"de milan\", \"de, Milan\", \"Milan de\" and \"de.Milan\"). "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "0696a564",
-   "metadata": {},
-   "source": [
-    "The KeyCollisionSeriesDetector detects entries that may be alternative spellings of the same thing. "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 24,
-   "id": "e064cfb6",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Entries that have detected alternative representations\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "1       granny,\n",
-       "3        Granny\n",
-       "18    de, Milan\n",
-       "29      golden2\n",
-       "38     de.Milan\n",
-       "41     de milan\n",
-       "45     Milan de\n",
-       "55     DE NANCY\n",
-       "Name: variety, dtype: object"
-      ]
-     },
-     "execution_count": 24,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "keycollision_detector = data[\"variety\"].cleaner.detect('keycollision', keys=\"fingerprint\")\n",
-    "print(\"Entries that have detected alternative representations\")\n",
-    "keycollision_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "2075e75f",
-   "metadata": {},
-   "source": [
-    "For now, key collision uses a fingerprint algorithm that is mainly effective with punctuation and case-sensitivity issues. Misspelling errors might be considered as different entries and may not be detected by the algorithm. "
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b84cdd85",
-   "metadata": {},
-   "source": [
-    "The dictionary of the detected fingerprints and their considered representation can be listed using the following instruction:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 25,
-   "id": "87e28c13",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "{'de nancy': 'de Nancy',\n",
-       " 'granny': 'granny',\n",
-       " 'golden': 'golden',\n",
-       " 'bigarrau': 'bigarrau',\n",
-       " 'amarelles': 'amarelles',\n",
-       " 'bigarreaux': 'bigarreaux',\n",
-       " 'de milan': 'de Milan'}"
-      ]
-     },
-     "execution_count": 25,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "keycollision_detector.dict_keys"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "3e22ca70",
-   "metadata": {},
-   "source": [
-    "## Errors Information"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "694fbdcd",
-   "metadata": {},
-   "source": [
-    "Once the error detector is initialized, multiple queries can be performed to analyse the series and get information about the errors present in the data."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "4a21a8de",
-   "metadata": {},
-   "source": [
-    "### Error Report"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 26,
-   "id": "cf612284",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "The error report : \n",
-      "\n",
-      " bounded : 6 errors detected among 100 samples \n",
-      "1      -2.53\n",
-      "7      55.00\n",
-      "14    644.00\n",
-      "43     -5.65\n",
-      "75     -5.07\n",
-      "96     -2.05\n",
-      "Name: price(euro), dtype: float64\n"
-     ]
-    }
-   ],
-   "source": [
-    "# generate an error report\n",
-    "errors_report = bounded_detector.report()\n",
-    "print(\"The error report : \\n\\n\", errors_report)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "fea1d4ba",
-   "metadata": {},
-   "source": [
-    "### Number of errors"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 27,
-   "id": "46543067",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "The series contains 6 errors\n"
-     ]
-    }
-   ],
-   "source": [
-    "# number of errors\n",
-    "print(\"The series contains %d errors\" % bounded_detector.n_errors)"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "11728e0c",
-   "metadata": {},
-   "source": [
-    "### List Detected errors"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6dd520a0",
-   "metadata": {},
-   "source": [
-    "the errouneous entries can be extracted using the method detected illustrated below. Alternatively, they can be retrieved using is_error or not_error (which allows simply to retrieve valid entries)."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 28,
-   "id": "0f6fa1da",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1      -2.53\n",
-       "7      55.00\n",
-       "14    644.00\n",
-       "43     -5.65\n",
-       "75     -5.07\n",
-       "96     -2.05\n",
-       "Name: price(euro), dtype: float64"
-      ]
-     },
-     "execution_count": 28,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "bounded_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "090ea236",
-   "metadata": {},
-   "source": [
-    "### Error Indicators"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "1f644b51",
-   "metadata": {},
-   "source": [
-    "it is possible to print a boolean series representing if a given entry was detected as error or not.\n",
-    "The methods is_error and not_error allow doing so: "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 29,
-   "id": "63550a83",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "0     False\n",
-       "1      True\n",
-       "2     False\n",
-       "3     False\n",
-       "4     False\n",
-       "      ...  \n",
-       "95    False\n",
-       "96     True\n",
-       "97    False\n",
-       "98    False\n",
-       "99    False\n",
-       "Length: 100, dtype: bool"
-      ]
-     },
-     "execution_count": 29,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# indicate if row is erroneous\n",
-    "bounded_detector.is_error()"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 30,
-   "id": "42253796",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "0      True\n",
-       "1     False\n",
-       "2      True\n",
-       "3      True\n",
-       "4      True\n",
-       "      ...  \n",
-       "95     True\n",
-       "96    False\n",
-       "97     True\n",
-       "98     True\n",
-       "99     True\n",
-       "Length: 100, dtype: bool"
-      ]
-     },
-     "execution_count": 30,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "# indicate if row is correct\n",
-    "bounded_detector.not_error()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "2e3098bb",
-   "metadata": {},
-   "source": [
-    "## Visualization"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b84bcef1",
-   "metadata": {},
-   "source": [
-    "### Numerical series"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "d30e91ab",
-   "metadata": {},
-   "source": [
-    "Pandas-cleaner offers a plotting method for numerical detectors.\n",
-    "It plots a visualization of the data contained in the treated series:\n",
-    "a scatter plot of the data,\n",
-    "the distribution of the data (histogram and kde),\n",
-    "and a boxplot.\n",
-    "\n",
-    "The coloring emphasizes the erroneous data. In addition, two horizontal lines delimit the allowed values. "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 31,
-   "id": "0efbc918",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       "<Figure size 432x288 with 4 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "axs = data[\"price(euro)\"].cleaner.detect('bounded', lower=0., upper=30).plot()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "90a516e0",
-   "metadata": {},
-   "source": [
-    "In the preceding graph, outliers make the plot much less interesting : interest points are ravelled and the distribution very dense. To focus on interest valid data points, the **compact** argument can be set to *True*  allowing to better visualize the data distribution, ommitting outiliers and explicitly displaying the number of errors."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 32,
-   "id": "dbec3828",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAs8AAAFzCAYAAADBkuQkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/Z1A+gAAAACXBIWXMAAAsTAAALEwEAmpwYAABlNUlEQVR4nO3dd3hU1dYG8HenB5LQEiAkIQUpUgNEBRVBsCJiARE76gUFFfWCBa9Yr4qfcO0VC4gFGyogolgABQVC7z3UAAk1hIS0/f2xZpxJMklmkpk5Z2be3/PMk5wzbeVkklmzz9prK601iIiIiIioZkFGB0BERERE5CuYPBMREREROSnE6AA8JjLyAAoLmxkdhl+JiDiIgoLmRodBREREZBTltzXPSmn4689mFKUArZXRYRAREREZhWUbREREREROYvJMREREROQkn6p5bty4se7cuXO5fUOGDMGoUaNw6tQp9O/f/5/9870cm0PHjgH/+hewbp2UPHz4IdCzp+PbLlsm102fDgwebNt/4gTQvj1w9dXAG2/ULR6tgfvvB+bMAerVA6ZMAbp1A1atAkaOlOcKDgb+8x/g+usdPkSfPn3+qYWJjIzEjz/+CAB49tln8euvv5a7bZMmTfDNN98AAMaNG4e//vqr3PWJiYn45JNPAAAPPPAAVq1aVe76Nm3a4L333gMAjBgxAlu2bCl3fXp6Ol555RUAwM0334y9e/eWu75nz5544YUXAACDBg3C4cOHy13fr18/jB8/HgBw+eWXo6CgoNz1AwYMwNixY60/d6VjUdVrz2rYsGEYNmwYcnNzMdj+d2oxcuRIXH/99dizZw9uueWWStePGTMGV155JTZv3oy77rqr0vWPP/44LrroIqxatQoPPPBApeuff/55nHvuuVi8eDEee+yxSte/8sorSE9Pxy+//IL//ve/la5/99130bZtW8yaNQuTJk2qdP20adOQlJSEL774Am+//Xal67/++mvExsZiypQpmDJlSqXr58yZg3r16uGtt97Cl19+Wen6+fPnAwAmTpyI2bNnl7uOrz2+9tz92luwYMFPWuvLKt3Ygxo2bKjT09PL7fPH360Rx7ZxeLjufOaZ5fYN6dMHo66+GqcKC9H/0Ucr3WfYZZdh2GWXIff4cQx+8slK148cOBDX9+2LPYcO4Zbnnweys+W9NDkZQAAdWxdyMStffN0CVR9fn6p5zsjI0JmZmc7dWOpzPRtQTW67DejVSxLooiLg1CmgYcPKtystBS6+GIiIAO64o3zyfP/9QE4O0Lixa8lzSgqQlVV+35w5wOuvy9clS+SxlywBtmyR49W6NbB/P9C9O7BxY+VYzXBMiYg8QCm1XGud4c3n7NKli169erU3n9IQRhzbjNhYnfn11559krlz5X12+nTPPk81DDm2ruRiPq6q4xs4ZRtZWUC7dsCwYUCbNsBNNwG//AKcd54kjUuXyu2WLpUR4K5dgXPPBTZvlv0vvyyJLQCsXQt07CjJcFWOHwcWLgTuvFO2w8IcJ86AJLSDBgFNm5bfv3w5cPAgcMkl5ff//LPE2K0bcN11wMmTzh2D778Hbr1VkuAePWRkPDtbjkfr1nKbFi0kjpwc5x6TiIgoEKWmypllCjiBkzwDwLZtwJgxwKZNcvnsM+DPP4GJE4Hnn5fbtGsH/PEHsHIl8MwzgHV4//775f7ffgvcfjvw7rtyuiYzU0aWK9q5E4iLk9t27Sq3yc+vfLt9++QxR44sv7+sTGKdOLH8/txc4L//lcR/xQogIwP43/+c+/n37QOSkmzbiYmyz97SpTJK3qqVc49JREQUiFq2BLZvl7PHFFACK3lOTQU6dQKCgoAOHYB+/WQUtlMnW4nD8eMymtuxI/Dgg8D69bI/KEhqhG+5BejdW0asAUle33+/8nOVlEhyO3KkJOL16wMTJlS+3QMPAC++KI9v7623gP79JcG19/ffwIYN8vzp6cDUqcCuXXLdPffIvvR0Kb+wfv/cc84dn+xs+fk++qhyPERERGQTGQnExkoCTQHFpyYM1ll4uO37oCDbdlCQJLsAMH48cOGFMhqclQXYT9bZuhWIipLEtCaJiXI55xzZHjzYcfKcmQkMHSrf5+ZKPXJICPDXXzIC/tZbUpZRVCTPfd55Uh/9+eeVH+vNN23fp6TIREB7CQnAnj227b17ZR8gkwWvuEIS7R49av75iIiIAl1KigyytWljdCTkRRxerOj4cVtCaT9L+/hxYPRoqWM+fBioaSJC8+ZSImGtmf71V+maUdHOnZKkZ2VJgv3WW9JZ49NPgd27Zf/EiVKrPGGCJLaLFkkJCSClIBU6AVRp4EDg449l0t/ffwMNGgDx8ZKYX3ONPIeDWbBERETkQMuWrHsOQEyeK3r4YWDcOKlTto5GA1LCcc898unygw+ARx8FDh2quuYZkImAN90EdO4so8DW+ul33pFLbcTFSVJ/ww3yuD17Sv22M/r3B9LSgDPOAIYPl0QdAL78Uj4UTJliK/WoOGpNRERE5SUnSxMBCihsVUfO4zElIj/FVnWe47et6gA58/vqq7b5UV7GVnWexVZ1RERERO5k7bhhf6aa/B6TZyIiIqLaiIiQtRGs85AoIDB5JiIiIqqt1FTDyjbIGB5vVaeUigCwEEC45fm+1lo/qZSaAqA3gOOWmw7TWq/ydDxEAeHECVmJ8u+/ZTJLaamsHnneeUDfvrYVJYmIqG6SkqTjxqBBRkdCXuKNPs+nAfTVWp9USoUC+FMp9aPluoe01l6o6CcKELm50gnms8+kX3h+vqxWafXNNzLps1MnWZnSutgPERHVDjtuBByPl21ocdKyGWq5eL5lQ3KydIfgxX2X5GSP/9qoDmbPljaE06YBBQVAXl75xBkATp2S65YulcV27rkHKC42Jl4iIn/Aso2A45WaZ6VUsFJqFYBDAOZprZdYrnpOKbVGKfWyUiq8ivuOUEplKqUyc3JynH/SrCwZYePFfRfrEuZkPh9/DAwZIov5FBU5d5+CAuntPWAAE2giL7F/Tzt8+LDR4fiVcvlCYaH3nrhlS1nwzI//j9Y6F/NTXkmetdalWut0AIkAzlZKdQQwDkA7AGcBaAzgkSru+57WOkNrnREXF+eNcIl8y9KlwN13SzLsqlOnZBn4Bx90f1xEVIn9e1qTJk2MDsevlMsXIiK898RhYbKq8Nat3ntOL2MuVp5Xu21orY8B+B3AZVrrbEtJx2kAHwE425uxEPmF06eB666rXeJsVVAAfPghsHix++IiIgokKSks3QggHk+elVJxSqmGlu8jAVwMYJNSKt6yTwG4GgAXhydy1fTpwJEjjq874wzgt99kEqG1+0ZamuPbFhQAY8d6Lk4iIn9m7bhBAcEbI8/xAH5XSq0BsAxS8zwbwKdKqbUA1gKIBfBfL8RC5F9eegk4edLxdQkJQFAQ8OSTwEcfyQTB99+v+rFWrpSVsoiIyDUpKey4EUA83qpOa70GQFcH+/t6+rmJ/FpeHrB5c9XXL14M9Olj277pJqBDh6pvHxwM/P470KqV20IkIgoIKSnAl18aHQV5CVcYJPJVa9YA9epVfb39zO/u3YEmTYCFC6u+fX4+656JiGojKUk6Ujnb7Yh8GpNnIl/lbLugtm2BmTOlldJ991V/23376h4XEVGgCQuTVVy3bDE6EvICJs9Evio4uObbnHkmMH++jIb07QscOFD97UO8segoEZEfYseNgMHkmchXnXFG5RUE7SUmSg1zbCzwzjvAOecA119f9e2DgoDOnd0fJxFRIGDHjYDBYSYiX9WmTfUrWrVqBTRrJt9PmGDb/8UXjm8fFSUJNhERuS4lBVi92ugoyAs48kzkq4KDgYEDZcTYkQULAKUqX6pSUiLt7IiIyHWpqcCGDUZHQV7A5JnIl40dC7hjGdrwcODWW4H69ev+WEREgSgxEdizBygsNDoS8jAmz0S+7OyzgauuqnsCXa8e8Pzz7omJiCgQhYZK3fOmTUZHQh7G5JnI1739tkwKdKb7hiORkcBnnwGNGrk3LiKiQJOSwkmDAYDJM5Gva9BAFjeJj5fyC1dERgIffghcdplnYiMiCiQtW3KZ7gDA5JnIH1hbJA0eLCUYVU0itIqKAtLSgD//BIYO9U6MRET+LjWVHTcCAJNnIn/RoAHwySfSZWPIEKmDrl9f9jdoAMTEyCIoXboA774LbNwIdOtmdNRERP4jNZULpQQA9nkm8jcZGcDnn8sCKtu2yaW0FIiLk0VQ6tUzOkIiIv8UHw8cOQKcOCEDFuSXmDwT+augIFlIpU0boyMhIgoMQUG20eeePY2OhjyEZRtERERE7pKczI4bfo7JMxEREZG7JCcDa9YYHQV5EJNnIiIiIndJSWHy7OeYPBMRERG5S1oasGGD0VGQBzF5JiIiInKXJk2A4mLg0CGjIyEPqX23jcjIAygsbObGWGqUCQBK2XYkJwNZWd4MgYiIiKhqSsno8/r1QNOmRkdDHlD7kefCwmbQGoZedu1y46EgIiIicoPkZC7T7cdYtkFERETkTsnJXKbbjzF5JiIiInKn1FSOPPsxJs9ERERE7pSSAmzcKCWm5Hc8lzxfdhnQpQvQoQNw991AaansP3IEuPhioHVr+Xr0qOP7T50qt2ndWr4nIiIi8gUNGgCRkcCePUZHQh7gueT5yy+l3mfdOiAnB/jqK9k/YQLQrx+wdat8nTCh8n2PHAGefhpYsgRYulS+ryrJJiIiIjKbVq24TLef8lzyHBMjX0tKgKIiW4u5778HbrtNvr/tNuC77yrf96efZFS6cWOgUSP5fu5cj4VKRERE5FYtW7Lu2U95tub50kulx2F0NDB4sOw7eBCIj5fvmzeX7Yr27QOSkmzbiYmyj4iIiMgXpKSw44af8mzy/NNPQHY2cPo08Ntvla9XqvyiJ0RERET+IDWVZRt+yvPdNiIigKuuknINAGjWTBJqQL46Wn0nIaF8kf3evbKPiIiIyBckJ8v8rpISoyMhd9Na1+4C6Crl5Wm9f798X1ys9ZAhWr/+umyPHav1Cy/I9y+8oPVDD1W+/+HDWqekaH3kiFxSUmRfRYDW06bJ9/n5WvfurfX06bJ97Jhsf/ONbOfkyPbMmbKdnS3bP/4o27t3y/a8ebK9fbtsz58v25s2yfaiRbK9dq1sL10q2ytXyvbKlbK9dKlsr10r24sWyfamTbI9f75sb98u2/Pmyfbu3bL944+ynZ0t2zNnynZOjmx/841sHzsm29Ony3Z+vmxPmybbRUWy/dFHsm313nta9+tn237zTa0vu8y2/corWl95pW37pZe0vvZa2/YLL2h9/fW27Wee0fqmm2zb48drPWyYbfvRR7UePty2PWaM1qNG2bbvv18uVqNGyW2shg+Xx7AaNkyew+qmmyQGq+uvt73OtJbYX3rJtn3llfIzWl12mRwDq3795BhZ9e4tx1BrOaa9e/O1x9ee4GvPL157ADJ1bd8Pa3npVr9+QPxujTi23YOCdGmPnrr0xpt16dAbdVnTprq057myPWSobJ93vmwPHiLbvS6Q7WsHy/YFfWT7mkGy3aevbF91jWz37SfbA6+S7X4Xy/aAK2X74kt1WUSkLv1+pn8d26iogHjdal31/4UQj2Tk+fnAwIFSrlFWBlx4obSrA4BHHwWGDAE++EA+lX35pezPzATeeQd4/32ZKDh+PHDWWXLdE0/IPiIiIh+mlBoBYAQAdAoLMzga/2J/bNsjGN8ticfKpe0QpEsxTC/G8pwWWL2kHUJ1EW7Rf2NpTgLW/dUO4boQN+ml+DsnARtUO9TT+RiqM7EoJxGbVTtE6TwM0cuxMCcR21QbxOhjGKxXYv7vSdihzkAjfQTX6NX47beWyFKpiNU5GKjXYt4vydiJJ1EwoSle8fFftf2x7RwebnA0xlO6tg28ldIwuvm3UmxATkREdaaUWq61zvDmc3bp0kWvDoAJZUYcW6Uy9O+/Z3rzKR3KyQFGjgRycz3z+EYc24yMDJ2Zafyx9Yaqji9XGCQiIiLygNhYKXk+dMjoSMidmDwTEREReYBSQFoa2z37GybPRERERB6SnMyOdf6GyTMRERGRh6SkAGvWGB0FuVPtk+eIiIP/LHJi1CU52Y2HgoiIiMi9UlNZtuFvap88FxQ0h9bKm5eM7t2lu4b1kpXlviNBRERE5GYpKcDGjWwO5k9YtkFERETkITExQL16wO7dRkdC7sLkmYiIiMiD0tI4adCfMHkmIiIi8qCWLVn37E+YPBMRERF5EDtu+Bcmz0REREQexI4b/oXJMxEREZEHJScD27bJUt3k+5g8ExEREXlQZCQQFwds3250JOQOTJ6JiIiIPCwlhR03/AWTZyIiIiIPa9mSybO/YPJMRERE5GHsuOE/mDwTEREReVhqKkee/QWTZyIiIiIPS0oCsrKA06eNjoTqiskzERERkYeFhQEJCcDmzUZHQnXF5JmIiIjIC1JSgPXrjY6C6orJMxEREZEXsOOGf2DyTEREROQF7LjhH5g8ExEREXkByzb8A5NnIiIiIi9ITAT27wcKCoyOhOqCyTMRERGRF4SESMu6TZuMjoTqgskzERERkZewdMP3MXkmIiIi8hJ23PB9TJ6JiIiIvCQ5mR03fB2TZyIiIiIvSUkBNmwwOgqqCybPRERERF6SkAAcOACcOmV0JFRbTJ6JiIiIvCQ4WOqe2XHDd3k8eVZKJSmlfldKbVBKrVdK3W/Z/5RSap9SapXl0t/TsRAREREZLTmZHTd8WYgXnqMEwBit9QqlVDSA5UqpeZbrXtZaT/RCDERERESm0LIlk2df5vHkWWudDSDb8n2eUmojgARPPy8RERGRGSUnA0uWGB0F1ZZXa56VUikAugKwvmTuVUqtUUp9qJRq5M1YiIiIiIzAjhu+zWvJs1IqCsA3AB7QWp8A8DaAVgDSISPTk6q43wilVKZSKjMnJ8db4RIREbmd/Xva4cOHjQ7Hr9gfW8Dc+UKLFkB2NlBQYHQkzmEuVp5XkmelVCgkcf5Uaz0DALTWB7XWpVrrMgCTAZzt6L5a6/e01hla64y4uDhvhEtEROQR9u9pTZo0MTocv2J/bAFz5wshIUBSErB5s9GROIe5WHne6LahAHwAYKPW+n92++PtbnYNAC5WSURERAEhOZmlG77KG902zgNwC4C1SqlVln2PAbhBKZUOQAPIAnCXF2IhIiIiMlxiIjtu+CpvdNv4E4BycNUcTz83ERERkRm1bAmsWmV0FFQbXGGQiIiIyMuSk7nKoK9i8kxERETkZUlJwK5dQFGR0ZGQq5g8ExEREXlZWBjQvDmwbZvRkZCrmDwTERERGSAlBdi40egoyFVMnomIiIgMkJjIdnW+iMkzERERkQGSktiuzhcxeSYiIiIyQMuWHHn2RUyeiYiIiAyQnAxs3w6UlRkdCbmCyTMRERGRAerXB6KigD17jI6EXMHkmYiIiMggXCzF9zB5JiIiIjJIYiLb1fkaJs9EREREBmG7Ot/D5JmIiIjIIC1bcuTZ1zB5JiIiIjJIy5bAli1GR0GuYPJMREREZJC4OODkSeD4caMjIWcxeSYiIiIyiFIy+rx5s9GRkLOYPBMREREZKCmJ7ep8CZNnIiIiIgO1aMGRZ1/C5JmIiIjIQElJbFfnS5g8ExERERkoKYkdN3wJk2ciIiIiAyUmAjt2AGVlRkdCzmDyTERERGSgevWAmBhgzx6jIyFnMHkmIiIiMhgXS/EdTJ6JiIiIDNaiBZNnX8HkmYiIiMhgCQns9ewrmDwTERERGSwxkcmzr2DyTERERGSwxERg2zajoyBnMHkmIiIiMlh8PLB/P1BUZHQkVBOPJ89KqSSl1O9KqQ1KqfVKqfst+xsrpeYppbZavjbydCxEREREZhQaCjRrBuzcaXQkVBNvjDyXABijtW4PoAeAe5RS7QE8CuBXrXVrAL9atomIiIgCUmIisHWr0VFQTTyePGuts7XWKyzf5wHYCCABwFUAplpuNhXA1Z6OhYiIiMis4uNZ9+wLvFrzrJRKAdAVwBIAzbTW2ZarDgBo5s1YiIiIiMwkPh7YvNnoKKgmXkuelVJRAL4B8IDW+oT9dVprDUBXcb8RSqlMpVRmTk6OFyIlIiLyDPv3tMOHDxsdjl+xP7aAb+YLiYnmXCiFuVh5XkmelVKhkMT5U631DMvug0qpeMv18QAOObqv1vo9rXWG1jojLi7OG+ESERF5hP17WpMmTYwOx6/YH1vAN/OFhARgxw6jo6iMuVh53ui2oQB8AGCj1vp/dlfNBHCb5fvbAHzv6ViIiIiIzKp5c2lXV1xsdCRUHW+MPJ8H4BYAfZVSqyyX/gAmALhYKbUVwEWWbSIiIqKAFBoKxMUBWVlGR0LVCfH0E2it/wSgqri6n6efn4iIiMhXJCYC27cDrVsbHQlVhSsMEhEREZlE8+aSPJN5MXkmIiIiMonmzblQitkxeSYiIiIyiRYtmDybHZNnIiIiIpNo0cKc7erIhskzERERkUnExwO7dgHa4dJxZAZMnomIiIhMon59ICICOHjQ6EioKkyeiYiIiEzErCsNkmDyTERERGQi8fFMns2MyTMRERGRiTRtyuTZzJg8ExEREZkIF0oxNybPRERERCbCsg1zY/JMREREZCLNmwNZWUZHQVVh8kxERERkIk2bAocOAcXFRkdCjjB5JiIiIjKR0FCgcWNg3z6jIyFHmDwTERERmUx8PEs3zIrJMxEREZHJNGsmy3ST+TB5JiIiIjKZ2Fhg506joyBHmDwTERERmUzz5kyezYrJMxEREZHJNG3KmmezYvJMREREZDLNmgF79hgdBTnC5JmIiIjIZJo2BfbvB8rKjI6EKmLyTERERGQyERFAvXqyWAqZC5NnIiIiIhNq3hzYvdvoKKgiJs9EREREJtS0KeuezSjEmRsppSIA3AmgA4AI636t9R0eiouIiIgooMXGen7kmTme65wdeZ4GoDmASwEsAJAIIM9TQREREREFuiZNvFK2wRzPRc4mz2dorccDyNdaTwVwBYBzPBcWERERUWBr2tQrS3Qzx3ORs8lzseXrMaVURwANADT1TEhERERE5KWaZ+Z4LnI2eX5PKdUIwOMAZgLYAOBFZ+6olPpQKXVIKbXObt9TSql9SqlVlkt/lyMnIiIi8mNxccC+fR5/mlrneIHKqQmDAH7VWh8FsBBAGgAopVKdvO8UAG8A+LjC/pe11hOdfAwiIiKigNKkCZCbC5SWAsHBHnuauuR4AcnZkedvHOz72pk7aq0XAjjidEREREREhNBQICYGOHjQo09T6xwvUFU78qyUagdpXdJAKXWt3VUxsGtnUkv3KqVuBZAJYIzlUw8R1SAnB1i7FsjPB9q1A1q3NjoiIiLyFGvpRosW7n1cD+d4fq2mso22AAYAaAjgSrv9eQCG1+F53wbwLABt+ToJgMN+gkqpEQBGAEDLli3r8JREvm/vXuDOO4Gff5btmBhg3jzg7LONjYuInGP/npaQkGBwNP7F/tgC/pMvxMZK8nzWWW5/aKdzPOZi5VWbPGutvwfwvVKqp9b6L3c9qdb6nxMQSqnJAGZXc9v3ALwHABkZGdpdMRD5oiVLbIkzAJw4AYwfD8yYAdSvb1xcROQc+/e0jh076rw8x+10o6KioJTyZmg+z/7YKuU/+UKTJp6ZNOhKjufuXGzy5MnYsWOHU7fNzs4GAMTHxzv9+GlpaRg+vC5jvNVzdsLgSqXUPXDT6jNKqXitdbZl8xoA66q7PRGJrKzK+1askCSayTORbzl0SOH55yvvLyrKw1NPAdHR0V6PicyncWOPd9xwa47nbgUFBUaHUImzyfM0AJsgq888A+AmABuduaNS6nMAfQDEKqX2AngSQB+lVDqkbCMLwF2uBE0UqDp3rrxv8GCpiSMi36JUMMLDmSBT9Tw18myn1jlebbkyKjxu3DgAwAsvvOCpcFzm8RUGtdY3aK3jtdahWutErfUHWutbtNadtNadtdYD7UahiagaZ58N/N//ARGWsYGLLwYefBAIcfZjMBER+ZTYWJnv4kFcYdBFzr7lVlx95gC4+gyR1zVoAIwZA1x9NVBYCKSkADyzS0Tkv5o0AQ4c8OhTMMdzkbPJc8XVZ6IAjPdYVERUpaAgtqcjIgoUjRt7PHlmjueimvo8/9tu83bL1zctXzk9iYiIiMiDGjYE8vKA4mJZNMVdmOPVXk0jz9YTwm0BnAX5RAJIP8ClngqKiIiIiORsY6NGMvqclOTWh2aOV0s19Xl+GgCUUgsBdNNa51m2nwLwg8ejIyIiIgpw1rpndybPzPFqz9ma52YAiuy2iyz7iADIUtHr1gHZ2UByMtChAxAWZnRUREREvq9RI+DgwZpvV0vM8VzkbPL8MYClSqlvLdtXA5jiiYDI9xQUAK+9Bjz2mGwrBUyZAtxyi3xPREREtWct2/AQ5ngucip51lo/p5T6EUAvy67btdYrPRcW+ZKNG4H//Me2rTUwahTQsye7QhAREdVVgwaeG3lmjuc6p5dW0FqvALDCg7GQjzp0SBJme/n5wOHDTJ59UWEhEBzs3lndRERUex4eeWaO5yJnVxgkqlJKim3FO6sWLYCWLQ0Jh2rpyBHg00+BCy4Arr0WWLgQKC01OioiIvJ08kyuYfJMdda2LTBjBtDUsh5Rairw1VeSQJPvmDkTuPlmYNkyYPZsoG9f+d4VR4/KhYiI3KdhQybPZsLkmepMKeDyy4HMTGDlSuCvv4BzzzU6KnLFsWPAiy+W31daCsyf79z9jx8Hpk0DevSQWvfPP5em/kREVHeNGgE5OUZHQVZO1zwT1SQpye0N3MlLQkKAqKjK++vVc+7+v/8O3HqrbfvGG4FZs4ABA9wTHxFRIGvYEMjNNToKsuLIMxEhKgp48sny+6Kjgd69nbv/5MmV902ZUuewiPxaWVkJTpzIrXTJy8tFXl4e8vLyoCvOxqaA1KCBnCHkPBRz4MgzEQEA+vUDfvtNap9jY4H+/YEuXZy7b0KCc/uIXFFWJksT+y+N8mtTiLCwcLz2WhSKi/Pw1FNAdHR0pdtQYAkOlkGOI0eAuDijoyEmz0QEAIiMBC68UC6uuvNOqXkuLLQ91i23uDc+ChybNwPTpwPz5knnl2uukYnI/iYoKBQxMVXPrFZcZYrsNGokpRtMno3H5JmI6uycc4BFi4DFi2UC6XnnAenpRkdFvujgQWDIEGDNGtletAhYsAD45BMpJSIKVKx7Ng8mz0TkFt26yYWoLjZutCXOVjNnAlu38vVFga1BA3bcMAu/riYjIiLfUlWlAisYKNBFR8vKvWQ8Js9ERGQaZ54pZUD2hg4F2rQxJh4is4iKYvJsFizbICLT2bABWLsWCA+X2umUFKMjIm9p2lTqm3/4QRbp6d8fuPRSoH59oyMjMlZMDMs2zILJMxGZytKlsjR4fr5st24ty4Vz5DFwnHEGcP/9ciEiERMDHDpkdBQEsGyDiEykqEiWCbcmzoBMFPvtN+NiIiIyg5gYlm2YBZNnIjKNggIp2aho2zbvx0JEZCbR0bJIChmPyTORDysrkzKHF18EJk0CVqwwOqLay82VRVZuv73ydX37ej8eIiIziY6WJbrJeKx5JvJhixdLYllcLNv16smCEhkZxsblilOnpKb50UeBkyeB118HRo8G3n5bfp7nnpNFV/xNVhawd68shd6mjb8vQ01EdcXk2Tz475rIR2kNvPGGLXEGJBH96ivjYqqNv/8Grr8e2LlTZpIPHQqcfTawaZN03LjnHlkcwJ9YP+D06gV07QpMnSr13kREVWHybB5Mnol8VGmp45nXvtbKaN68yvueew5o0gRISvJ+PJ62fz9w4422iT+FhcC//gWsX29sXERkbhERMljCD9rG83jyrJT6UCl1SCm1zm5fY6XUPKXUVsvXRp6Og8jfhIQA995bef8NN3g/lrpo0aLyvuRk6fHsjw4ckATaXlkZsGePMfEQkW9QiqPPZuGNkecpAC6rsO9RAL9qrVsD+NWyTUQu6tcP+OwzoFMnoHt34LvvvFsffPCg1O7al4646qKLgGbNbNuhocBjj8koiz+Ki5OFQCpKSPB+LETkW6KimDybgccnDGqtFyqlUirsvgpAH8v3UwHMB/CIp2MhY50+LV/9dUTRCA0ayEjzFVfIhLOoKO88b2GhTPJ74AFJoO+8E3jkESA11fXHOvNMqQFevlxa1XXtKhd/lZQkNc6DB0s/6+Bg4H//A9q3Nzoy8rayshKcOJFb5fVFRXnIy3PtH2ZUVBSUUnUNjUwqOho4ftzoKMiobhvNtNbZlu8PAGhW3Y3Jt506Bfz+O/DSS7L90EPAhRdKJwVyj5gY7z7f8uXAddfZtt99V36fL70kyaCr2raVS6C49FJg5Upg1y4ZhW7XDggLMzoq8j4NoOoC1rCwcLz2WhSczYWLivLw1FNAdHS0W6Ij86lXj8mzGRjeqk5rrZVSuqrrlVIjAIwAgJYtW3otLnKfP/4ABgywbS9YAMydKwkE+aa1ayvv+/BDYMwYlh84QylZdrx1a6MjIW+zf0+Ljk5ETIyDon+qFftjC/hnvhAVZUzyzFysPKO6bRxUSsUDgOVrlau1a63f01pnaK0z4uLivBYguc/kyZX3vf++9+Mg94mNrbwvNRWoX9/7sRD5Evv3tMjIJkaH41fsjy3gn/lCvXrAiRPef17mYuUZlTzPBHCb5fvbAHxvUBzkBY569Ppb395Ak5EBpKfbtkNCpGSjYUOjIiIi8n+RkcYkz1Sex8s2lFKfQyYHxiql9gJ4EsAEAF8qpe4EsAvAEE/HQca54w7g44+BkhLZDgkpvwTzoUOyUt6yZUDHjsD551fu71tSIu28WBdqDikpwPffS93uiRMy2c0+mSYiIvdj8mwO3ui2UVXX2X6efm4yhx49gIULgVmzZHvgQOCss+T7wkLg+eeBV1+13X7AAGDKFFkko7QUWLQIeOUVWfxj9Gjg4os5wmkGLVvKxRn5+cDq1TJBLiEB6NKFZx+IiFzFCYPmYPiEQfJ/wcFAz55yqWjrVuC118rvmz0b2LhRRqCXLQP69pUkGgD+/BP45BPgpps8Hze5R2kp8NFHwH332faNGwf85z+skSYicgVHns2By3ObUG6uJInz5wPZ2TXe3KedPg1oB71WCgvl66+/2hJnqxdfBPLyPB8b1V5xMbBkiXTg+PVX6cJh74UXgE2bjImNiMhXRUby/c8MmDybzM6dwJAhQK9e0gu5b18ZhfVXrVoB555bfl9Skq3nr6MFVSIjZUEQMq+ff5bf6513SslOkYNWtkeOeD8uIiJfVq8ek2czYApiMr/8IguKWG3aJPW/jkZn/UGjRjI6ef/9Mglt2DAp27BOGOzbt/JiKo8/ztP9Znb4MPDggzLBE5AkuWJtdExM7VYjJHPbu1cW0Nm1y+hIiPxTRARw8qTRURCTZ5P566/K++bNs5Ux+KO2bYFJk4DMTOC994DOnW3XdesmI5fjxwMjR0oJwEUXGRcr1ezUKWDfPtv2lCnAv/9t68bRpo1MHj3jDCOiq1lOjiSB/vqB1VPmz5eJwBkZQPfuwA8/8BgSuVtkpEzAJmNxwqDJ9O0rk6vsXX21/MH4s+Bg6a7hSPfuciHfEB8v5Rqvvy7bBQXAI49IO8L69YHGjQEz9tg/dUrOejz0EHDsmJwNuesurpjojF27gMGD5awDIF+vu05aGXpi2fVjx4AtWyQ5b9NGzmARBYKICCbPZsCRZ5O58ELgttts2337AjfeaFw8RK4KCZGyjdGjpeSmdWvgm2+ATp0kkXI1cS4uliTsiy+A336TCbWesHQpcP31wO7dMpv92WeBzz7zzHP5m717bYmzVUGBHEt327kTGDoUOOccaYM5ZAiwfbv7n4fIjCIi5IM+GYvJs8kkJABvvinJwrJlwIwZ5j29TVSV1FQpxdm0SUacr7gCCA2t3WP98IOUAgwdCvTrJ4m5JxLoP/6ovO/tt8tPbNy9W8qI1qyRTjHuVFQkz2XmUoesLPl9zJlTPjGOja18diw4GGjWzP0xzJwJ/PSTbfuXX2QfUSCIiJAPpmQsJs8mVL++1IdmZHAhCfJdISEy8TM2tvaPsW8fcPfdtsmHgPT5XrOm7vFV1Lx55X2pqfJmBUjrvbPOAnr3Brp2BSZOdN+s91WrZNXNs84CHnsM2LbNPY/rTuvWSRegAQPkw5B9J6DWrWW+QnCwbCslCxu1a+f+OObMqbzvhx/c/zxEZsTk2RxY80xEpnXiBHDwYOX9nhh57t0bSE62dYoIDQWeeEJKT44ckST+0CG5rqxMur5ccIEklHWxY4esmmn9mSZMANauBaZPB6Ki6vbY7vTJJ1KeYbV9O/Ddd8CZZ0rryCFDpDRnzx6gRQtZsj0szP1xXHqptEK0d9ll7n8ebygrK8GJE+57MRcV5SEvr3x/z6ioKCil3PYcZKzwcCbPZsDkmYhMKyFBEtSFC237goJkpNPd2rSREoAVK6SmsHNnW4eQ3FwZHa7IHTW9GzdW/jDwww9S29upU90f3x3KyoBFiyrvX7rU9n1YmCy73qWLZ2O56iop01iwQLYvuAC45hrPPqfnaAAOmqDXUlhYOF57LQrWXLmoKA9PPQVER0e77TnIWCEh8vdYUiLfkzF46D3kxAk59RoSIjXLFXsVU+2VlMjolrUsgPxXTIzMAbj3XkmWmjcH3nkH6NjRM893xhmO5xjExkpSuHp1+f0V+1fXhrUsxF5oqGdGbWsrKAi46SZZ+dSeEUlrq1YyF2TzZqkPb9u26k49ZhcUFIqYmBZGh0E+RClb6QY/ExmHybMH7Nghb/Y//ijbEyfKxJnp02U0a+jQ8r2MyXl79gAvvwy88YZMUHruOeDmm4GGDY2OjDylY0cZady/X5LpFgbkGo0bS9I+cKD0gQ4KAp5+2j2jrJ06SemH/YTFRx+VJNFMBgyQcpJ335U38NGjpdzECI0bAz17GvPcREazlm6YKXmePHkyduzY4ZHHtj7uuHHjPPL4AJCWlobhw4c7fXsmzx7w+ee2xDklRU7tjh0r2z/8AEyeLKdA27SRfevXS+3g+vXAtddKuzpfHUnxtK++kuQZkBZm990nk7quuMLYuMizYmLkYqQePaQDzs6d0le4bVvHo8auatoUmDZNkuf162VZ8549zXdKNjFR/vbuu08+PKSm1r6DChHVXni4+RZO27FjB1av3o7CQvc3xg8Lk380S5Z45oeOiNhX840qMNm/Z99XWAh8+61te9AgGbGyl5srp3/btJFJN5dcIqNqgCTeL70EjBkDcI5HeXl5spR3RfPmMXkm70hOlouvPK67hYV5poMGETkvLMz9rTLdobAwATt33m90GC5LTX3V5fuwVZ2bhYdLL1orparv27pqlS1xtnr6aSlPoPIiIoAOHSrv98TkMSJ/tX+/1I8vXSpzM4jIt4SFmW/kOdAweXYzpYBhw2xL0s6YIUv82mvc2FYrad+/1qqkxPH+QBcaKiPy9u27WrUCLrrIuJiIfMnatdKdok8fWaFv5MjKH96JyNxCQmRRJTIOyzY84MwzZRnhTZtk0YCkJKB7d2DqVEmab7gB2LJF6py7d5f6yaNHbfd/6CH3zOL3R2efLYtVrF0ro/zp6VJXTuSMggJ57ezYIW3wOncOnIWIioulJMx+KevPPpN5FoMGGRcXEbnGrGUbgYTJs4e0aFG+K0BamrR6ys+X5Pjtt2V/VJSszLVwodRB3367zGoP8vNzAvv3Syu/6GgZpXellV/79nIhckVZGfDpp4D9hOqHHpKFUMy0GImnHDsmH+orWreOyTORLwkN5ciz0fw8RTOfzZttiTMAnDwJ3HgjcM89kkAPHw7ExxsXnzesWiXdBHr3lpH3J54ADh82Oiryd9u3S3s1ey+9BGzYYEw83tawIXD55ZX3s20mkW9h2YbxmDx72alTjvcfPWq+1lSekJ8PjBtnW5lNa2DSJCAz09i4yP8dPep4WVtPLPUNyKTfOXOAWbOkvZ3RQkOBBx8sv2rh3XdLazwi8h1Mno0XAOmauVhXMNu2zbYvLc3xqmb+6MgRYP78yvt37fJ6KBRgkpPlb82+j3+9ep5ZjGTzZuDKK4GtW2W7eXPgp5+MH+Vt3x749Vf5/xMR4XrJFBEZLyRE5jCQcTjy7GXNm0sHjqFDZcnfIUOkL7S/l2pYNW4s5RoV+UKPW3cqLpZJoxs3cuKHtzRrBnz5JdC1q2ynpMjKhdbFitxp1ixb4gwABw4AH33k/uepjbg4KZvq2pWJM5EvCg5m8mw0jjwboFMnYMoUGYVt3Fi6RgSK+vWBF16QldT27pV9Dz4IZGQYG5c3HTwoK7VNmiST2G67DXjqKXZY8Ybu3YFffpHfQePGklB7wooVlff99Ze84XFVPiKqi+BgaWlLxmHybJDw8MAZba6oa1fg779lAldUlKxYFkgjYPPnAy++aNv+6CP5QPXgg4aFFFAaN5aLJ115pawWau+mm5g4E1HdBQUxeTYayzbIEAkJslhDt26BlTgDwA8/VN732Wcs3/AnffvKxNjQUBkluusu4OqrjY6KiPxBcDBQWmp0FIGNI89EXtatGzBtWvl9PXtK43vyD82aAc88I6uNlpXJREX+fqmisrISnDjhoXYvAIqK8pCXV/e6wKioKCil3BARuQNHno3H5JmcUlYGrFwpC7lERkqNcuvWRkflm/r3l4VxNm6U7fh46e/N9yb/EhLimcmI5E80AM/1HAsLC8drr0XV6X9LUVEennoKiI6OdltcVDdBQfKeTMYxNHlWSmUByANQCqBEax1A08Z8y59/AhddZJvhm5AgE6/atTM2rppoLbXV+fnS0aNhQ6MjkoTq559lZbeSEqBjRy4xTq45elR6pUdFyag2P3j5pqCgUMTEtKj5hkR2goJYtmE0M9Q8X6i1TveFxPnwYUl49u/37vOeOiWjlNu3SzLobQUFwH//W741zr59jvs1m0l+PvDuu0CXLkB6uqyuZpbV5BITgcsuk6XYmTiTI0eOANnZlf/m160DLr1UXtNdugDvv1/14ktE5H+U4siz0cyQPPuEzEzgwgulK0JGBvDjj9558W7fDtx6qyxu0LmztDg7dszzz2vv9GnHi5hkZ3s3DletWAGMHGlLLP7+G3j8ccerzAUqrYGsLFk0IxD7hh44IBM4P/xQzq7k5xsdkfy9zZoFnHee/M0/+6x8WAUkvoceApYts22PGCFL3hNRYFDKmIE0sjE6edYAflZKLVdKjTA4liodOgTccAOwdq1sZ2fLzHlrzaqnlJUB77wDfPONbJ86BYwZAyxd6tnnrahhQ0lCK+rTp+r7aC0rua1fD+TleSqy6tmv4mg1c6b8PklGNidOBDp0AM48U1rl7dljdFTek5srr+sBA4A77wR69arcXs4ImZnAwIHApk0S45NPAlOnynUHDwJz51a+j6PXOhH5LybPxjI6eT5fa90NwOUA7lFKXVDxBkqpEUqpTKVUZk5OjvcjhCzm4ejN6fBhGZH11Ehmbi4wfXrl/d5OngHg+utlBKxRIykz+OIL4JxzHN/WvlyiY0dg8GBZrtjbmjevvK9zZ6BBA+/HYkZ//AE8/LB8KCspAd58E/jqK6Oj8p61a4Hvviu/79//BnbuNCScfyxZUnnfW2/Jh74GDeSDTkX2r/XiYintWLTI+yVmVDP797SCgsNGh+NX7I8tYEy+4A1GjDybIRczE0OTZ631PsvXQwC+BXC2g9u8p7XO0FpnxMXFeTtEADLyaj/ROC4O+L//A+6/H2jVCrjxRs/U0kZHS7JXUVqa+5+rJvHxwH/+I2/Ky5bJsuJV9WdevlxG9E6elO2ffwaefx4o8tykcoe6dZOk36pePeDVV80xadAMfv658r4pU2y/N3/nqPwpL8/40g1HC7gkJAAREUCTJpJIR0barrv5ZtuS43l5wCuvyPb558sH3MxM154/N1fKxU6cqPWPQNWwf0+LjGxidDh+xf7YAsbkC95gRPJshlzMTAxLnpVS9ZVS0dbvAVwCYJ1R8VQnLQ14+23bjPa77gIee0zqDEtLZfTqzjvdX4scGSmnbO0T9549pRbSWcXFwNat8mZY19m5SgEtWgCxsdXfbtOmyvu++UZOOTuruBg4fty1+Cpq1kwSjQULgO+/l6S+V6+6PaY/cTSC2bWrJGmBoG3byj/rhRcav0z6uedKZxir4GDgueeAmBjZ7t1bXsvffw8sXAi89pp8oAekleTDD9t6wO7dC4wa5fz/pgUL5G/kjDNklUTWUhOZD7vrGM/IVnXNAHxrabweAuAzrbWDaj5zuO46STZ27JAR1Iqz2//+W1pHuXtU8+yzZaR340YZOe3UyfllvfftAyZNAl5/Xd6AH3oIuPdeSSo9yVG5RIcOtjf/mqxYIXEvXy6jajffXPuOFI0by0qGVNkll0iv7q1bZbthQ2D0aOlPHAjatwd++knOIK1bJ/MYnnmm/Ot03Top7wgNlQ8WrVp5Pq42bYB582TE+MQJed5u3WzXKyX/ixx9+MnKqrxv2TIgJ6fm/01btgBXXGEbeV+4UOZ6/PFHzR+Yich7WO9sPMPeJrXWOwB0Mer5XRUWJm9g3brJm0pF9evLxRPatpWLq2bPlu4cgIxE/fe/kjDccIN746soI0Pawv34o2xHRkoy7Eyt8ZYtQL9+tpGy8eOl3vzdd4Hwui+URXasSdqaNfKBsFOnwFvU44ILgN9+kyS1WbPyI9HLlslItDWZTEiQ4+UoaXW31q1rtwhRUlLlfZ06OS4FqWjbtsolK5s2SULO5JnIPLTm6LPRAmSMyb06dpRa2i++sO2bONGYWuSqlJVVXgIakPIJTyfPLVpI7ezatVKD2bat8wnHhg2VTzFPmwY8+qj5F2TxRcnJ5UsEAlGjRnKxV1IitcP2yeS+fTJS7Y3kubbS02VuwvPPyxtso0bSsaeJE6W1jhLsyEjnzxgRkXeYMXnOzs5GREQ+UlNfNToUl0VE7EV2tmujn0yea6FxY5l4duutUsfburWcWjXTizkoSEo+Fi0qv9/+9K8nNW0qI8iucjS6HB4up83NZvVqKTEJCwO6d2dybybWSY9RUbW7f1GR40nA1hIXs2rQQOZjXHutrEKYlgakplZ/n1On5P9YUpLUR7/1lu26SZOk/pmIzMVM+UYgYvJcS82aAf37Gx1F9YYNAz791NbXODlZ6jqrc+qUJB6xsZKAe1vnznJZs8a2b/z4qhOAo0flA8Jvv0nJQb9+tTvd7aq//5ZT+oWFsh0bKzF06uT556aq5edLacV//ytnX8aNk5Uc7SfdOqNePWD4cOCee8rvN/vfPCCxO/shecMGmQsxZ46cIZo8WRLv7GxJvLt0cc//Aa2lxeZnn8nf7C23SDcQ+64hROScsjJj3p+rEx8fj927C7Fz5/1Gh+Ky1NRXER/v2kx5Js9+rHNnYPFimfQUFCSJXXUT7xYvlu4eGzZI0nDOOVIyceQIcPfdMsvfU3XdVgkJwIwZwO+/yyTJPn2ku4ijfxRaAx99JAvHWLVrJ6fWPdkxoaREzjxYE2dA2nv98AOTZ6P98QdwzTW27SFDpCvFwIGuP9Y110gSOWmS1EI/95wkfP7i+HHgX/8C/vpLtjdvBi6+WM6m1OasUXWWL5f/H6dPy/a0aTIn44or3Ps8RIFAa/Mlz4GGyXMNzFhb5IpWrZzrELBhg7xxWruIhITIiJ215dWsWcC339pGrg8ckD7B334rJQuDBrmvFtTZmHftAp54ovy+TZuknMLTybOjRXMcdTog79i7V1oxTplS+br33qtd8hwfDzz9tIxABwfLBzt/snu3LXG2On1aJu22b+/e55o715Y4W02YAPTty9FnIleVlcn/JDIOP7tU4ehR4OuvgUsvlTdPI1b186b1622Jc/Pm0hfamjhb/d//yWqKxcXSxeO226TH9fjxcjp7927vxlxcXH70136/s4qKpP2gKyuxRUTISHxFV11VfvvUKUnqPLUCJcmx/fRTmSh38cWOE7G6dIoICpIPYv6WOANSD+6onKXi5El3qPi/BJC/PbbcInIdk2fjBfTIc1mZJIknT0o5g/2bxowZckrT6tNPpawhPd3bUXqH/WqBVY22BwXJ/qwsWws8q6ws6a7hzQUmkpPld/Tuu7Z9MTHSU9oZO3ZIV4IpU2QS6MsvS72nMyNhV14JvPQS8OKLjk/pr1oFPP64LDpx4YWytHkXn2nM6DtWrJA+4ABw+LAsYBQebhvlDA0FRowwLj4zS02V8qM77rDtGzpUugm522WXyd+IfRL98MNVr1IaKMrKSnDiRK7RYVSrqCgPeXmu9wmNioqC8uXTtibGsg3jBWzynJ8PTJ0KjB0ro1fdu0sS1bGj1K8++2z52xcUAEuW+G/y3KWLTDJasUJm3qelSeJhP4r7yCOSKGrteMSorMx78QLS5eKxxyQJmDpVfoYxY6rvia21jJAHBQFvvAF88IHsz8mRJGzhQudWIWzaVF47N90kIwBNm9qu27dPRqGtI/GzZskHi8WLnV/ghpyzeXP57ZdekoVOSkrkg16/ftJ3nBwbOlT+XrZulUnQ3bo519bOVWedJfMY3npL5lCMGiUfKkkDKDI6iGqFhYXjtdeiXCpfLCrKw1NPAdGuztQlp5SWBs5iVmYVsId/5cryM+mXL5fk8Kuv5E3X0ac6f/6kl5goPaAXL5akr0cP6R7x2WfyZnfHHbaR1dRUefN77TXb/Vu0MGayXMuW8nsbOVJGjE+dkgR4714ZmU5Pt01yzM0F3n9fOjHccYf8bBWtWuXaEt6OkuHt2yuXsGRlyX4mz+5lXZba6uBBmYz2xx/uX+3TH0VGynLg555bu/sfOSKv7agoaWlX1f/I4GD5/3H++ebsFGCUoKBQxMS0MDoM8jFMno0XsIff0YSvH3+Utm4pKTJR6NZbbddFRUn3CX+WklK5G4ej7gKhoXLKtUMHKWfp0UNaT9V2CW13iImRxHniREmOrSZNAu67T2L+7TdpXQZIcpucLKf67blj6XJHvYWVqr5TSVmZdHYIDw+M1dwOHJCzHDk50mKwa9fyq/s5q1s3GV3+9VfZDg2VUgQmzp63fr3Me1i+XH53EybIh9KaBhuZOBPVTWmpOdc+CCQBmzw7GgHs3Nm2mtbAgdLi6pNPZHTzhhvkel+3c6d8cGjQwNYdIzdXan6dWT7bKiFBakmHDzdPN5JNm6Su0t6jj0q9Zfv2clbBas4cmQC5dq2tNKVbN1lYprZyc6UDSHS0JOyvv2677v77qy4n2bNH6rZff11OmU+cKBMwrcnk7t1yRmDLFikv6tHDM6fWvSUnR2qTZ8607fv0U+DGG11/rIQE+RtdvVpWpjzzTM/U7Bpt82Z5rQYHS3mS0auZFhTISobLl8t2YSHwwAPyIeiCC2TfoUNyJic3Vz4gde4spVZEVDdMno0XsMlzt24yWmpdwrp+fUlerEvUNmggCXRtWlyZ1ZIlkpQdOSKJ2dSpUoO4YIEkja+95vroulkSZ0A6pFSsxS4uti333bGjdFCx7p84UfpEKyUJb3q6rLJ28qRMZHJlhGz1akn+NmyQU+HTpknSnpUlbfe6d696ctTUqbak/8QJaftnrb3OyZFJkfPm2W7/5JMyGdFXT9utXl0+cQbkw0avXnL8XdW8uVz81cqVMrp+9KhsJyZKL3N3t5NzxaFD0te8oq1bJXnOyZHSrm++kf1KyYfXQYO8GyeRPyopYfJstIA9gRYXJ6d3//hDJnStWCGnzm+6CbjuOuCXXxy3QfNVx4/L6OeRI7I9bJiUXixYINtLlwIDBvh2r+LU1Mqn6xMSbOUkgwaVL8soKJDSkxtvlO4ZxcUy2ezcc+VYrVtX/rG2bQOmT5dJhsuXy6d/AMjLA0aPti3nXFAADB4ssYwaJe0OqyrFOHQIeOedyvuXLJGv69eXT5wB6RDiqOzIV1g/zNg7ckQm8VJ5Wsvrw5o4A1LPP3u2cTEBMrjQtWvl/S0s5burV9sSZ0B+jlGjZDItEdVNSQnP4hjNR8eu3KNRI1tN7x9/SMN+a8eIr7+W0Z1LLjEuPnc6dgxYtsy2HRsrJQb2cnOlfZuRtct1kZYmH4RGjJDVCbt3B95+2/aG3rEj8OefsvR3WZlMcLSWUuTlyWnnWbNke+1aGR39808ZDd2yRV4L1mMWEiKLxFx4oSTACxdWjmfHjponYkVGyuNXTCqs3Tsc9YguLq684IQvadu2cieXSy6REVUqr7hYSh8qqvjBztsaNpTWjpddJmdqABl46N5dvrd+SLd36JD8nRFR3RQXm3PkOSJiH1JTX3X744aF5QAAioriarhl7URE7APgxMpsdgI6ebY3fXrlVmuvvSanS/2hGXlsrPws1lHMoCD5uayjp1au1D2b0fnnSyJ75IicXai44MMZZ8ilou3bbYmz1e7dsj8pSZJo+w8bJSVSPnH22ZJItG1buW1aCycm0UdHS8nGpZfaeuCmptqS7rZt5XeXa9cK9qKL5Da+qkMHqTm/5x45zX/NNXIMHE20dOT0aflwlJ0tv5t27Xy3hKUmYWHA7bdXXqSp4oI8RjjvPDkDs3Wr/N/o0MH299amTeX/LxdfzA9IRO5QXCyTy80kzYMTMXbsKLY8Ry1mlTullcvx++lbjntYFwXxB/XrS43vkCGS5M2eDTz0kMyQt/r3vyUR8XWxsa53rAgNld+39QNUcLD0kF6wAJg82fFy4bt3y8hwbKxM+Ovf37ZK4913O78oSu/eskzymjXye8rIsD1fWpqcAXn+eSnlGDRIkk7rxFZfFBQkHwAWL5aRyGbNnF+iuagI+PBD4N575XcVEiL15ddf7z9/qxUNHCjlVK+8Ij/vE08Affq4/jhVLX5UnexsGfk+eVImY3boUP4x2rSRS0UdO8qE67vvljKTyy+X/z/OfkAioqqZMXkePny4xx57nKVN1gsvvOCx53AVk2eLG26Q2kL70ef77vOvtkqdO8uo7M6dMuLZvLmMeO7aJSNC3bpV307Nn51xhiSl1g4Zo0ZJB4gdO2Tb0d/syJG2JL13b6mb37ZNJp126OB8ghscLAlzVYt5dOsmsZw4IY9d3ZmQkyeBv/+W33NSksTlKLkxgyZNXO8asmmTLXEGZLT+X/+ScoHWrSvfvrhYRkdXr5YzBPYfTHxFixYyMn/XXbblwp1NgktK5IPZO+/I62fUKJnQ58zf+e7dMh9g0SLZjoiQUiVn+qCHhABXXCGlYnl58jME6v8WIncrKjJf8hxomDxb9OgBzJ8vo1pFRcCdd9Z+4QAza9q0/Gp4tRnB8kfh4TLSfO65shJaRkb5VnNffikJ9OTJUhJy//22ZaGt2ratfnXDusZXcUEQR775RiaDWqWlyeRXXy7zsHfgQOXyqvx86e7gKHmeN08mwlq7sLRuLf3cfS2BDg6u3e9w6VKpy7eWT8yeLeVJAwbUfN9ly2yJMyATqB95BJg71/kPhlV1QikpATIzJbGPipISECO7hxD5EjOOPAcaJs8WISEyouLK6nLkX5o3l+WKhw6VBMveypVS/7x4sdR1xsebr0wgO1tKcezt2CEj4v6SPCclyZuG/YTJJk2kq0pFR45IRxn79oVbt0pS6GvJc219/33leQ2TJkn9cU1vvtnZlfdt3ChnN+paNvTHHxKDNbYmTWTwwh97dBO52+nTtVtUitzH/UUJkZEHoJT2xCVz+XLJWKwXX20LQabXoYOsQGhv6FAp72jRwjuJc8WkpyZFRXJqviJ/arnYti3wxRe2ia1xcbJd8XcFyM/tKAF01CqvNgoKJBH/7jspDTHjcXZU4hMc7Nzr11Eie+ON5c9c1UZBgawCav/6PnxYVgAlopoVFTF5Npr7k+fCwmbQGl65VOy1RuQmLVvKIhDjxsnZiLfekoVJvHGqbPduKRm54AJZIXH9euful5go/abtRURISz5/ERQknSZWrpTa7uXLpYuMI82by4Q1e0rJYjh1VVwMvPeedFu55hrgrLNksRtrxxSzGDiwcieSsWOd6xF71lnS07xhQzlu118PPPhg3TubFBU5/lBj31GGiKpWWOj8JGvyDJZt+Jm9e2VyVF6ejJ527Gi+8gJf0aGDdLmoTZeC2iookG4KU6fK9uLFMrK6YIEk9NUJDpZJrk2aAO+/LxMFH3vMP5aVryg1teZSlKAgmWQHyIS5+HhZkt3ai7guNm0CxoyxbWstH1x69TKmdrewUMpUGjcuPyJ19tkyefSTT+SsxG23SX2xM+rXB+64Q8orCgrk9eeO0a4GDWTOQMUPNhddVPfHJvJ3WnPk2QyYPPuRXbtkdUTrYijh4TI7/oILjI3L13nzw8eOHcDHH5ffl5UlqxfWlDwDUhP8yCOyUExkJHDwoIyQ/vyzLAI0YICcLs/Lk9tW7IPtb1q2lBKBe+6R4+Gunzcnp3JZTVFR9aOnO3ZIm8j69SXBdrWdYlXWrgWefVYmhvbpI/3HrW0Sg4KAnj3lUlu1WTK9JtdcI6P3EyfKyPazz0qiH2jKykpw4kTdhtzDwsKgTDZCUlSUByDa6DD8UlGRnDnyp05gvojJs4/Ly5M3zwMHZCKP/SqCp0/LaX9XZseTsYKC5FIxMXP1H2WjRrIk++jRslIiIKsk5udLMnnihLTA++gj/xyZtqeUcwvWuCI5Wdo92q+Y17hx1R9wMjOlLaR15b0BA2Q03NFER1ccOCC9v7dule1vv5WSlkWL3P8zu1PTptJycOhQ6bHu64sz1Z4GUFTrexcXn8TYsVGIjjZbohqNKDb19ojCQo46m4H3k+fly6WXVkGBrCrx6quVh/a0lvN6c+YA9eoBU6bIOz2Vk58PvPii9IAND5c3o4q2bHHP7HjyjrQ06cVr3yavQwe5uGrrVlviDMgCOQ8/bNtesULKPGbPlkTQkW3b5IxGkyaygA7/aYtWrSRRvfVWYP9+GZ2dNs3xHOaCAhkNtl+yevZsqdkeNKhucWzfbkucrbKy5Pdm5uTZypXR95MnZRGiuk5YNJOgoFDExNT+F3X6dB6io2HC5Jk85fRpSYvIWN5PnkeOlGa555wjyfPcubL8lL0ff5R3hK1bZVm1kSPlK5Wzfr0kzoD8QTVuXPk2t9wiK7iRbwgPl7MFGRmS+PboIZO+ajNCWXH02lE3iIULZfKWo/fe33+XyXl5eTLy/cUXUq6wZInUp/bt6xsJmqf06ydneg4dkr+x+HjHtzt+vPwZISvrAjx1UdWbqD8tSFJaKq/Txx+XybR33y0fWjxRTkJkdoWFTJ7NwLtVM9nZcr64Rw8Zbb71VunzVNH338t1Ssltjx1zPD07wB06VH77++9lhKtJE0l2brtNRharW5GOzKdFC3n5f/21dEao7QqBbdqUXwTHUaeQlBTHp8wPHJDXj7Us4eabZZGYUaNkMuMtt8hrraCgdrH5ixYtpHtHVYkzIH+PV19deb87ymXatpW/cXt33+25xXqMsGoVcMklMnl2715JoiuuBksUKJg8m4N3k+d9+6SfllViouxzdDv7YYWqbhfgUlPLt5xaulQqXRYtknKNd9+VMgAKTI0aSdeNF16QCWNJSeVXHwwLk9eIozMTOTnAnj227dRUKfOw98EHlUsGqLLQUOnMYV2AKTQUeOYZaQVXV/XqAePHSxnI//4nqwc+/bSs2ucv1qyp3ALwjTekXIYo0BQU+NeZJV/FCYM+7MwzgRkzZCnxgwelJvWNN/xr1InqplUrKQN56CE5A3H11fJ6yc2VpaqraqvWtKncd/t22bZfpc9Ka9cXcglUbdtKYrtzp9SNn3FG3fslW8XFAVdcIRd/5ChRaNyYyxNTYGLybA7eTZ4TEuS8m9XevY6LORMSyg97VXW7ABcUJG+YmZkyGalFC/e1vyL/Yi3dadgQOP/8mm/frJmUZ1x7rZQHHTtWPpkG5LV3xhmeiNY/NWjgngVaAk337nLmY+dO276XXpIPDUSBprDQv84s+Srvlm3Ex0vbh7//lmGrjz+WGUkVDRwo12ktt23QoOqiwk8+ka+nTkmB5xdfyPbx47I9Y4Zs5+bK9qxZsn3ggGzPnSvbe/bI9i+/yPaOHbK9YIFsb94s24sXy/a6dbJtnQm0apVsr1ol28uWyfa6dbK9eLFsb94s2wsWyLZ11pC1Sav1Q8PcubJ94IBsz5ol29ZGsjNmyPbx40hMBDpv/AKxg/vIcbAelz59pJkqIB1L7AtgJ08uvyrBW2+Vn7j56qvye7CaOLF8a4AJE6TPlNWzz0phrNUTTwC3327bHjdOmg9bjR0rzXetHnhALlb33CO3sRoxQh7D6vbb5Tmsbr5ZYrAaOlRitBo0SH4Gq4ED5We0uvxyOQZWF10kx8iqTx85hoAc0z59/P61d16rA1i2DFg/YRae/6sPZn2Ui7FjgTGpM5CV2gevP3dcJhp+8YXcn689wdeeW//vtbqzD+Z9nospU4AZt8zA0fQ+uOL843K9u197Xtb06Dakr5oCAAgqLcawKX3QeY38bkOLT2HYlD7osE5+t+GFxzFsSh+cuVF+t/VO5WL4p/0R/OOP8mBm/916WVtsRvzMdxFUkI/gvGNIH90LzX/4AEEF+Qg5moP00b3QbO5UBBXkIzR3P9JH90LcL58hqCAfYQd2IX10L8TO/wpBBfkI37cD6aN7ockf3yGoIB+RuzcjfXQvNF48G0EF+ai3Yx3SR/dCo6VzEVSQj/pbVyJ9dC80XP4rggryEbVxKdJH90LM6oUIKshH9Lq/kD66F6LX/YWggnzErF6I9NG9ELVxKYIK8tFw+a9IH90L9beuRFBBPhotnYv00b1Qb8c6nD5xGj1OGntssXmzV/8nDf/0U6Tu3m17bhO8br1ftvHWW7ZWdZdfbvvH9c478vXuu6ULx5w5MqxVr540oyUir2vZEkB7AD9KmdD/nQ8UdwfC3gGQYmxsFDhatQJanQNZd2M3AB9emlgpNQLACABoH8zaE3eyP7adAaS9ch9SXnsQ0BqhZUWov24JUl++r9x22sSRtu31S1Gmgv/ZbutgW6tgQJchtKwY7dYPKrd95riroFUwlC5DSFkx2j/cv9x2x39fAq2C/tnudP+F5bY733uBZbsUIWUl6HJ3z/LbwzPQRStM7j8DOGngsWXNFJR2VMxYp0dU2mGBpCco5bgYk4iIyAVKqeVa6wxvPmezZul65MhVtb7/6dN5eOwx8/d5NuLYdoyK1Y/f/LU3n9LjVFkprnv/EqxdUYIu6bI+hhHHNiMjQ2dmZnrt+cZZzvy98MILXntOq6qOLycMEhERkV+JiChf3eUXThYA0+v/kziTcbg6OhEREZHZ5edztqBJMHkmIiIiMrtTp6TpAhmOyTMRERGR2Z08yeTZJNxf8xwRcRBKOVizzAOSk73yNERERESGys+X1r1kOPePPBcUNIfWyhOXjO7dpbuG9ZKV5fbwiYiIiEwnP19WuiLDsdsGERGRAcrKSnDihCx8FRYWBqVc66JQVJQHaX5NAeHkSSbPJsHkmYiIyABxOIixeB4ni4sRNXZcLfo1RyOK3RcCx8mTQKNGRkdBYPJMRERkiNCgILSIiUHe6dNAdLTpFzshg508KcttkuHYbYOIiIjI7PLzOfJsEhx5JiIi4x06BOzZIzWdaWmAi/W/RH6PybNpcOSZyB9t3w488wxw4YVAQgLQrBlwxhnADTcAH38MFBQYHSGRzfLlwHnnARkZQHo6MG0acPq00VERmcuJE0DjxkZHYaySEuDRR4GUFKB3b2DpUkPC4MgzkT/ZsQO4807g77+BsjKgqMh23aFDklTPng2MGgWMGQM8/jgQGmpcvERHjgD/+hewbZtsnzwJ3HYb0L69JNNEJE6eBJo0MToKY02aBLz4ony/axdwxRXA7t1AZKRXw+DIM5G/mDIF6NQJ+OMPoLCwfOJs7+RJOf03cSLQsSP7pZOxDhwAVq2qvH/nTq+HQmRqx4+zbGPevPLbubnAypVeDyOwkuf9+4EvvwT+8x9gxgz5p03kD956C7jnHuDUKaC01Ln7nDolo31nnSWf4ImM0KgRkJhYeX98vPdjITKz48f9f+R5yxZg+nRg717H16enl9+OiADatfN4WBUFTvJ8/Licpr7+euD554FBg4Ann5QEgsiXLV0KjB1bu9dyWRlw9CjQv7/UkhF5W3w88P77QHi4bd9DD8lZFCISRUVAcTHgz329335bEuEbbpBJw99/X/k2jz8OXHqpfB8bC3zwgSF14IGTPG/aJJ9m7L33HrB5szHxELlDSQkwZEjdJgCWlkrpxsSJbguLyCWXXCKnXmfNknr98eOBBg2MjorIPKwlG/7ahaa0VKoCtJbt4mJJlCtq2BCYO1cGffbvB2680athWgVO8lxY6Np+Il8wcyZw+HD1twkPlw+PWgOvv+74NqdOARMmVF0nTeRJSgFnngkMGACccw7AxUKIyjtxwr9LNkpKgLy88vuOHq369g0bGjrZPXCS5zZtpFWXvfR0oHVrQ8Ihcov//U8mAFbniScc15RWVFYG/PCDe+IiIiL38fd65/Bw4NZby+8bMcKYWJwQOMlzfDzw7bfA7bcDycnA3XcDn34qNTNEvqisTPrjVqdTJ+DBB6W+vyYnTwK//eae2IiIyH2OH/f/fOWdd4A33wTuuEN6vY8fb3REVQqsPs8dOwLvvisvwoYNgZDA+vHJz2RlAcHBVV+vlEzEevNNIDOz5sfTGvjrL7eFR0REbnLsGBAXZ3QUnhUaKmsQ+IDAGXm2Cg2VT29MnMnXHT9effJ8++2yCtPHH8sqg4BMwqpu9OL4cbeGSEREbnD8uKwUS6bADJLIV0VESOlGVZKSgKZNgTVrbPtuuUWWPR4+vOrHJCIiczlxgsmziTB5JvJVaWmSCFflyy+Bdevk+w4dgKefBn78UXppVqVLF/fGSERVKikrQ+6JE8grKkITa4suIkdOnPD/sg0fwuSZyFeFh0sCXVWv8o0b5QLIEqYAsH07sGKF49vXqwf07u3+OInIIQ2gCECxv/buJfc5epQjzyYSeDXPRP5k1ChJemuyYIFMILzvvqpvU1YGDB7svtiIqFqhQUFoEROD+KgoKCbQVJ1jx6QMj0zBf5PnlBRJFgLhkpJi9NEmo9x2GxDkhj/j8HBZqbBRo7o/FhERudfhw0yeTcR/k+ddu6T1ViBcdu0y+miTURo0AN54A6hfv26PU68e8PLL7omJiIjcp6gIyM8HGjc2OhKy8N/kmShQ3Hor0L+/c+UbjkRGAl99xX/MRERmdOyYtBh1x1lGcgv+Joh8nVLAZ58BV17p2gh0cLDc/uuvgX79PBcfERHV3tGj7LRhMkyeifxBSAjw+efA5MlATAwQFVX1bZWSpDkjA1i7VkatiYjInI4cAeLjjY6C7DB5rmjmTGDCBPc9XnAwkJ4ul4EDq77dl18C7dtLP94bb3T9/kRKATfcAGRnA6++KslxRISUZdSvL6trxsUB110H/PKLLMWdmmp01EREVB0mz6ZjSJ9npdRTAIYDyLHsekxrPceIWCoZONC9SWpkJLBqVfW32boVeOEFYNEi6XZw6JBr9yeyV68ecMcdcikrAw4elAknDRvKBEPynNOngcJCHmcicp/Dh5k8m4yRI88va63TLRfPJ85ZWUC7dsCwYUCbNsBNN8no23nnAa1bA0uXyu2mTAHuvVe+HzYMGD0aOPdcWYzi6689E9vkycA999jahLEdDblLUJD8001OZkLnaX/9Je3+zjkHmDQJ2LvX6IiIyB8cPQokJBgdhTn89JOsb/DKK8CpU4aFEVhlG9u2AWPGAJs2yeWzz4A//wQmTgSef97xfbKz5TazZwOPPmrbn57u3HMWFsrp8x49gO++c3ybLVvkct55cru5c127PxEZa+1amXQ5c6as+Dh2LPD660BpqdGREZGvO3qUI88AMG0acNllwNtvAw8+CAwaZFgoRi7Pfa9S6lYAmQDGaK2POrqRUmoEgBEA0LJly7o9Y2oq0KmTfN+hg7zZKSX7srIc3+fqq2X0rn17Of1t5Wwpxa5d8olxxw6gb195rlatyt+mpERKN+bPl9GqCy6QN+OGDZ27PxEZa+1aoKCg/L5XX5URkuRkY2IiU7J/T0uIjjY4Gv9SLl+oa+97MzFBzbNbczEAkydPxo4dO5y6rfV2WdOmIcX+irlz8eKoUTjm4KxqWloahg8fXuc4q+KxkWel1C9KqXUOLlcBeBtAKwDpALIBTKrqcbTW72mtM7TWGXF1bdUSHm77PijIth0UJAlsTffRuvrHX7LENrlv5kzZZz3VkpYG9OkDrFxZ+X6JiVJnHRoqCX6bNpJMO3t/IjKW/f8Jq6go+ZsmsmP/ntYkMtLocPxKuXwhIsLocNwnNxdo0cLQENyai7koMjISkZGROF3h/2ypUig26H+sx0aetdYXOXM7pdRkALM9FYdXnXNO+RHpo0dl8lZ4uLz4Fy0CHn648v2uvlrajN1+u9xuyxZJlp29P5nfjh1SE7t/P3DWWXLxp5GRQNe1K5CSUv4M1osvGv6GR0Q+rqxM3v/9rGyjVqPCixYBl1zyT61z8L334vFXX3VzZM4xqttGvNY627J5DYB1RsRRJ+npNZdubNwI3HWXjGyXlUnNdPv2ct0TT0gt88CBwKWXAj//LNcFBwMvvQQ0aQIsXlz1/cl37N4tH5DWrrXtmzYNuPlmw0IiN0tLk4ksv/0mCXS/fjJPgYioLo4dk7NYjs5uBZrzzpOc6OWXZXvaNBl07NrV66EoXVMpgieeVKlpkJINDSALwF12yXSVMjIydGZmprNPUnOZhb8IpJ/VF333HXDNNeX3xcUBq1f73WgCka9SSi3XWmd48zk7Nm2q/7rzTuQVFSH6qacQ7ac10EYc24zYWJ3pqQ5Z3rRlC/Daa8A6x2OMhhxbV3Ixd8rJkbN59mW2V18NfPutx56yquNryMiz1voWI56XyBCO2ukcPSqdVIgoYIUlJgKPPYZoAFHVrQpKgcsE9c6mcexY5flpOTkOb+ppgdWqjsgIHToAYWHl940YIRNFiShgBQUFITo6GtHR0VBKGR0OmVFuLt8rrFq3ltINe3fcYUgoRraqIwoMnTsD8+YBjz8uXVRuv13qttiJgYiIqpObK3MqSMyeLW1At26VckiDej0zeSbyNKWkd/ecOUB+vqwgyVEmIiKqyeHDQO/eRkdhHg0bAk8+aXQUfpw8JycHToLCRRh8Q1SUXIiIiJxx+DCX5jYh/02eq1oxkIiIiMgXHDoEJCUZHQVVwAmDRERERGajNXDgAJNnE2LyTERERGQ2eXlASAgQE2N0JFQBk2ciIiIiszl0iG3qTIrJMxEREZHZ5OSwZMOkmDwTERERmc3Bg0DLlkZHQQ4orbXRMThNKZUDYFct7x4LINeN4fgzHivX8Hi5hsfLeTxWrqnL8UrWWse5M5iaKKXyAGz25nO6kSvHmsdWeOLv2YhjW5dcrLaM+l/o8Pj6VPJcF0qpTK11htFx+AIeK9fweLmGx8t5PFau8bXj5Wvx2jN77GaMz4wx+QqzHTuWbRAREREROYnJMxERERGRkwIpeX7P6AB8CI+Va3i8XMPj5TweK9f42vHytXjtmT12M8Znxph8hamOXcDUPBMRERER1VUgjTwTEREREdWJ3yfPSqnLlFKblVLblFKPGh2P2SilkpRSvyulNiil1iul7rfsb6yUmqeU2mr52sjoWM1CKRWslFqplJpt2U5VSi2xvMa+UEqFGR2jWSilGiqlvlZKbVJKbVRK9eRrq2pKqQctf4frlFKfK6Ui+PoSSqkPlVKHlFLr7PY5fC0p8ZrlmK1RSnUzLvLKfO19qZr3iaeUUvuUUqssl/5eiqfa46eUCrf8rWyz/O2k2F03zrJ/s1LqUiPjUUo1sRzXk0qpN9wRC3mHXyfPSqlgAG8CuBxAewA3KKXaGxuV6ZQAGKO1bg+gB4B7LMfoUQC/aq1bA/jVsk3ifgAb7bZfBPCy1voMAEcB3GlIVOb0KoC5Wut2ALpAjhtfWw4opRIAjAaQobXuCCAYwFDw9WU1BcBlFfZV9Vq6HEBry2UEgLe9FGONfPR9qar3CUBem+mWyxxPB+Lk8bsTwFHL38zLkL8hWG43FEAHyGvpLcvjGRIPgEIA4wGMrUsM5H1+nTwDOBvANq31Dq11EYDpAK4yOCZT0Vpna61XWL7PgyQ3CZDjNNVys6kArjYkQJNRSiUCuALA+5ZtBaAvgK8tN+GxslBKNQBwAYAPAEBrXaS1Pga+tqoTAiBSKRUCoB6AbPD1BQDQWi8EcKTC7qpeS1cB+FiLvwE0VErFeyXQmvnc+1I17xNGcOb42b8uvgbQz/K/+ioA07XWp7XWOwFsszyeIfForfO11n9CkmjyIf6ePCcA2GO3vRfG/cGbnuVUUlcASwA001pnW646AKCZUXGZzCsAHgZQZtluAuCY1rrEss3XmE0qgBwAH1nKXN5XStUHX1sOaa33AZgIYDckaT4OYDn4+qpOVa8lM//vN3NsNarwPgEA91pKYz70UgmWM8fvn9tY/naOQ/5Xe+LY1yUe8lH+njyTk5RSUQC+AfCA1vqE/XVaWrIEfFsWpdQAAIe01suNjsVHhADoBuBtrXVXAPmoUKLB15aNJfG4CvKhowWA+qhcpkBV4GvJ8xy8T7wNoBWAdMgHvknGRUfkPf6ePO8DkGS3nWjZR3aUUqGQf4ifaq1nWHYftJ7mtHw9ZFR8JnIegIFKqSzIqbm+kJrehpbT7ABfY/b2AtirtbaOUH0NSab52nLsIgA7tdY5WutiADMgrzm+vqpW1WvJzP/7zRxblRy9T2itD2qtS7XWZQAmo+4lEM5w5vj9cxvL304DAIedvK834yEf5e/J8zIArS2z1cMgEwVmGhyTqVjqwD4AsFFr/T+7q2YCuM3y/W0Avvd2bGajtR6ntU7UWqdAXku/aa1vAvA7gMGWm/FYWWitDwDYo5Rqa9nVD8AG8LVVld0Aeiil6ln+Lq3Hi6+vqlX1WpoJ4FZL140eAI7blXcYzefel6p6n6hQR34NgHUV7+sBzhw/+9fFYMj/am3ZP9TS/SIVMqF0qYHxkK/SWvv1BUB/AFsAbAfwH6PjMdsFwPmQU51rAKyyXPpD6rF+BbAVwC8AGhsdq5kuAPoAmG35Pg3yD3gbgK8AhBsdn1kukNO5mZbX13cAGvG1Ve3xehrAJkgSMg1AOF9f/xybzyGlAcWQsxp3VvVaAqAgHRC2A1gL6WBi+M9g97P41PtSNe8T0yzHdw0kQYw36vgBeAbAQMv3EZa/lW2Wv500u/v+x3K/zQAuN0E8WZCJsCctr+v2Rv++ean5whUGiYiIiIic5O9lG0REREREbsPkmYiIiIjISUyeiYiIiIicxOSZiIiIiMhJTJ6JiIiIiJzE5JmIiMgHKaWaK6WmK6W2K6WWK6XmKKXauPHx+yilznXX45mVUqpUKbVKKbVeKbVaKTVGKeXW/EgpdbdS6lbL98OUUi3c+fjkXSE134SIiIjMxLJwybcApmqth1r2dQHQDNJz2B36QPoPL3bT45lVgdY6HQCUUk0BfAYgBsCT7noCrfU7dpvDIL3c97vr8cm7OPJMRETkey4EUGyflGmtVwP4Uyn1klJqnVJqrVLqeuCfUeTZ1tsqpd5QSg2zfJ+llHpaKbXCcp92SqkUAHcDeNAyKtvLmz+cUbTWhwCMAHCvZYXKYMvxXKaUWqOUugv453jOV0p9rZTapJT61PKBBkqpCUqpDZbbT7Tse0opNVYpNRhABoBPLcf1CqXUd9bnV0pdrJT61us/OLmEI89ERES+pyOA5Q72XwtZ2bMLgFgAy5RSC514vFytdTel1CgAY7XW/1JKvQPgpNZ6oruC9gVa6x1KqWAATQFcBVne/SylVDiARUqpny037QqgA2QEeRGA85RSGyFLlbfTWmulVMMKj/21UupeyDHOtCTck5RScVrrHAC3A/jQGz8n1R5HnomIiPzH+QA+11qXaq0PAlgA4Cwn7jfD8nU5gBQPxeaLLgFwq1JqFYAlkCXhW1uuW6q13qu1LoMsWZ4C4DiAQgAfKKWuBXCqugfXsszzNAA3WxLtngB+dPtPQW7FkWciIiLfsx7AYBduX4LyA2YRFa4/bflaigDPDZRSaZDjcAiAAnCf1vqnCrfpA9sxg+X2IVrrEqXU2QD6QX4/9wLoW8NTfgRgFiTp/kprXeKGH4M8iCPPREREvuc3AOFKqRHWHUqpzgCOAbjeUqsbB+ACAEsB7ALQXikVbhnh7OfEc+QBiHZ34GZmOWbvAHjDMir8E4CRSqlQy/VtlFL1q7l/FIAGWus5AB6ElM9UVO64aq33Q0o/Hock0mRyAf3pkoiIyBdZ6mmvAfCKUuoRyKhlFoAHAEQBWA1AA3hYa30AAJRSX0K6POwEsNKJp5kF4Gul1FWQ0dc/3P1zmESkpSwjFDJCPw3A/yzXvQ8px1hhqU/OAXB1NY8VDeB7pVQEZNT63w5uMwXAO0qpAgA9tdYFAD4FEKe13ljXH4Y8T8kHKyIiIiIyglLqDQArtdYfGB0L1YzJMxEREZFBlFLLAeQDuFhrfbqm25PxmDwTERERETmJEwaJiIiIiJzE5JmIiIiIyElMnomIiIiInMTkmYiIiIjISUyeiYiIiIicxOSZiIiIiMhJ/w/K8q+Gq3+1ogAAAABJRU5ErkJggg==",
-      "text/plain": [
-       "<Figure size 864x432 with 4 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "axs = data[\"price(euro)\"].cleaner.detect('bounded', lower=0., upper=30)\\\n",
-    "                    .plot(color='blue', errors_color='red', compact=True, limits=True, figsize=(12,6))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "946fd049",
-   "metadata": {},
-   "source": [
-    "### Key Collision"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "8b541e28",
-   "metadata": {},
-   "source": [
-    "Pandas-cleaner offers a plotting method for the keycollision detector as well.\n",
-    "This makes it easier to visualize the different legal values detected by the keycollision algorithm and how many different representations there are for each legal value."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 33,
-   "id": "40300897",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       "<Figure size 432x288 with 1 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "axs = data[\"variety\"].cleaner.detect('keycollision').plot()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "19e9e79d",
-   "metadata": {},
-   "source": [
-    "The graph makes it easy to visualize the legal values. This helps to both explore the dataset and evaluate the relevance of the keycollision algorithm. \n",
-    "\n",
-    "Here, we can easily see, for example, that the \"granny\" entry was represented with three distinct values.\n",
-    "The graph also shows the values kept by the keycollision algorithm. For instance, we can note that the key collision algorithm failed to spot the misspelling of \"bigarrau\" and considered it as a distinct legal value while it should have replaced it with \"bigarreaux\"."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "702ddf65",
-   "metadata": {},
-   "source": [
-    "The plotting method offers options to compact the graph and focus on some part of the data by plotting only a given number of most and least frequent entries:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 34,
-   "id": "f42a1637",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "image/png": "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",
-      "text/plain": [
-       "<Figure size 576x288 with 1 Axes>"
-      ]
-     },
-     "metadata": {
-      "needs_background": "light"
-     },
-     "output_type": "display_data"
-    }
-   ],
-   "source": [
-    "axs = data[\"variety\"].cleaner.detect('keycollision')\\\n",
-    "                    .plot(cmap='cividis', not_displayed_color='red', nfirst=3, nlast=2, figsize=(8,4))"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "10913944",
-   "metadata": {},
-   "source": [
-    "## Cleaning"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "91dc6d79",
-   "metadata": {},
-   "source": [
-    "Pandas-cleaner offers multiple methods to clean the detected errors. These can be listed by running :\n",
-    "```(python)\n",
-    "pdcleaner.series_cleaning_methods.keys()\n",
-    "```\n",
-    "\n",
-    "The cleaning methods are used to replace the detected errors with more relevent values.\n",
-    "Cleaning methods can be called on dataframes even if the detection methods were initially applied on a column of the dataframe. \n",
-    "The replacement can be done inplace by modifying the same pandas object, or by creating a modified copy of it.\n",
-    "\n",
-    "Note that nan values are not considered as errors and are kept intact."
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "b091c71c",
-   "metadata": {},
-   "source": [
-    "### Clip\n",
-    "For bounded detectors, clipping refers to replacing the detected errors with the bounds. Thus, if a value is too high it will be replaced by the highest value allowed, while low values will be replaced by the minimum value allowed."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 35,
-   "id": "abbf2d43",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "lowest value allowed : 0.00040050000000000014\n",
-      "highest value allowed : 0.007971\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "2     0.007971\n",
-       "9     0.000401\n",
-       "10    0.007971\n",
-       "11    0.007971\n",
-       "14    0.007971\n",
-       "15    0.000401\n",
-       "19    0.007971\n",
-       "20    0.000401\n",
-       "22    0.000401\n",
-       "30    0.000401\n",
-       "38    0.000401\n",
-       "41    0.000401\n",
-       "46    0.007971\n",
-       "61    0.007971\n",
-       "74    0.000401\n",
-       "75    0.000401\n",
-       "85    0.000401\n",
-       "90    0.007971\n",
-       "92    0.007971\n",
-       "93    0.007971\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 35,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "print(f\"lowest value allowed : {quantiles_detector.lower}\")\n",
-    "print(f\"highest value allowed : {quantiles_detector.upper}\")\n",
-    "s_gaussian.cleaner.clean(detector_obj=quantiles_detector, method=\"clip\")[quantiles_detector.index]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "5c0be69d",
-   "metadata": {},
-   "source": [
-    "### To Na\n",
-    "Pandas-cleaner allows to simply replace the values indicating errors with Na values.\n",
-    "This may make the errors easier to spot and homogenize the process of treating both Na values and errors in the data. This also allows treating errors with methods like fillna."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 36,
-   "id": "98ab10c1",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "2    NaN\n",
-       "9    NaN\n",
-       "10   NaN\n",
-       "11   NaN\n",
-       "14   NaN\n",
-       "15   NaN\n",
-       "19   NaN\n",
-       "20   NaN\n",
-       "22   NaN\n",
-       "30   NaN\n",
-       "38   NaN\n",
-       "41   NaN\n",
-       "46   NaN\n",
-       "61   NaN\n",
-       "74   NaN\n",
-       "75   NaN\n",
-       "85   NaN\n",
-       "90   NaN\n",
-       "92   NaN\n",
-       "93   NaN\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 36,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "s_gaussian.cleaner.clean(detector_obj=quantiles_detector, method=\"to_na\")[quantiles_detector.index]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "f2ceae48",
-   "metadata": {},
-   "source": [
-    "### Replacement\n",
-    "The replacement cleaning method allows replacing detected errors with a specified value.\n",
-    "This method can be seen as an equivalent of fillna but in the case of detected errors. \n",
-    "\n",
-    "In the following example we compute the median and replace errors with it."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 37,
-   "id": "3ac213a2",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "median value to replace with : 0.00557\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "2     0.00557\n",
-       "9     0.00557\n",
-       "10    0.00557\n",
-       "11    0.00557\n",
-       "14    0.00557\n",
-       "15    0.00557\n",
-       "19    0.00557\n",
-       "20    0.00557\n",
-       "22    0.00557\n",
-       "30    0.00557\n",
-       "38    0.00557\n",
-       "41    0.00557\n",
-       "46    0.00557\n",
-       "61    0.00557\n",
-       "74    0.00557\n",
-       "75    0.00557\n",
-       "85    0.00557\n",
-       "90    0.00557\n",
-       "92    0.00557\n",
-       "93    0.00557\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 37,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "median_value = s_gaussian.median()\n",
-    "print(f\"median value to replace with : {median_value}\")\n",
-    "s_gaussian.cleaner.clean(detector_obj=quantiles_detector, value=median_value, method=\"replace\")[quantiles_detector.index]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "fd31e6d0",
-   "metadata": {},
-   "source": [
-    "### Drop\n",
-    "Pandas-cleaner allows to drop entries containing errors in a similar way to dropna.\n",
-    "The following code snippet removes the rows that have errors from the series."
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 38,
-   "id": "a33f9e11",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "0     0.00525\n",
-       "1     0.00571\n",
-       "3     0.00473\n",
-       "4     0.00390\n",
-       "5     0.00567\n",
-       "       ...   \n",
-       "95    0.00741\n",
-       "96    0.00732\n",
-       "97    0.00502\n",
-       "98    0.00622\n",
-       "99    0.00632\n",
-       "Name: pesticide_content(mg/kg), Length: 80, dtype: float64"
-      ]
-     },
-     "execution_count": 38,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "s_gaussian.cleaner.clean(detector_obj=quantiles_detector, method=\"drop\")"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "6a7577eb",
-   "metadata": {},
-   "source": [
-    "### Keys\n",
-    "\n",
-    "This cleaning method is mainly used with the key collision detector. It replaces values that have multiple representations by a single value.\n",
-    "\n",
-    "For example, in this dataset we had detected a few values that had alternative representations:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 39,
-   "id": "4d4b1bc0",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1       granny,\n",
-       "3        Granny\n",
-       "18    de, Milan\n",
-       "29      golden2\n",
-       "38     de.Milan\n",
-       "41     de milan\n",
-       "45     Milan de\n",
-       "55     DE NANCY\n",
-       "Name: variety, dtype: object"
-      ]
-     },
-     "execution_count": 39,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "keycollision_detector.detected"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "5c89a2ab",
-   "metadata": {},
-   "source": [
-    "These can be replaced by their most frequent representation :"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 40,
-   "id": "5ce93d3d",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "1       granny\n",
-       "3       granny\n",
-       "18    de Milan\n",
-       "29      golden\n",
-       "38    de Milan\n",
-       "41    de Milan\n",
-       "45    de Milan\n",
-       "55    de Nancy\n",
-       "Name: variety, dtype: object"
-      ]
-     },
-     "execution_count": 40,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "data[\"variety\"].cleaner.clean(detector_obj=keycollision_detector, method=\"bykeys\")[keycollision_detector.index]"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "a34e4713",
-   "metadata": {},
-   "source": [
-    "### Cleaning Inplace\n",
-    "\n",
-    "most cleaning method support cleaning the data inplace by modifying directly the treated dataframe or series. This can be simply done using the argument `inplace=True` in most cleaning methods.\n",
-    "\n",
-    "Here's an example:"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 41,
-   "id": "2b08f814",
-   "metadata": {},
-   "outputs": [
-    {
-     "data": {
-      "text/plain": [
-       "0    0.00525\n",
-       "1    0.00571\n",
-       "2    0.00860\n",
-       "3    0.00473\n",
-       "4    0.00390\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 41,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "series_copy =  s_gaussian.copy()\n",
-    "series_copy.head()"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "76a834c8",
-   "metadata": {},
-   "source": [
-    "#### Returning a New Series When Cleaning "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 42,
-   "id": "7145ce80",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "Here's the clean series:\n",
-      "2    NaN\n",
-      "9    NaN\n",
-      "10   NaN\n",
-      "11   NaN\n",
-      "14   NaN\n",
-      "15   NaN\n",
-      "19   NaN\n",
-      "20   NaN\n",
-      "22   NaN\n",
-      "30   NaN\n",
-      "38   NaN\n",
-      "41   NaN\n",
-      "46   NaN\n",
-      "61   NaN\n",
-      "74   NaN\n",
-      "75   NaN\n",
-      "85   NaN\n",
-      "90   NaN\n",
-      "92   NaN\n",
-      "93   NaN\n",
-      "Name: pesticide_content(mg/kg), dtype: float64\n",
-      "And the original series is kept intact: \n",
-      "2      0.00860\n",
-      "9      0.00000\n",
-      "10     0.00992\n",
-      "11     0.00807\n",
-      "14    56.00000\n",
-      "15     0.00000\n",
-      "19     0.00831\n",
-      "20     0.00000\n",
-      "22     0.00000\n",
-      "30     0.00000\n",
-      "38     0.00000\n",
-      "41     0.00000\n",
-      "46     0.00822\n",
-      "61     0.00852\n",
-      "74     0.00000\n",
-      "75     0.00000\n",
-      "85     0.00000\n",
-      "90     0.01100\n",
-      "92     0.00832\n",
-      "93     0.00848\n",
-      "Name: pesticide_content(mg/kg), dtype: float64\n"
-     ]
-    }
-   ],
-   "source": [
-    "print(\"Here's the clean series:\")\n",
-    "print(series_copy.cleaner.clean.to_na(detector_obj=quantiles_detector)[quantiles_detector.index])\n",
-    "print(\"And the original series is kept intact: \")\n",
-    "print(series_copy[quantiles_detector.index])"
-   ]
-  },
-  {
-   "cell_type": "markdown",
-   "id": "7ffa2434",
-   "metadata": {},
-   "source": [
-    "#### Cleaning Series Inplace "
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": 43,
-   "id": "edc9490c",
-   "metadata": {},
-   "outputs": [
-    {
-     "name": "stdout",
-     "output_type": "stream",
-     "text": [
-      "The series was cleaned inplace:\n"
-     ]
-    },
-    {
-     "data": {
-      "text/plain": [
-       "2    NaN\n",
-       "9    NaN\n",
-       "10   NaN\n",
-       "11   NaN\n",
-       "14   NaN\n",
-       "15   NaN\n",
-       "19   NaN\n",
-       "20   NaN\n",
-       "22   NaN\n",
-       "30   NaN\n",
-       "38   NaN\n",
-       "41   NaN\n",
-       "46   NaN\n",
-       "61   NaN\n",
-       "74   NaN\n",
-       "75   NaN\n",
-       "85   NaN\n",
-       "90   NaN\n",
-       "92   NaN\n",
-       "93   NaN\n",
-       "Name: pesticide_content(mg/kg), dtype: float64"
-      ]
-     },
-     "execution_count": 43,
-     "metadata": {},
-     "output_type": "execute_result"
-    }
-   ],
-   "source": [
-    "series_copy.cleaner.clean.to_na(detector_obj=quantiles_detector, inplace=True)\n",
-    "print(\"The series was cleaned inplace:\")\n",
-    "series_copy[quantiles_detector.index]"
-   ]
-  },
-  {
-   "cell_type": "code",
-   "execution_count": null,
-   "id": "3daf044e",
-   "metadata": {},
-   "outputs": [],
-   "source": []
-  }
- ],
- "metadata": {
-  "interpreter": {
-   "hash": "703ca24be5df84d841d012d5ad58ea3627f38800985b18c41fa74c5dc4d6e62e"
-  },
-  "kernelspec": {
-   "display_name": "Python 3 (ipykernel)",
-   "language": "python",
-   "name": "python3"
-  },
-  "language_info": {
-   "codemirror_mode": {
-    "name": "ipython",
-    "version": 3
-   },
-   "file_extension": ".py",
-   "mimetype": "text/x-python",
-   "name": "python",
-   "nbconvert_exporter": "python",
-   "pygments_lexer": "ipython3",
-   "version": "3.8.12"
-  },
-  "toc": {
-   "base_numbering": 1,
-   "nav_menu": {},
-   "number_sections": true,
-   "sideBar": true,
-   "skip_h1_title": false,
-   "title_cell": "Table of Contents",
-   "title_sidebar": "Contents",
-   "toc_cell": false,
-   "toc_position": {
-    "height": "calc(100% - 180px)",
-    "left": "10px",
-    "top": "150px",
-    "width": "370.594px"
-   },
-   "toc_section_display": true,
-   "toc_window_display": true
-  }
- },
- "nbformat": 4,
- "nbformat_minor": 5
-}


Test patch:
diff --git a/pdcleaner/tests/test_cat_keycollision.py b/pdcleaner/tests/test_cat_keycollision.py
deleted file mode 100644
index 07942ba..0000000
--- a/pdcleaner/tests/test_cat_keycollision.py
+++ /dev/null
@@ -1,47 +0,0 @@
-"""Tests for `pdcleaner` detection method (keycol_series)
-based on key collisions."""
-
-import pytest
-import pandas as pd
-from pandas.testing import assert_series_equal
-
-
-def test_raise_if_numerical_series(series_with_outlier):
-    with pytest.raises(TypeError, match="applies to categorical/string Series"):
-        series_with_outlier.cleaner.detect('keycollision')
-
-
-def test_wrong_method(keycol_series):
-    with pytest.raises(ValueError, match='ot a valid method'):
-        keycol_series.cleaner.detect('keycollision', keys='blabla')
-
-
-def test_method_not_a_string(keycol_series):
-    with pytest.raises(TypeError, match='must be a string'):
-        keycol_series.cleaner.detect('keycollision', keys=42)
-
-
-def test_keycollision(keycol_series):
-    results = keycol_series.cleaner.detect.keycollision()
-    expected = pd.Series([False, True, True, False, False, ])
-    assert_series_equal(results.is_error(), expected)
-
-
-def test_keycollision_with_nan(keycol_series_with_nan):
-    results = keycol_series_with_nan.cleaner.detect.keycollision()
-    expected = pd.Series([False, False, True, True, False, ])
-    assert_series_equal(results.is_error(), expected)
-
-
-def test_keycollision_from_existing_detector(keycol_series, keycol_test_series):
-    detector = keycol_series.cleaner.detect.keycollision()
-    results_test = keycol_test_series.cleaner.detect(detector)
-    expected = pd.Series([True, False])
-    assert_series_equal(results_test.is_error(), expected)
-
-
-def test_keycollision_dict(keycol_series):
-    results = keycol_series.cleaner.detect.keycollision().dict_keys
-    expected = {'linus torvalds': 'Linus Torvalds',
-                'bill gates': 'Bill Gates'}
-    assert results == expected
diff --git a/pdcleaner/tests/test_clean.py b/pdcleaner/tests/test_clean.py
deleted file mode 100644
index 4b68ded..0000000
--- a/pdcleaner/tests/test_clean.py
+++ /dev/null
@@ -1,298 +0,0 @@
-import pytest
-
-import numpy as np
-import pandas as pd
-from pandas.testing import assert_series_equal, assert_frame_equal
-
-
-# API
-
-
-def test_not_a_valid_argument(series_with_outlier):
-    detector = series_with_outlier.cleaner.detect('iqr')
-    with pytest.raises(TypeError, match="is not a valid argument for clean()"):
-        series_with_outlier.cleaner.clean(1, detector)
-
-
-def test_not_a_valid_method(series_with_outlier):
-    detector = series_with_outlier.cleaner.detect('iqr')
-    with pytest.raises(ValueError, match="is not a valid cleaning method"):
-        series_with_outlier.cleaner.clean('bad_method', detector)
-
-
-def test_not_a_bounded_detector(cat_series):
-    detector = cat_series.cleaner.detect('types', str)
-    with pytest.raises(ValueError, match="does not have lower and upper bounds and can not"):
-        cat_series.cleaner.clean('clip', detector)
-
-
-def test_no_keys(cat_series):
-    detector = cat_series.cleaner.detect('types', str)
-    with pytest.raises(ValueError, match="method does not have a keys dictionary"):
-        cat_series.cleaner.clean('bykeys', detector)
-
-
-# TestCleanSeries:
-
-
-def test_drop_num_series_direct_call(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean.drop(results)
-    expected = pd.Series([1, 2, 4], index=[0, 1, 3])
-    assert_series_equal(cleaned, expected)
-
-
-def test_drop_num_series(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean('drop', results)
-    expected = pd.Series([1, 2, 4], index=[0, 1, 3])
-    assert_series_equal(cleaned, expected)
-
-
-def test_replace_num_series(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean('replace', results, value=0)
-    expected = pd.Series([1, 2, 0, 4])
-    assert_series_equal(cleaned, expected)
-
-
-def test_replace_num_series_direct_call(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean.replace(results, value=0)
-    expected = pd.Series([1, 2, 0, 4])
-    assert_series_equal(cleaned, expected)
-
-
-def test_clip_num_series(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean('clip', results)
-    expected = pd.Series([1, 2, 10, 4])
-    assert_series_equal(cleaned, expected)
-
-
-def test_clip_num_series_direct_call(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean.clip(results)
-    expected = pd.Series([1, 2, 10, 4])
-    assert_series_equal(cleaned, expected)
-
-
-def test_to_na_num_series(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean('to_na', results)
-    expected = pd.Series([1, 2, np.nan, 4])
-    assert_series_equal(cleaned, expected)
-
-
-def test_to_na_num_series_direct_call(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_outlier.cleaner.clean.to_na(results)
-    expected = pd.Series([1, 2, np.nan, 4])
-    assert_series_equal(cleaned, expected)
-
-
-def test_clean_series_inplace(series_with_outlier):
-    results = series_with_outlier.cleaner.detect.bounded(upper=10)
-    series_with_outlier.cleaner.clean('clip', results, inplace=True)
-    expected = pd.Series([1, 2, 10, 4])
-    assert_series_equal(series_with_outlier, expected)
-
-
-# TestCleanDataFrameColumn:
-
-
-def test_drop_num_col(df_quanti_quali):
-    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
-    msg = "Dropping inplace will not modify the DataFrame"
-    with pytest.warns(UserWarning, match=msg):
-        df_quanti_quali['num'].cleaner.clean('drop', results, inplace=True)
-
-
-def test_replace_num_col(df_quanti_quali):
-    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
-    df_quanti_quali['num'].cleaner.clean('replace', results, value=0, inplace=True)
-    expected = pd.Series([1, 2, 0, 4, 5], name='num')
-    assert_series_equal(df_quanti_quali['num'], expected)
-
-
-def test_clip_num_col(df_quanti_quali):
-    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
-    df_quanti_quali['num'].cleaner.clean('clip', results, inplace=True)
-    expected = pd.Series([1, 2, 10, 4, 5], name='num')
-    assert_series_equal(df_quanti_quali['num'], expected)
-
-
-def test_to_na_num_col(df_quanti_quali):
-    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
-    df_quanti_quali['num'].cleaner.clean('to_na', results, inplace=True)
-    expected = pd.Series([1, 2, np.nan, 4, 5], name='num')
-    assert_series_equal(df_quanti_quali['num'], expected)
-
-
-# TestBykeys:
-
-
-def test_bykeys_keycollision(keycol_series):
-    results = keycol_series.cleaner.detect.keycollision()
-    corrected = keycol_series.cleaner.clean('bykeys', results)
-    expected = pd.Series(['Linus Torvalds',
-                          'Linus Torvalds',
-                          'Linus Torvalds',
-                          'Linus Torvalds',
-                          'Bill Gates',
-                          ])
-    assert_series_equal(corrected, expected)
-
-
-def test_bykeys_keycollision_inplace(keycol_series):
-    results = keycol_series.cleaner.detect.keycollision()
-    keycol_series.cleaner.clean('bykeys', results, inplace=True)
-    expected = pd.Series(['Linus Torvalds',
-                          'Linus Torvalds',
-                          'Linus Torvalds',
-                          'Linus Torvalds',
-                          'Bill Gates',
-                          ])
-    assert_series_equal(keycol_series, expected)
-
-
-def test_bykeys_from_existing_detector(keycol_series, keycol_test_series):
-    results = keycol_series.cleaner.detect.keycollision()
-    corrected = keycol_test_series.cleaner.clean('bykeys', results)
-    expected = pd.Series(['Linus Torvalds', 'Bill Gates', ])
-    assert_series_equal(corrected, expected)
-
-
-def test_bykeys_from_existing_inplace(keycol_series, keycol_test_series):
-    results = keycol_series.cleaner.detect.keycollision()
-    keycol_test_series.cleaner.clean('bykeys', results, inplace=True)
-    expected = pd.Series(['Linus Torvalds', 'Bill Gates', ])
-    assert_series_equal(keycol_test_series, expected)
-
-
-# TestCleanReplace:
-
-
-def test_replace_with_value(series_with_nan):
-    # pd.Series([np.nan, 2, 100, 3])
-    results = series_with_nan.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_nan.cleaner.clean('replace', results, value=0)
-    expected = pd.Series([np.nan, 2, 0, 3])
-    assert_series_equal(cleaned, expected)
-
-
-def test_replace_inplace(series_with_nan):
-    series_obj = series_with_nan
-    # pd.Series([np.nan, 2, 100, 3])
-    results = series_obj.cleaner.detect.bounded(upper=10)
-    series_obj.cleaner.clean('replace', results, value=0, inplace=True)
-    expected = pd.Series([np.nan, 2, 0, 3])
-    assert_series_equal(series_obj, expected)
-
-
-def test_replace_with_lambda(series_with_nan):
-    # pd.Series([np.nan, 2, 100, 3])
-    results = series_with_nan.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_nan.cleaner.clean('replace', results, value=lambda s: 5)
-    expected = pd.Series([np.nan, 2, 5, 3])
-    assert_series_equal(cleaned, expected)
-
-
-def test_replace_with_dict(series_with_nan):
-    # pd.Series([np.nan, 2, 100, 3])
-    results = series_with_nan.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_nan.cleaner.clean('replace', results, value={100: 1, 99: 9, 2: -2})
-    expected = pd.Series([np.nan, 2, 1, 3])
-    assert_series_equal(cleaned, expected)
-
-
-def test_replace_with_incomplete_dict(series_with_nan):
-    # pd.Series([np.nan, 2, 100, 3])
-    results = series_with_nan.cleaner.detect.bounded(upper=10)
-    cleaned = series_with_nan.cleaner.clean('replace', results, value={99: 9, 2: -2})
-    expected = pd.Series([np.nan, 2, np.nan, 3])
-    assert_series_equal(cleaned, expected)
-
-
-def test_cast_to_float(series_with_separate_numbers):
-    # pd.Series(['100 000', '154,5', '9 000', '250,12'], dtype='object')
-    results = series_with_separate_numbers.cleaner.detect.castable(target='float',
-                                                                   thousands=' ',
-                                                                   decimal=',')
-    cleaned = series_with_separate_numbers.cleaner.clean('cast', results)
-    expected = pd.Series([100000, 154.5, 9000, 250.12])
-    assert_series_equal(cleaned, expected)
-
-
-def test_cast_to_int(series_with_separate_numbers):
-    # pd.Series(['100 000', '154,5', '9 000', '250,12'], dtype='object')
-    results = series_with_separate_numbers.cleaner.detect.castable(target='int',
-                                                                   thousands=' ',
-                                                                   decimal=',')
-    cleaned = series_with_separate_numbers.cleaner.clean('cast', results)
-    expected = pd.Series([100000, np.nan, 9000, np.nan], dtype='Int32')
-    assert_series_equal(cleaned, expected)
-
-
-def test_cast_to_date(series_with_different_types):
-    # pd.Series(['1.05', '154', '15/05/2022', 'Alice'], dtype='object')
-    results = series_with_different_types.cleaner.detect.castable(target='date')
-    cleaned = series_with_different_types.cleaner.clean('cast', results, format="%d/%m/%Y")
-    expected = pd.Series([np.nan, np.nan, '2022-05-15',  np.nan], dtype='datetime64[ns]')
-    assert_series_equal(cleaned, expected)
-
-
-def test_cast_to_boolean(series_with_boolean):
-    detect_results = series_with_boolean.cleaner.detect('castable',
-                                                        target='boolean',
-                                                        bool_values={"Yes": True, "No": False})
-    cleaned = series_with_boolean.cleaner.clean('cast', detect_results)
-    expected = pd.Series([True, False, False, True, np.nan, np.nan])
-    assert_series_equal(cleaned, expected)
-
-
-def test_cast_with_different_detector(series_with_nan):
-    msg = "This cleaning method works only with the castable detector"
-    results = series_with_nan.cleaner.detect.bounded(upper=10)
-    with pytest.raises(ValueError, match=msg):
-        series_with_nan.cleaner.clean('cast', results)
-
-
-def test_clean_df_drop(df_quanti_quali):
-    detector = df_quanti_quali['cat'].cleaner.detect.enum(values=['cat', 'dog'])
-    df_clean = df_quanti_quali.cleaner.clean('drop', detector)
-    expected = pd.DataFrame({'num': pd.Series([1, 2, 100, 4]),
-                             'cat': pd.Series(['cat',
-                                               'cat',
-                                               'dog',
-                                               'dog',
-                                               ])})
-    assert_frame_equal(df_clean, expected)
-
-
-def test_clean_strip_left(series_with_extra_spaces):
-    detector = series_with_extra_spaces.cleaner.detect.spaces(side='left')
-    cleaned = series_with_extra_spaces.cleaner.clean.strip(detector)
-    expected = pd.Series(['Paris', 'Paris ', 'Lille', 'Lille ', 'Troyes'])
-    assert_series_equal(cleaned, expected)
-
-
-def test_clean_strip_right(series_with_extra_spaces):
-    detector = series_with_extra_spaces.cleaner.detect.spaces(side='right')
-    cleaned = series_with_extra_spaces.cleaner.clean.strip(detector)
-    expected = pd.Series(['Paris', 'Paris', ' Lille', ' Lille', 'Troyes'])
-    assert_series_equal(cleaned, expected)
-
-
-def test_clean_strip_both(series_with_extra_spaces):
-    detector = series_with_extra_spaces.cleaner.detect.spaces(side='both')
-    cleaned = series_with_extra_spaces.cleaner.clean.strip(detector)
-    expected = pd.Series(['Paris', 'Paris', 'Lille', 'Lille', 'Troyes'])
-    assert_series_equal(cleaned, expected)
-
-
-def test_clean_strip_wrong_detector(series_with_extra_spaces):
-    detector = series_with_extra_spaces.cleaner.detect.value(value='Paris')
-    msg = 'This cleaning method works only with the spaces detector'
-    with pytest.raises(ValueError, match=msg):
-        series_with_extra_spaces.cleaner.clean('strip', detector)
diff --git a/pytest.ini b/pytest.ini
index 8417df5..8f9820f 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,5 +1,5 @@
 [pytest]
-testpaths = pdcleaner/tests/
+testpaths = tests/
 markers =
     win32: mark a test as win32 to run on windows (use -m "not win32" to deselect the test when running pytest)
     unix: mark a test as unix to run on unix (use -m "not unix" to deselect the test when running pytest)
\ No newline at end of file
diff --git a/pdcleaner/tests/__init__.py b/tests/__init__.py
similarity index 100%
rename from pdcleaner/tests/__init__.py
rename to tests/__init__.py
diff --git a/pdcleaner/tests/conftest.py b/tests/conftest.py
similarity index 95%
rename from pdcleaner/tests/conftest.py
rename to tests/conftest.py
index f598c50..c2804af 100644
--- a/pdcleaner/tests/conftest.py
+++ b/tests/conftest.py
@@ -133,7 +133,7 @@ def cat_series_with_capital():
 
 
 @pytest.fixture
-def keycol_series():
+def altern_series():
     """Create a categorical series with alternative
     formulations for the same person"""
     return pd.Series(['Linus Torvalds',
@@ -145,7 +145,7 @@ def keycol_series():
 
 
 @pytest.fixture
-def keycol_series_with_nan():
+def altern_series_with_nan():
     """Create a categorical series with alternative
     formulations for the same person and a NaN"""
     return pd.Series(['Linus Torvalds',
@@ -157,15 +157,26 @@ def keycol_series_with_nan():
 
 
 @pytest.fixture
-def keycol_test_series():
+def altern_test_series():
     """Create a categorical series to test on a previously defined detector"""
     return pd.Series(['torvalds LinuS',
                       'Bill Gates'
                       ])
 
+@pytest.fixture
+def altern_series_first():
+    """Categorical series with alternative formulations for the same person.
+    In this case, the first encountered is not the most frequent"""
+    return pd.Series(['Linus Torvalds',
+                    'linus.torvalds',
+                    'Torvalds, Linus',
+                    'Torvalds, Linus',
+                    'Bill Gates',
+                    ])
+
 
 @pytest.fixture
-def keycol_plot_series():
+def altern_plot_series():
     """Create a categorical series to test plotting method"""
     return pd.Series(['Linus Torvalds',
                       'Torvalds, Linus',
@@ -335,4 +346,3 @@ def series_with_boolean():
 def series_with_datetime():
     """Create a dummy series containing date elements"""
     return pd.to_datetime(pd.Series(['2022-10-01', '2021-06-11', '2019-04-03', ' 2020-09-25']))
-
diff --git a/tests/pdcleaner/cleaning/test_clean.py b/tests/pdcleaner/cleaning/test_clean.py
new file mode 100644
index 0000000..47fcbce
--- /dev/null
+++ b/tests/pdcleaner/cleaning/test_clean.py
@@ -0,0 +1,156 @@
+import pytest
+
+import numpy as np
+import pandas as pd
+from pandas.testing import assert_series_equal
+
+
+# API
+
+
+def test_not_a_valid_argument(series_with_outlier):
+    detector = series_with_outlier.cleaner.detect('iqr')
+    with pytest.raises(TypeError, match="is not a valid argument for clean()"):
+        series_with_outlier.cleaner.clean(1, detector)
+
+
+def test_not_a_valid_method(series_with_outlier):
+    detector = series_with_outlier.cleaner.detect('iqr')
+    with pytest.raises(ValueError, match="is not a valid cleaning method"):
+        series_with_outlier.cleaner.clean('bad_method', detector)
+
+
+def test_not_a_bounded_detector(cat_series):
+    detector = cat_series.cleaner.detect('types', str)
+    with pytest.raises(ValueError, match="does not have lower and upper bounds and can not"):
+        cat_series.cleaner.clean('clip', detector)
+
+
+def test_no_keys(cat_series):
+    detector = cat_series.cleaner.detect('types', str)
+    with pytest.raises(ValueError, match="method does not have a keys dictionary"):
+        cat_series.cleaner.clean('alternatives', detector)
+
+# TestCleanSeries:
+
+
+def test_to_na_num_series(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean('to_na', results)
+    expected = pd.Series([1, 2, np.nan, 4])
+    assert_series_equal(cleaned, expected)
+
+
+def test_to_na_num_series_direct_call(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean.to_na(results)
+    expected = pd.Series([1, 2, np.nan, 4])
+    assert_series_equal(cleaned, expected)
+
+
+def test_clean_series_inplace(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    series_with_outlier.cleaner.clean('clip', results, inplace=True)
+    expected = pd.Series([1, 2, 10, 4])
+    assert_series_equal(series_with_outlier, expected)
+
+
+# TestCleanDataFrameColumn:
+
+def test_clip_num_col(df_quanti_quali):
+    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
+    df_quanti_quali['num'].cleaner.clean('clip', results, inplace=True)
+    expected = pd.Series([1, 2, 10, 4, 5], name='num')
+    assert_series_equal(df_quanti_quali['num'], expected)
+
+
+def test_to_na_num_col(df_quanti_quali):
+    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
+    df_quanti_quali['num'].cleaner.clean('to_na', results, inplace=True)
+    expected = pd.Series([1, 2, np.nan, 4, 5], name='num')
+    assert_series_equal(df_quanti_quali['num'], expected)
+
+
+# Testalternatives:
+
+
+def test_alternatives_alternatives(altern_series):
+    results = altern_series.cleaner.detect.alternatives()
+    corrected = altern_series.cleaner.clean('alternatives', results)
+    expected = pd.Series(['Linus Torvalds',
+                          'Linus Torvalds',
+                          'Linus Torvalds',
+                          'Linus Torvalds',
+                          'Bill Gates',
+                          ])
+    assert_series_equal(corrected, expected)
+
+
+def test_alternatives_alternatives_inplace(altern_series):
+    results = altern_series.cleaner.detect.alternatives()
+    altern_series.cleaner.clean('alternatives', results, inplace=True)
+    expected = pd.Series(['Linus Torvalds',
+                          'Linus Torvalds',
+                          'Linus Torvalds',
+                          'Linus Torvalds',
+                          'Bill Gates',
+                          ])
+    assert_series_equal(altern_series, expected)
+
+
+def test_alternatives_from_existing_detector(altern_series, altern_test_series):
+    results = altern_series.cleaner.detect.alternatives()
+    corrected = altern_test_series.cleaner.clean('alternatives', results)
+    expected = pd.Series(['Linus Torvalds', 'Bill Gates', ])
+    assert_series_equal(corrected, expected)
+
+
+def test_alternatives_from_existing_inplace(altern_series, altern_test_series):
+    results = altern_series.cleaner.detect.alternatives()
+    altern_test_series.cleaner.clean('alternatives', results, inplace=True)
+    expected = pd.Series(['Linus Torvalds', 'Bill Gates', ])
+    assert_series_equal(altern_test_series, expected)
+
+
+def test_cast_to_float(series_with_separate_numbers):
+    # pd.Series(['100 000', '154,5', '9 000', '250,12'], dtype='object')
+    results = series_with_separate_numbers.cleaner.detect.castable(target='float',
+                                                                   thousands=' ',
+                                                                   decimal=',')
+    cleaned = series_with_separate_numbers.cleaner.clean('cast', results)
+    expected = pd.Series([100000, 154.5, 9000, 250.12])
+    assert_series_equal(cleaned, expected)
+
+
+def test_cast_to_int(series_with_separate_numbers):
+    # pd.Series(['100 000', '154,5', '9 000', '250,12'], dtype='object')
+    results = series_with_separate_numbers.cleaner.detect.castable(target='int',
+                                                                   thousands=' ',
+                                                                   decimal=',')
+    cleaned = series_with_separate_numbers.cleaner.clean('cast', results)
+    expected = pd.Series([100000, np.nan, 9000, np.nan], dtype='Int32')
+    assert_series_equal(cleaned, expected)
+
+
+def test_cast_to_date(series_with_different_types):
+    # pd.Series(['1.05', '154', '15/05/2022', 'Alice'], dtype='object')
+    results = series_with_different_types.cleaner.detect.castable(target='date')
+    cleaned = series_with_different_types.cleaner.clean('cast', results, format="%d/%m/%Y")
+    expected = pd.Series([np.nan, np.nan, '2022-05-15',  np.nan], dtype='datetime64[ns]')
+    assert_series_equal(cleaned, expected)
+
+
+def test_cast_to_boolean(series_with_boolean):
+    detect_results = series_with_boolean.cleaner.detect('castable',
+                                                        target='boolean',
+                                                        bool_values={"Yes": True, "No": False})
+    cleaned = series_with_boolean.cleaner.clean('cast', detect_results)
+    expected = pd.Series([True, False, False, True, np.nan, np.nan])
+    assert_series_equal(cleaned, expected)
+
+
+def test_cast_with_different_detector(series_with_nan):
+    msg = "This cleaning method works only with the castable detector"
+    results = series_with_nan.cleaner.detect.bounded(upper=10)
+    with pytest.raises(ValueError, match=msg):
+        series_with_nan.cleaner.clean('cast', results)
diff --git a/tests/pdcleaner/cleaning/test_clean_clip.py b/tests/pdcleaner/cleaning/test_clean_clip.py
new file mode 100644
index 0000000..45ef6ba
--- /dev/null
+++ b/tests/pdcleaner/cleaning/test_clean_clip.py
@@ -0,0 +1,18 @@
+
+import pandas as pd
+from pandas.testing import assert_series_equal
+
+
+def test_clip_num_series(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean('clip', results)
+    expected = pd.Series([1, 2, 10, 4])
+    assert_series_equal(cleaned, expected)
+
+
+def test_clip_num_series_direct_call(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean.clip(results)
+    expected = pd.Series([1, 2, 10, 4])
+    assert_series_equal(cleaned, expected)
+
diff --git a/tests/pdcleaner/cleaning/test_clean_drop.py b/tests/pdcleaner/cleaning/test_clean_drop.py
new file mode 100644
index 0000000..114a4b4
--- /dev/null
+++ b/tests/pdcleaner/cleaning/test_clean_drop.py
@@ -0,0 +1,52 @@
+import pytest
+
+import numpy as np
+import pandas as pd
+from pandas.testing import assert_series_equal, assert_frame_equal
+
+
+def test_drop_num_series_direct_call(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean.drop(results)
+    expected = pd.Series([1, 2, 4], index=[0, 1, 3])
+    assert_series_equal(cleaned, expected)
+
+
+def test_drop_num_series(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean('drop', results)
+    expected = pd.Series([1, 2, 4], index=[0, 1, 3])
+    assert_series_equal(cleaned, expected)
+
+
+def test_drop_num_col(df_quanti_quali):
+    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
+    msg = "Dropping inplace will not modify the DataFrame"
+    with pytest.warns(UserWarning, match=msg):
+        df_quanti_quali['num'].cleaner.clean('drop', results, inplace=True)
+
+
+def test_clean_df_drop(df_quanti_quali):
+    detector = df_quanti_quali['cat'].cleaner.detect.enum(values=['cat', 'dog'])
+    df_clean = df_quanti_quali.cleaner.clean('drop', detector)
+    expected = pd.DataFrame({'num': pd.Series([1, 2, 100, 4]),
+                             'cat': pd.Series(['cat',
+                                               'cat',
+                                               'dog',
+                                               'dog',
+                                               ])})
+    assert_frame_equal(df_clean, expected)
+
+
+def test_clean_drop_df_df(df_quanti_quali):
+    df_quanti_quali.loc[0, 'num'] = np.nan
+    detector = df_quanti_quali.cleaner.detect("missing", how='any')
+    df_quanti_quali.cleaner.clean('drop', detector, inplace=True)
+    expected = pd.DataFrame({'num': [2., 100, 4, 5],
+                         'cat':['cat',
+                                'dog',
+                                'dog',
+                                'bird'
+                                ]},
+                            index=[1, 2, 3, 4])
+    assert_frame_equal(df_quanti_quali, expected)
\ No newline at end of file
diff --git a/tests/pdcleaner/cleaning/test_clean_replace.py b/tests/pdcleaner/cleaning/test_clean_replace.py
new file mode 100644
index 0000000..c0de8cd
--- /dev/null
+++ b/tests/pdcleaner/cleaning/test_clean_replace.py
@@ -0,0 +1,66 @@
+import numpy as np
+import pandas as pd
+from pandas.testing import assert_series_equal
+
+
+def test_replace_num_series(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean('replace', results, value=0)
+    expected = pd.Series([1, 2, 0, 4])
+    assert_series_equal(cleaned, expected)
+
+
+def test_replace_num_series_direct_call(series_with_outlier):
+    results = series_with_outlier.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_outlier.cleaner.clean.replace(results, value=0)
+    expected = pd.Series([1, 2, 0, 4])
+    assert_series_equal(cleaned, expected)
+
+
+def test_replace_num_col(df_quanti_quali):
+    results = df_quanti_quali['num'].cleaner.detect.bounded(upper=10)
+    df_quanti_quali['num'].cleaner.clean('replace', results, value=0, inplace=True)
+    expected = pd.Series([1, 2, 0, 4, 5], name='num')
+    assert_series_equal(df_quanti_quali['num'], expected)
+
+
+
+def test_replace_with_value(series_with_nan):
+    # pd.Series([np.nan, 2, 100, 3])
+    results = series_with_nan.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_nan.cleaner.clean('replace', results, value=0)
+    expected = pd.Series([np.nan, 2, 0, 3])
+    assert_series_equal(cleaned, expected)
+
+
+def test_replace_inplace(series_with_nan):
+    series_obj = series_with_nan
+    # pd.Series([np.nan, 2, 100, 3])
+    results = series_obj.cleaner.detect.bounded(upper=10)
+    series_obj.cleaner.clean('replace', results, value=0, inplace=True)
+    expected = pd.Series([np.nan, 2, 0, 3])
+    assert_series_equal(series_obj, expected)
+
+
+def test_replace_with_lambda(series_with_nan):
+    # pd.Series([np.nan, 2, 100, 3])
+    results = series_with_nan.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_nan.cleaner.clean('replace', results, value=lambda s: 5)
+    expected = pd.Series([np.nan, 2, 5, 3])
+    assert_series_equal(cleaned, expected)
+
+
+def test_replace_with_dict(series_with_nan):
+    # pd.Series([np.nan, 2, 100, 3])
+    results = series_with_nan.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_nan.cleaner.clean('replace', results, value={100: 1, 99: 9, 2: -2})
+    expected = pd.Series([np.nan, 2, 1, 3])
+    assert_series_equal(cleaned, expected)
+
+
+def test_replace_with_incomplete_dict(series_with_nan):
+    # pd.Series([np.nan, 2, 100, 3])
+    results = series_with_nan.cleaner.detect.bounded(upper=10)
+    cleaned = series_with_nan.cleaner.clean('replace', results, value={99: 9, 2: -2})
+    expected = pd.Series([np.nan, 2, np.nan, 3])
+    assert_series_equal(cleaned, expected)
diff --git a/tests/pdcleaner/cleaning/test_clean_strip.py b/tests/pdcleaner/cleaning/test_clean_strip.py
new file mode 100644
index 0000000..b706098
--- /dev/null
+++ b/tests/pdcleaner/cleaning/test_clean_strip.py
@@ -0,0 +1,33 @@
+
+import pytest
+
+import pandas as pd
+from pandas.testing import assert_series_equal
+
+
+def test_clean_strip_leading(series_with_extra_spaces):
+    detector = series_with_extra_spaces.cleaner.detect.spaces(side='leading')
+    cleaned = series_with_extra_spaces.cleaner.clean.strip(detector)
+    expected = pd.Series(['Paris', 'Paris ', 'Lille', 'Lille ', 'Troyes'])
+    assert_series_equal(cleaned, expected)
+
+
+def test_clean_strip_trailing(series_with_extra_spaces):
+    detector = series_with_extra_spaces.cleaner.detect.spaces(side='trailing')
+    cleaned = series_with_extra_spaces.cleaner.clean.strip(detector)
+    expected = pd.Series(['Paris', 'Paris', ' Lille', ' Lille', 'Troyes'])
+    assert_series_equal(cleaned, expected)
+
+
+def test_clean_strip_both(series_with_extra_spaces):
+    detector = series_with_extra_spaces.cleaner.detect.spaces(side='both')
+    cleaned = series_with_extra_spaces.cleaner.clean.strip(detector)
+    expected = pd.Series(['Paris', 'Paris', 'Lille', 'Lille', 'Troyes'])
+    assert_series_equal(cleaned, expected)
+
+
+def test_clean_strip_wrong_detector(series_with_extra_spaces):
+    detector = series_with_extra_spaces.cleaner.detect.value(value='Paris')
+    msg = 'This cleaning method works only with the spaces detector'
+    with pytest.raises(ValueError, match=msg):
+        series_with_extra_spaces.cleaner.clean('strip', detector)
diff --git a/tests/pdcleaner/detection/test_alternatives.py b/tests/pdcleaner/detection/test_alternatives.py
new file mode 100644
index 0000000..90f565b
--- /dev/null
+++ b/tests/pdcleaner/detection/test_alternatives.py
@@ -0,0 +1,65 @@
+"""Tests for `pdcleaner` detection method (altern_series)
+based on key collisions."""
+
+import pytest
+import pandas as pd
+from pandas.testing import assert_series_equal
+
+
+def test_raise_if_numerical_series(series_with_outlier):
+    with pytest.raises(TypeError, match="applies to categorical/string Series"):
+        series_with_outlier.cleaner.detect('alternatives')
+
+
+def test_wrong_method(altern_series):
+    with pytest.raises(ValueError, match='ot a valid method'):
+        altern_series.cleaner.detect('alternatives', keys='blabla')
+
+
+def test_method_not_a_string(altern_series):
+    with pytest.raises(TypeError, match='must be a string'):
+        altern_series.cleaner.detect('alternatives', keys=42)
+
+
+def test_alternatives(altern_series):
+    results = altern_series.cleaner.detect.alternatives()
+    expected = pd.Series([False, True, True, False, False, ])
+    assert_series_equal(results.is_error(), expected)
+
+
+def test_alternatives_with_nan(altern_series_with_nan):
+    results = altern_series_with_nan.cleaner.detect.alternatives()
+    expected = pd.Series([False, False, True, True, False, ])
+    assert_series_equal(results.is_error(), expected)
+
+
+def test_alternatives_from_existing_detector(altern_series, altern_test_series):
+    detector = altern_series.cleaner.detect.alternatives()
+    results_test = altern_test_series.cleaner.detect(detector)
+    expected = pd.Series([True, False])
+    assert_series_equal(results_test.is_error(), expected)
+
+
+def test_alternatives_dict(altern_series):
+    results = altern_series.cleaner.detect.alternatives().dict_keys
+    expected = {'linus torvalds': 'Linus Torvalds',
+                'bill gates': 'Bill Gates'}
+    assert results == expected
+
+
+def test_alternatives_keep_first(altern_series_first):
+    results = altern_series_first.cleaner.detect.alternatives(keep='first')
+    expected = pd.Series([False, True, True, True, False, ])
+    assert_series_equal(results.is_error(), expected)
+
+
+def test_alternatives_wrong_value_for_keep(altern_series):
+    match = "keep should have the value 'mode' or 'first'"
+    with pytest.raises(ValueError, match=match):
+        altern_series.cleaner.detect.alternatives(keep='toto')
+
+
+def test_alternatives_wrong_type_for_keep(altern_series):
+    match = "keep should have the value 'mode' or 'first'"
+    with pytest.raises(ValueError, match=match):
+        altern_series.cleaner.detect.alternatives(keep=1)
\ No newline at end of file
diff --git a/pdcleaner/tests/test_cat_associations.py b/tests/pdcleaner/detection/test_associations.py
similarity index 97%
rename from pdcleaner/tests/test_cat_associations.py
rename to tests/pdcleaner/detection/test_associations.py
index ba63bd3..b223e69 100644
--- a/pdcleaner/tests/test_cat_associations.py
+++ b/tests/pdcleaner/detection/test_associations.py
@@ -92,7 +92,7 @@ def test_errors_detected_with_freq(df_two_cat_cols):
     detector = df_two_cat_cols.cleaner.detect.associations(freq=0.05)
     expected_detected = pd.DataFrame({'col1': 'B', 'col2': 'a'}, index=[19])
     expected_errors = pd.Series([False] * 19 + [True])
-    assert_frame_equal(detector.detected, expected_detected)
+    assert_frame_equal(detector.detected(), expected_detected)
     assert_series_equal(detector.is_error(), expected_errors)
 
 
@@ -102,7 +102,7 @@ def test_errors_detected_with_count(df_two_cat_cols):
                                       'col2': ['c', 'c', 'a']},
                                      index=[8, 9, 19]
                                      )
-    assert_frame_equal(detector.detected, expected_detected)
+    assert_frame_equal(detector.detected(), expected_detected)
 
 
 def test_from_existing(df_two_cat_cols):
diff --git a/pdcleaner/tests/test_bounded.py b/tests/pdcleaner/detection/test_bounded.py
similarity index 100%
rename from pdcleaner/tests/test_bounded.py
rename to tests/pdcleaner/detection/test_bounded.py
diff --git a/pdcleaner/tests/test_by_category.py b/tests/pdcleaner/detection/test_by_category.py
similarity index 86%
rename from pdcleaner/tests/test_by_category.py
rename to tests/pdcleaner/detection/test_by_category.py
index 3944c03..80f3598 100644
--- a/pdcleaner/tests/test_by_category.py
+++ b/tests/pdcleaner/detection/test_by_category.py
@@ -22,9 +22,9 @@ def test_get_method(df_num_cat):
 
 
 def test_get_kwargs(df_num_cat):
-    my_kwargs = {'threshold': 3}
-    detector = df_num_cat.cleaner.detect('iqr', **my_kwargs)
-    assert detector.method_kwargs == my_kwargs
+    kwargs = {'threshold': 3}
+    detector = df_num_cat.cleaner.detect('iqr', **kwargs)
+    assert detector.method_kwargs == kwargs
 
 
 def test_with_existing_detector(df_two_cat_cols):
diff --git a/pdcleaner/tests/test_castable.py b/tests/pdcleaner/detection/test_castable.py
similarity index 100%
rename from pdcleaner/tests/test_castable.py
rename to tests/pdcleaner/detection/test_castable.py
diff --git a/pdcleaner/tests/test_cat_web.py b/tests/pdcleaner/detection/test_cat_web.py
similarity index 100%
rename from pdcleaner/tests/test_cat_web.py
rename to tests/pdcleaner/detection/test_cat_web.py
diff --git a/pdcleaner/tests/test_custom.py b/tests/pdcleaner/detection/test_custom.py
similarity index 97%
rename from pdcleaner/tests/test_custom.py
rename to tests/pdcleaner/detection/test_custom.py
index 3d44f60..4e893e5 100644
--- a/pdcleaner/tests/test_custom.py
+++ b/tests/pdcleaner/detection/test_custom.py
@@ -1,7 +1,5 @@
 """Unit tests for custom detector"""
 
-from http.client import EXPECTATION_FAILED
-from unittest import expectedFailure
 import pytest
 import pandas as pd
 
diff --git a/pdcleaner/tests/test_date_range.py b/tests/pdcleaner/detection/test_date_range.py
similarity index 100%
rename from pdcleaner/tests/test_date_range.py
rename to tests/pdcleaner/detection/test_date_range.py
diff --git a/pdcleaner/tests/test_detect_api.py b/tests/pdcleaner/detection/test_detect_api.py
similarity index 100%
rename from pdcleaner/tests/test_detect_api.py
rename to tests/pdcleaner/detection/test_detect_api.py
diff --git a/pdcleaner/tests/test_detect_special_index_series.py b/tests/pdcleaner/detection/test_detect_special_index_series.py
similarity index 96%
rename from pdcleaner/tests/test_detect_special_index_series.py
rename to tests/pdcleaner/detection/test_detect_special_index_series.py
index 3377d7a..ed88f67 100644
--- a/pdcleaner/tests/test_detect_special_index_series.py
+++ b/tests/pdcleaner/detection/test_detect_special_index_series.py
@@ -25,7 +25,7 @@ def test_alphabetic_index_not_error(series_alpha_index):
 
 def test_alphabetic_index_detected(series_alpha_index):
     detector = series_alpha_index.cleaner.detect.bounded(lower=2, upper=4)
-    actual = detector.detected
+    actual = detector.detected()
     expected = pd.Series([1, 100], index=["a", "c"])
     assert_series_equal(actual, expected)
 
@@ -46,6 +46,6 @@ def test_unordered_numeric_index_not_error(series_unsorted_idx):
 
 def test_unordered_numeric_index_detected(series_unsorted_idx):
     detector = series_unsorted_idx.cleaner.detect.bounded(lower=2, upper=4)
-    actual = detector.detected
+    actual = detector.detected()
     expected = pd.Series([1, 100], index=[12, 5])
     assert_series_equal(actual, expected)
diff --git a/pdcleaner/tests/test_detect_with_outliers_obj.py b/tests/pdcleaner/detection/test_detect_with_outliers_obj.py
similarity index 100%
rename from pdcleaner/tests/test_detect_with_outliers_obj.py
rename to tests/pdcleaner/detection/test_detect_with_outliers_obj.py
diff --git a/pdcleaner/tests/test_detected_valid.py b/tests/pdcleaner/detection/test_detected_valid.py
similarity index 88%
rename from pdcleaner/tests/test_detected_valid.py
rename to tests/pdcleaner/detection/test_detected_valid.py
index 0cbbb77..90e2261 100644
--- a/pdcleaner/tests/test_detected_valid.py
+++ b/tests/pdcleaner/detection/test_detected_valid.py
@@ -9,7 +9,7 @@ def test_valid(series_with_outlier):
     detector = \
         series_with_outlier.cleaner.detect('bounded', lower=2, upper=4)
     expected = pd.Series([2, 4], index=[1, 3])
-    assert_series_equal(detector.valid, expected)
+    assert_series_equal(detector.valid(), expected)
 
 
 def test_detected_series(series_with_outlier):
@@ -18,7 +18,7 @@ def test_detected_series(series_with_outlier):
         series_with_outlier.cleaner.detect('bounded', lower=2, upper=4)
     # expected = pd.Series([True, False, True, False])
     detected  = series_with_outlier.cleaner.detected(detector)
-    assert_series_equal(detected, detector.detected)
+    assert_series_equal(detected, detector.detected())
 
 
 def test_valid_series(series_with_outlier):
@@ -27,7 +27,7 @@ def test_valid_series(series_with_outlier):
         series_with_outlier.cleaner.detect('bounded', lower=2, upper=4)
     # expected = pd.Series([True, False, True, False])
     valid  = series_with_outlier.cleaner.valid(detector)
-    assert_series_equal(valid, detector.valid)
+    assert_series_equal(valid, detector.valid())
 
 
 def test_detected_df(df_two_cat_cols):
@@ -38,4 +38,4 @@ def test_detected_df(df_two_cat_cols):
 
 def test_valid_df(df_two_cat_cols):
     detector = df_two_cat_cols.cleaner.detect.associations(freq=0.05)
-    assert_frame_equal(df_two_cat_cols.cleaner.valid(detector), detector.valid)
\ No newline at end of file
+    assert_frame_equal(df_two_cat_cols.cleaner.valid(detector), detector.valid())
diff --git a/pdcleaner/tests/test_duplicated.py b/tests/pdcleaner/detection/test_duplicated.py
similarity index 100%
rename from pdcleaner/tests/test_duplicated.py
rename to tests/pdcleaner/detection/test_duplicated.py
diff --git a/pdcleaner/tests/test_gauss_transform.py b/tests/pdcleaner/detection/test_gauss_transform.py
similarity index 98%
rename from pdcleaner/tests/test_gauss_transform.py
rename to tests/pdcleaner/detection/test_gauss_transform.py
index fe8f2e6..e5824c0 100644
--- a/pdcleaner/tests/test_gauss_transform.py
+++ b/tests/pdcleaner/detection/test_gauss_transform.py
@@ -96,7 +96,7 @@ def test_modzscore_negative_pvalue(series_with_outlier):
 
 
 def test_iqr_transform_params_from_existing(series_with_outlier, series_test_set):
-    """params from detector_obj"""
+    """params from detector"""
     detector = series_with_outlier.cleaner.detect.iqr(transform='boxcox',
                                                       normaltest='warn',
                                                       pvalue=1e-2)
@@ -106,7 +106,7 @@ def test_iqr_transform_params_from_existing(series_with_outlier, series_test_set
 
 
 def test_zscore_transform_params_from_existing(series_with_outlier, series_test_set):
-    """params from detector_obj"""
+    """params from detector"""
     detector = series_with_outlier.cleaner.detect.zscore(transform='boxcox',
                                                          normaltest='warn',
                                                          pvalue=1e-2)
@@ -116,7 +116,7 @@ def test_zscore_transform_params_from_existing(series_with_outlier, series_test_
 
 
 def test_modzscore_transform_params_from_existing(series_with_outlier, series_test_set):
-    """params from detector_obj"""
+    """params from detector"""
     detector = series_with_outlier.cleaner.detect.modzscore(transform='boxcox',
                                                             normaltest='warn',
                                                             pvalue=1e-2)
diff --git a/pdcleaner/tests/test_iqr.py b/tests/pdcleaner/detection/test_iqr.py
similarity index 100%
rename from pdcleaner/tests/test_iqr.py
rename to tests/pdcleaner/detection/test_iqr.py
diff --git a/pdcleaner/tests/test_length.py b/tests/pdcleaner/detection/test_length.py
similarity index 61%
rename from pdcleaner/tests/test_length.py
rename to tests/pdcleaner/detection/test_length.py
index 192dd8a..49ba6b8 100644
--- a/pdcleaner/tests/test_length.py
+++ b/tests/pdcleaner/detection/test_length.py
@@ -4,24 +4,25 @@
 
 import pandas as pd
 from pandas.testing import assert_series_equal
+import pdcleaner
 
 
 def test_detect_call_as_parameter(series_with_different_length):
     detect_results = \
-        series_with_different_length.cleaner.detect('length', mode='bound', lower=2, upper=5)
+        series_with_different_length.cleaner.detect('length', lower=2, upper=5)
     assert detect_results.lower == 2
     assert detect_results.upper == 5
 
 
 def test_detect_call_as_method(series_with_different_length):
     detect_results = \
-        series_with_different_length.cleaner.detect.length(mode='bound', lower=2, upper=5)
+        series_with_different_length.cleaner.detect.length(lower=2, upper=5)
     assert detect_results.lower == 2
     assert detect_results.upper == 5
 
 def test_length_from_existing_detector(series_with_different_length):
     detect_results = \
-        series_with_different_length.cleaner.detect.length(mode='bound', lower=2, upper=5)
+        series_with_different_length.cleaner.detect.length(lower=2, upper=5)
     series2 = pd.Series(['123'])
     detector2 = series2.cleaner.detect(detect_results)
     assert detector2.mode=='bound'
@@ -29,62 +30,58 @@ def test_length_from_existing_detector(series_with_different_length):
     assert detector2.upper == 5
 
 def test_detect_with_lower_and_upper(series_with_different_length):
-    detect_results = series_with_different_length.cleaner.detect('length', mode='bound',
+    detect_results = series_with_different_length.cleaner.detect('length',
                                                                  lower=2, upper=5)
     expected = pd.Series([False, True, False, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_detect_with_only_upper(series_with_different_length):
-    detect_results = series_with_different_length.cleaner.detect('length', mode='bound', upper=5)
+    detect_results = series_with_different_length.cleaner.detect('length', upper=5)
     expected = pd.Series([False, True, False, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_detect_with_only_lower(series_with_different_length):
-    detect_results = series_with_different_length.cleaner.detect('length', mode='bound',
-                                                                 lower=3)
+    detect_results = series_with_different_length.cleaner.detect('length', lower=3)
     expected = pd.Series([False, False, False, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_detect_with_fixed_value(series_with_different_length):
-    detect_results = series_with_different_length.cleaner.detect('length', mode='fixed_value',
-                                                                 fix_value=5)
+    detect_results = series_with_different_length.cleaner.detect('length', value=5)
     expected = pd.Series([False, True, False, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_detect_call_on_series_with_nan(cat_series_with_nan):
-    detect_results = cat_series_with_nan.cleaner.detect.length(mode='fixed_value', fix_value=3)
+    detect_results = cat_series_with_nan.cleaner.detect.length(value=3)
     expected = pd.Series([False, False, False, False, False, True])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_detect_on_series_with_integers(series_with_integers):
-    detect_results = series_with_integers.cleaner.detect.length(mode='bound', upper=6)
+    detect_results = series_with_integers.cleaner.detect.length(upper=6)
     expected = pd.Series([False, True, False, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_detect_on_series_with_floats(series_with_floats):
-    detect_results = series_with_floats.cleaner.detect.length(mode='bound', upper=6)
+    detect_results = series_with_floats.cleaner.detect.length(upper=6)
     expected = pd.Series([False, True, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_inclusive_arg_detect_on_series(series_with_different_length):
     # pd.Series(['75013', '952401', '93250', '94230'])
-    result = series_with_different_length.cleaner.detect.length(mode='bound',
-                                                                lower=2, upper=5).is_error()
+    result = series_with_different_length.cleaner.detect.length(lower=2, upper=5).is_error()
     expected = pd.Series([False, True, False, False])
     assert_series_equal(result, expected)
 
     result = (series_with_different_length
               .cleaner
               .detect
-              .length(mode='bound',
-                      lower=5,
+              .length(lower=5,
                       upper=6,
                       inclusive="right")
               .is_error())
@@ -95,8 +92,7 @@ def test_inclusive_arg_detect_on_series(series_with_different_length):
     result = (series_with_different_length
               .cleaner
               .detect
-              .length(mode='bound',
-                      lower=5,
+              .length(lower=5,
                       upper=6,
                       inclusive="left")
               .is_error())
@@ -107,8 +103,7 @@ def test_inclusive_arg_detect_on_series(series_with_different_length):
     result = (series_with_different_length
               .cleaner
               .detect
-              .length(mode='bound',
-                      lower=5,
+              .length(lower=5,
                       upper=6,
                       inclusive="neither")
               .is_error())
@@ -116,63 +111,67 @@ def test_inclusive_arg_detect_on_series(series_with_different_length):
     assert_series_equal(result, expected)
 
 
-def test_no_specified_bounded_warns(series_with_different_length):
-    msg = 'lower or upper must be specified in bound mode'
+def test_incompatible_args(series_with_different_length):
+    msg = "Incompatible arguments: value and upper or lower"
     with pytest.raises(ValueError, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='bound')
+        series_with_different_length.cleaner.detect.length(value=3, upper=5)
 
 
-def test_no_fixed_value(series_with_different_length):
-    msg = "fix_value must be specified in fixed_value mode"
+def test_incompatible_args_2(series_with_different_length):
+    msg = "Incompatible arguments: value and upper or lower"
     with pytest.raises(ValueError, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='fixed_value')
+        series_with_different_length.cleaner.detect.length(value=3, lower=1)
 
 
 def test_lower_gte_upper(series_with_different_length):
     msg = "Lower bound is >= upper bound"
     with pytest.raises(ValueError, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='bound', lower=2, upper=0)
+        series_with_different_length.cleaner.detect.length(lower=2, upper=0)
 
 
 def test_lower_eq_upper(series_with_different_length):
     msg = "Lower bound is >= upper bound"
     with pytest.raises(ValueError, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='bound', lower=2, upper=2)
+        series_with_different_length.cleaner.detect.length(lower=2, upper=2)
 
 
-def test_unused_upper_value_given(series_with_different_length):
-    msg = "Upper or Lower bound is not necessary in fixed_value mode"
-    with pytest.warns(UserWarning, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='fixed_value', fix_value=5, upper=5)
+# def test_unused_upper_value_given(series_with_different_length):
+#     msg = "Upper or Lower bound is not necessary in fixed_value mode"
+#     with pytest.warns(UserWarning, match=msg):
+#         series_with_different_length.cleaner.detect.length(mode='fixed_value', value=5, upper=5)
 
 
-def test_unused_lower_value_given(series_with_different_length):
-    msg = "Upper or Lower bound is not necessary in fixed_value mode"
-    with pytest.warns(UserWarning, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='fixed_value', fix_value=5, lower=1)
+# def test_unused_lower_value_given(series_with_different_length):
+#     msg = "Upper or Lower bound is not necessary in fixed_value mode"
+#     with pytest.warns(UserWarning, match=msg):
+#         series_with_different_length.cleaner.detect.length(mode='fixed_value', value=5, lower=1)
 
 
-def test_unused_fixed_value_given(series_with_different_length):
-    msg = "Fix_value is not necessary in bound mode"
-    with pytest.warns(UserWarning, match=msg):
-        series_with_different_length.cleaner.detect.length(mode='bound', fix_value=5, lower=1)
+# def test_unused_fixed_value_given(series_with_different_length):
+#     msg = "value is not necessary in bound mode"
+#     with pytest.warns(UserWarning, match=msg):
+#         series_with_different_length.cleaner.detect.length(mode='bound', value=5, lower=1)
 
 
 def test_invalid_lower_type_raise(series_with_outlier):
     msg = "Lower bound must be a number"
     with pytest.raises(TypeError, match=msg):
-        series_with_outlier.cleaner.detect.length(mode="bound", lower="str")
+        series_with_outlier.cleaner.detect.length(lower="str")
 
 
 def test_invalid_upper_type_raise(series_with_outlier):
     msg = "Upper bound must be a number"
     with pytest.raises(TypeError, match=msg):
-        series_with_outlier.cleaner.detect.length(mode="bound", upper="str")
+        series_with_outlier.cleaner.detect.length(upper="str")
 
 
-def test_invalid_fix_value_type_raise(series_with_outlier):
-    msg = "Fix value must be a number"
+def test_invalid_value_type_raise(series_with_outlier):
+    msg = "Argument value must be a number"
     with pytest.raises(TypeError, match=msg):
-        series_with_outlier.cleaner.detect.length(mode="fixed_value", fix_value="str")
+        series_with_outlier.cleaner.detect.length(value="str")
 
 
+def test_length_no_arg_raise(series_with_outlier):
+    msg="At least one argument must be provided"
+    with pytest.raises(ValueError, match=msg):
+        series_with_outlier.cleaner.detect.length()
diff --git a/pdcleaner/tests/test_missing.py b/tests/pdcleaner/detection/test_missing.py
similarity index 100%
rename from pdcleaner/tests/test_missing.py
rename to tests/pdcleaner/detection/test_missing.py
diff --git a/pdcleaner/tests/test_multivar_numerics.py b/tests/pdcleaner/detection/test_outliers.py
similarity index 79%
rename from pdcleaner/tests/test_multivar_numerics.py
rename to tests/pdcleaner/detection/test_outliers.py
index 7ce5213..1e79288 100644
--- a/pdcleaner/tests/test_multivar_numerics.py
+++ b/tests/pdcleaner/detection/test_outliers.py
@@ -17,24 +17,24 @@ def test_applied_to_series():
     series = pd.Series([1, np.nan, 'a'])
     match = "detector applies to DataFrames."
     with pytest.raises(TypeError, match=match):
-        series.cleaner.detect.ndoutliers()
+        series.cleaner.detect.outliers()
 
 
 def test_applied_to_unvalid_df(anscombe):
     match = "applies to DataFrames with numeric columns only"
     with pytest.raises(TypeError, match=match):
-        anscombe.cleaner.detect.ndoutliers()
+        anscombe.cleaner.detect.outliers()
 
 
 def test_parameters_default(anscombe):
     df = subset(anscombe, 'I')
-    detector = df.cleaner.detect.ndoutliers()
+    detector = df.cleaner.detect.outliers()
     assert detector.min_samples == 2
 
 
 def test_parameters_modify(anscombe):
     df = subset(anscombe, 'I')
-    detector = df.cleaner.detect.ndoutliers(eps=0.1, min_samples=3)
+    detector = df.cleaner.detect.outliers(eps=0.1, min_samples=3)
     assert detector.eps == 0.1
     assert detector.min_samples == 3
 
@@ -43,39 +43,39 @@ def test_type_error_parameter_eps(anscombe):
     df = subset(anscombe, 'I')
     match = 'eps must be a number'
     with pytest.raises(TypeError, match=match):
-        df.cleaner.detect.ndoutliers(eps='string')
+        df.cleaner.detect.outliers(eps='string')
 
 
 def test_type_error_parameter_min_samples(anscombe):
     df = subset(anscombe, 'I')
     match = 'min_samples must be an integer'
     with pytest.raises(TypeError, match=match):
-        df.cleaner.detect.ndoutliers(min_samples=2.5)
+        df.cleaner.detect.outliers(min_samples=2.5)
 
 
 def test_anscombe_i(anscombe):
     df = subset(anscombe, 'I')
-    detector = df.cleaner.detect.ndoutliers()
-    print(detector.detected)
+    detector = df.cleaner.detect.outliers()
+    print(detector.detected())
     assert detector.has_errors() is False
 
 
 def test_anscombe_ii(anscombe):
     df = subset(anscombe, 'II')
-    detector = df.cleaner.detect.ndoutliers()
+    detector = df.cleaner.detect.outliers()
     assert detector.has_errors() is False
 
 
 def test_anscombe_iii(anscombe):
     df = subset(anscombe, 'III')
-    detector = df.cleaner.detect.ndoutliers()
+    detector = df.cleaner.detect.outliers()
     expected = pd.Series([False] * 2 + [True] + [False] * 8)
     assert_series_equal(detector.is_error(), expected)
 
 
 def test_anscombe_iv(anscombe):
     df = subset(anscombe, 'IV')
-    detector = df.cleaner.detect.ndoutliers()
+    detector = df.cleaner.detect.outliers()
     expected = pd.Series([False] * 7 + [True] + [False] * 3)
     assert_series_equal(detector.is_error(), expected)
 
@@ -83,7 +83,7 @@ def test_anscombe_iv(anscombe):
 def test_from_existing_detector(anscombe):
     df = subset(anscombe, 'II')
     df_test = pd.DataFrame({'x': [12], 'y': [4]})
-    detector = df.cleaner.detect('ndoutliers')
+    detector = df.cleaner.detect('outliers')
     match = "This detection method can not be used"\
             " with an existing detector as an input."
     with pytest.raises(ValueError, match=match):
@@ -93,7 +93,7 @@ def test_from_existing_detector(anscombe):
 def test_with_nan(anscombe):
     df = subset(anscombe, 'I')
     df.loc[df.x == 10, 'y'] = np.nan
-    detector = df.cleaner.detect.ndoutliers()
+    detector = df.cleaner.detect.outliers()
     assert detector.has_errors() is False
 
 
@@ -101,7 +101,7 @@ def test_simple_3dset():
     df = pd.DataFrame({'x': [1, 1.1, 4],
                        'y': [1.1, 1, 4],
                        'z': [1, 1.1, 4]})
-    detector = df.cleaner.detect.ndoutliers()
+    detector = df.cleaner.detect.outliers()
     expected = pd.Series([False, False, True])
     assert_series_equal(detector.is_error(), expected)
 
@@ -110,4 +110,4 @@ def test_dbscan_error():
     dataframe = pd.DataFrame({'x': [1], 'y': [2]})
     match = 'DBScan error: see sklearn documentation for help'
     with pytest.raises(ValueError, match=match):
-        dataframe.cleaner.detect('ndoutliers').index
+        dataframe.cleaner.detect('outliers').index
diff --git a/pdcleaner/tests/test_pattern.py b/tests/pdcleaner/detection/test_pattern.py
similarity index 100%
rename from pdcleaner/tests/test_pattern.py
rename to tests/pdcleaner/detection/test_pattern.py
diff --git a/pdcleaner/tests/test_quantile_detector.py b/tests/pdcleaner/detection/test_quantiles.py
similarity index 97%
rename from pdcleaner/tests/test_quantile_detector.py
rename to tests/pdcleaner/detection/test_quantiles.py
index 0175347..e7fdffa 100644
--- a/pdcleaner/tests/test_quantile_detector.py
+++ b/tests/pdcleaner/detection/test_quantiles.py
@@ -1,4 +1,4 @@
-"""UnitTests for :py:class:pdcleaner.detection.gaussian.QuantilesSeriesDetector"""
+"""UnitTests for :py:class:pdcleaner.detection.gaussian.quantiles"""
 
 import pandas as pd
 import pytest
diff --git a/pdcleaner/tests/test_report.py b/tests/pdcleaner/detection/test_report.py
similarity index 97%
rename from pdcleaner/tests/test_report.py
rename to tests/pdcleaner/detection/test_report.py
index 016a14c..38c2a70 100644
--- a/pdcleaner/tests/test_report.py
+++ b/tests/pdcleaner/detection/test_report.py
@@ -196,17 +196,17 @@ def test_report_web_url_nocheck(capsys, series_with_urls):
 
 def test_report_fingerprint(capsys, cat_series):
     """key collision"""
-    detector = cat_series.cleaner.detect('keycollision')
+    detector = cat_series.cleaner.detect('alternatives')
     detector.report()
     captured = capsys.readouterr()
     assert 'keys                     fingerprint' in captured.out
 
 
-def test_report_ndoutliers(capsys, anscombe):
+def test_report_outliers(capsys, anscombe):
     """multivariate outliers"""
     df = anscombe
     df = df[df.dataset == 'I'].reset_index()[['x', 'y']]
-    detector = df.cleaner.detect("ndoutliers")
+    detector = df.cleaner.detect("outliers")
     detector.report()
     captured = capsys.readouterr()
     assert 'min_samples                        2' in captured.out
@@ -230,7 +230,7 @@ def test_report_missing(capsys, dataframe_with_nan):
 
 def test_report_length(capsys, series_with_different_length):
     """length"""
-    detector = series_with_different_length.cleaner.detect('length', mode='bound', lower=3)
+    detector = series_with_different_length.cleaner.detect('length', lower=3)
     detector.report()
     captured = capsys.readouterr()
     assert 'lower                              3' in captured.out
diff --git a/pdcleaner/tests/test_series_type.py b/tests/pdcleaner/detection/test_series_type.py
similarity index 100%
rename from pdcleaner/tests/test_series_type.py
rename to tests/pdcleaner/detection/test_series_type.py
diff --git a/pdcleaner/tests/test_spaces.py b/tests/pdcleaner/detection/test_spaces.py
similarity index 82%
rename from pdcleaner/tests/test_spaces.py
rename to tests/pdcleaner/detection/test_spaces.py
index 9b14c59..e676445 100644
--- a/pdcleaner/tests/test_spaces.py
+++ b/tests/pdcleaner/detection/test_spaces.py
@@ -12,8 +12,8 @@ def test_detect_call_as_parameter(series_with_extra_spaces):
 
 
 def test_detect_call_as_method(series_with_extra_spaces):
-    detect_results = series_with_extra_spaces.cleaner.detect.spaces(side='left')
-    assert detect_results.side == 'left'
+    detect_results = series_with_extra_spaces.cleaner.detect.spaces(side='leading')
+    assert detect_results.side == 'leading'
 
 
 def test_detect_with_both_parameter(series_with_extra_spaces):
@@ -22,26 +22,26 @@ def test_detect_with_both_parameter(series_with_extra_spaces):
     assert_series_equal(detect_results.is_error(), expected)
 
 
-def test_detect_with_left_parameter(series_with_extra_spaces):
-    detect_results = series_with_extra_spaces.cleaner.detect.spaces(side='left')
+def test_detect_with_leading_parameter(series_with_extra_spaces):
+    detect_results = series_with_extra_spaces.cleaner.detect.spaces(side='leading')
     expected = pd.Series([False, False, True, True, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
-def test_detect_with_right_parameter(series_with_extra_spaces):
-    detect_results = series_with_extra_spaces.cleaner.detect.spaces(side='right')
+def test_detect_with_trailing_parameter(series_with_extra_spaces):
+    detect_results = series_with_extra_spaces.cleaner.detect.spaces(side='trailing')
     expected = pd.Series([False, True, False, True, False])
     assert_series_equal(detect_results.is_error(), expected)
 
 
 def test_with_unknown_parameter(series_with_extra_spaces):
-    msg = "Parameter side must be left or right or both"
+    msg = "Parameter side must be leading or trailing or both"
     with pytest.raises(ValueError, match=msg):
         series_with_extra_spaces.cleaner.detect.spaces(side='east')
 
 
 def test_side_from_existing_detector(series_with_extra_spaces):
-    detector = series_with_extra_spaces.cleaner.detect.spaces(side='right')
+    detector = series_with_extra_spaces.cleaner.detect.spaces(side='trailing')
     series = pd.Series([' Paris'])
     detector2 = series.cleaner.detect(detector)
     assert detector2.side == detector.side
diff --git a/pdcleaner/tests/test_values.py b/tests/pdcleaner/detection/test_values.py
similarity index 100%
rename from pdcleaner/tests/test_values.py
rename to tests/pdcleaner/detection/test_values.py
diff --git a/pdcleaner/tests/test_zscore.py b/tests/pdcleaner/detection/test_zscore_modzscore.py
similarity index 100%
rename from pdcleaner/tests/test_zscore.py
rename to tests/pdcleaner/detection/test_zscore_modzscore.py
diff --git a/pdcleaner/tests/test_plot_keycollision.py b/tests/pdcleaner/plots/test_plot_alternatives.py
similarity index 69%
rename from pdcleaner/tests/test_plot_keycollision.py
rename to tests/pdcleaner/plots/test_plot_alternatives.py
index 87b1855..b794a11 100644
--- a/pdcleaner/tests/test_plot_keycollision.py
+++ b/tests/pdcleaner/plots/test_plot_alternatives.py
@@ -5,30 +5,30 @@
 import matplotlib.pyplot as plt
 
 
-def test_nfirst_not_int(keycol_plot_series):
+def test_nfirst_not_int(altern_plot_series):
     match = "should be an integer"
-    detector = keycol_plot_series.cleaner.detect.keycollision()
+    detector = altern_plot_series.cleaner.detect.alternatives()
     with pytest.raises(TypeError, match=match):
         detector.plot(nfirst='one')
 
 
-def test_nlast_not_int(keycol_plot_series):
+def test_nlast_not_int(altern_plot_series):
     match = "should be an integer"
-    detector = keycol_plot_series.cleaner.detect.keycollision()
+    detector = altern_plot_series.cleaner.detect.alternatives()
     with pytest.raises(TypeError, match=match):
         detector.plot(nlast='one')
 
 
-def test_nfirst_negative(keycol_plot_series):
+def test_nfirst_negative(altern_plot_series):
     match = "should be >=0"
-    detector = keycol_plot_series.cleaner.detect.keycollision()
+    detector = altern_plot_series.cleaner.detect.alternatives()
     with pytest.raises(ValueError, match=match):
         detector.plot(nfirst=-1)
 
 
-def test_nlast_negative(keycol_plot_series):
+def test_nlast_negative(altern_plot_series):
     match = "should be >=0"
-    detector = keycol_plot_series.cleaner.detect.keycollision()
+    detector = altern_plot_series.cleaner.detect.alternatives()
     with pytest.raises(ValueError, match=match):
         detector.plot(nlast=-3)
 
@@ -41,9 +41,9 @@ def assert_ytickslabels_and_text(ax, expected_ytickslabels, expected_text):
         assert text_properties.get_text() == expected_text[cnt]
 
 
-def test_no_arg(keycol_plot_series):
+def test_no_arg(altern_plot_series):
     detector = \
-        keycol_plot_series.cleaner.detect('keycollision', keys='fingerprint')
+        altern_plot_series.cleaner.detect('alternatives', keys='fingerprint')
     ax = detector.plot()
     expected_ytickslabels = ["Steve Jobs", "Bill Gates", "Linus Torvalds"]
     expected_text = []
@@ -51,9 +51,9 @@ def test_no_arg(keycol_plot_series):
     plt.close()
 
 
-def test_nfirst_and_nlast_zeros(keycol_plot_series):
+def test_nfirst_and_nlast_zeros(altern_plot_series):
     detector = \
-        keycol_plot_series.cleaner.detect('keycollision', keys='fingerprint')
+        altern_plot_series.cleaner.detect('alternatives', keys='fingerprint')
     ax = detector.plot(nfirst=0, nlast=0)
     expected_ytickslabels = ["Steve Jobs", "Bill Gates", "Linus Torvalds"]
     expected_text = []
@@ -61,9 +61,9 @@ def test_nfirst_and_nlast_zeros(keycol_plot_series):
     plt.close()
 
 
-def test_nfirst_only(keycol_plot_series):
+def test_nfirst_only(altern_plot_series):
     detector = \
-        keycol_plot_series.cleaner.detect('keycollision', keys='fingerprint')
+        altern_plot_series.cleaner.detect('alternatives', keys='fingerprint')
     ax = detector.plot(nfirst=2)
     expected_ytickslabels = ["1", "Bill Gates", "Linus Torvalds"]
     expected_text = ["    +1    "]
@@ -71,9 +71,9 @@ def test_nfirst_only(keycol_plot_series):
     plt.close()
 
 
-def test_nlast_only(keycol_plot_series):
+def test_nlast_only(altern_plot_series):
     detector = \
-        keycol_plot_series.cleaner.detect('keycollision', keys='fingerprint')
+        altern_plot_series.cleaner.detect('alternatives', keys='fingerprint')
     ax = detector.plot(nlast=2)
     expected_ytickslabels = ["Steve Jobs", "Bill Gates", "1"]
     expected_text = ["    +1    "]
@@ -81,9 +81,9 @@ def test_nlast_only(keycol_plot_series):
     plt.close()
 
 
-def test_nfirst_and_nlast(keycol_plot_series):
+def test_nfirst_and_nlast(altern_plot_series):
     detector = \
-        keycol_plot_series.cleaner.detect('keycollision', keys='fingerprint')
+        altern_plot_series.cleaner.detect('alternatives', keys='fingerprint')
     ax = detector.plot(nfirst=1, nlast=1)
     expected_ytickslabels = ["Steve Jobs", "1", "Linus Torvalds"]
     expected_text = ["    +1    "]
@@ -91,9 +91,9 @@ def test_nfirst_and_nlast(keycol_plot_series):
     plt.close()
 
 
-def test_nfirst_and_nlast_sup_len_df(keycol_plot_series):
+def test_nfirst_and_nlast_sup_len_df(altern_plot_series):
     detector = \
-        keycol_plot_series.cleaner.detect('keycollision', keys='fingerprint')
+        altern_plot_series.cleaner.detect('alternatives', keys='fingerprint')
     ax = detector.plot(nfirst=3, nlast=2)
     expected_ytickslabels = ["Steve Jobs", "Bill Gates", "Linus Torvalds"]
     expected_text = []
diff --git a/pdcleaner/tests/test_plot_counts.py b/tests/pdcleaner/plots/test_plot_counts.py
similarity index 100%
rename from pdcleaner/tests/test_plot_counts.py
rename to tests/pdcleaner/plots/test_plot_counts.py
diff --git a/pdcleaner/tests/test_plot_freq.py b/tests/pdcleaner/plots/test_plot_freq.py
similarity index 100%
rename from pdcleaner/tests/test_plot_freq.py
rename to tests/pdcleaner/plots/test_plot_freq.py
diff --git a/pdcleaner/tests/test_plot_multicategories_associations.py b/tests/pdcleaner/plots/test_plot_multicategories.py
similarity index 100%
rename from pdcleaner/tests/test_plot_multicategories_associations.py
rename to tests/pdcleaner/plots/test_plot_multicategories.py
diff --git a/pdcleaner/tests/test_plot.py b/tests/pdcleaner/plots/test_plot_numseries.py
similarity index 97%
rename from pdcleaner/tests/test_plot.py
rename to tests/pdcleaner/plots/test_plot_numseries.py
index 3ea78ff..c4b5399 100644
--- a/pdcleaner/tests/test_plot.py
+++ b/tests/pdcleaner/plots/test_plot_numseries.py
@@ -13,11 +13,11 @@
 from matplotlib import colors
 import matplotlib.pyplot as plt
 
-from pdcleaner.tests.utils.utils import plt_collection_to_series
-from pdcleaner.tests.utils.utils import assert_listoflist_near
+from tests.tests_utils.utils import plt_collection_to_series
+from tests.tests_utils.utils import assert_listoflist_near
 
 # Test numeric plots
-
+import matplotlib; matplotlib.use('agg')
 
 def test_with_bounded(series_test_set):
     axs = series_test_set.cleaner.detect.bounded(lower=0, upper=10).plot()
@@ -36,7 +36,7 @@ def test_with_iqr(series_test_set):
 
 
 def test_with_values(cat_series):
-    match = "'EnumSeriesDetector' object has no attribute 'plot'"
+    match = "'enum' object has no attribute 'plot'"
     vals = ["cat", "dog"]
     with pytest.raises(AttributeError, match=match):
         cat_series.cleaner.detect.enum(values=vals).plot()
diff --git a/pdcleaner/tests/test_df_utils.py b/tests/pdcleaner/utils/test_df_utils.py
similarity index 100%
rename from pdcleaner/tests/test_df_utils.py
rename to tests/pdcleaner/utils/test_df_utils.py
diff --git a/pdcleaner/tests/test_utils_valid_dtype.py b/tests/pdcleaner/utils/test_utils_valid_dtype.py
similarity index 100%
rename from pdcleaner/tests/test_utils_valid_dtype.py
rename to tests/pdcleaner/utils/test_utils_valid_dtype.py
diff --git a/pdcleaner/tests/test_utils.py b/tests/tests_utils/test_utils.py
similarity index 100%
rename from pdcleaner/tests/test_utils.py
rename to tests/tests_utils/test_utils.py
diff --git a/pdcleaner/tests/utils/utils.py b/tests/tests_utils/utils.py
similarity index 100%
rename from pdcleaner/tests/utils/utils.py
rename to tests/tests_utils/utils.py