[
  {
    "path": ".coveragerc",
    "content": "[run]\nbranch = True\nsource = beautifultable\n\n[report]\nexclude_lines =\n    if self.debug:\n    pragma: no cover\n    raise NotImplementedError\n    if __name__ == .__main__.:\n    pass\nignore_errors = True\nomit =\n    test.py\n"
  },
  {
    "path": ".github/workflows/build.yml",
    "content": "# This workflow will install Python dependencies, run tests and lint with a variety of Python versions\n# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions\n\nname: Build\n\non:\n  push:\n    branches: [ master ]\n  pull_request:\n    branches: [ master ]\n  workflow_dispatch:\n\njobs:\n\n  black:\n    name: Check formatting\n    runs-on: 'ubuntu-latest'\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-python@v2\n      - uses: psf/black@stable\n  \n  coverage:\n    name: Check code coverage\n    runs-on: 'ubuntu-latest'\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python\n        uses: actions/setup-python@v2\n        with:\n          python-version: '3.x'\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          python -m pip install coverage\n          if [ -f requirements.txt ]; then pip install -r requirements.txt; fi\n      - name: Generate coverage report\n        run: |\n          coverage run test.py\n          coverage xml\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v2\n\n\n  build:\n    runs-on: ${{ matrix.os }}\n    needs: black\n    strategy:\n      fail-fast: false\n      matrix:\n        os:\n          - 'ubuntu-latest'\n          - 'macos-latest'\n          - 'windows-latest'\n        python-version:\n          - '3.7'\n          - '3.8'\n          - '3.9'\n          - '3.10'\n          - 'pypy-3.9'\n    steps:\n      - uses: actions/checkout@v2\n      - name: Set up Python ${{ matrix.python-version }}\n        uses: actions/setup-python@v2\n        with:\n          python-version: ${{ matrix.python-version }}\n      - name: Install dependencies\n        run: |\n          python -m pip install --upgrade pip\n          python -m pip install flake8\n          python -m pip install -r requirements.txt\n      - name: Lint with flake8\n        run: |\n          # stop the build if there are Python syntax errors or undefined names\n          flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics\n          # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide\n          flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics\n      - name: Run Test\n        run: |\n          python test.py\n"
  },
  {
    "path": ".github/workflows/publish-test.yml",
    "content": "# This workflow will upload a Python Package using Twine when a release is created\n# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries\n\n# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n# separate terms of service, privacy policy, and support\n# documentation.\n\nname: Test Publish\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\njobs:\n  deploy:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python\n      uses: actions/setup-python@v2\n      with:\n        python-version: '3.x'\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install build\n    - name: Build package\n      run: python -m build\n    - name: Publish package to TestPyPi\n      uses: pypa/gh-action-pypi-publish@master\n      with:\n        user: __token__\n        password: ${{ secrets.TEST_PYPI_API_TOKEN }}\n        repository_url: https://test.pypi.org/legacy/\n"
  },
  {
    "path": ".github/workflows/publish.yml",
    "content": "# This workflow will upload a Python Package using Twine when a release is created\n# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries\n\n# This workflow uses actions that are not certified by GitHub.\n# They are provided by a third-party and are governed by\n# separate terms of service, privacy policy, and support\n# documentation.\n\nname: Publish\n\non:\n  release:\n    types: [published]\n  workflow_dispatch:\n\njobs:\n  deploy:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v2\n    - name: Set up Python\n      uses: actions/setup-python@v2\n      with:\n        python-version: '3.x'\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install build\n    - name: Build package\n      run: python -m build\n    - name: Publish package to PyPi\n      uses: pypa/gh-action-pypi-publish@master\n      with:\n        user: __token__\n        password: ${{ secrets.PYPI_API_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": "__pycache__/\n*egg-info/\ndocs/_build/\ndist/\nbuild/\n.tox/\n*.pyc\n.coverage\n.vscode/\n.venv\n.idea\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "MIT License\n\nCopyright (c) 2022 Priyam Singh\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "MANIFEST.in",
    "content": "include LICENSE.txt\ninclude README.rst\ninclude docs/*.rst\ninclude test.py\n"
  },
  {
    "path": "README.rst",
    "content": "##########################################################################\nbeautifultable\n##########################################################################\n\n.. inclusion-marker-badges-start\n\n.. image:: https://badge.fury.io/py/beautifultable.svg\n    :target: https://badge.fury.io/py/beautifultable\n\n.. image:: https://img.shields.io/pypi/pyversions/beautifultable.svg\n    :target: https://pypi.python.org/pypi/beautifultable/\n\n.. image:: https://codecov.io/gh/pri22296/beautifultable/branch/master/graphs/badge.svg\n    :target: https://codecov.io/gh/pri22296/beautifultable/branch/master/\n\n.. image:: https://api.codacy.com/project/badge/Grade/7a76eb35ad4e450eaf00339e98381511\n    :target: https://www.codacy.com/app/pri22296/beautifultable?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=pri22296/beautifultable&amp;utm_campaign=Badge_Grade\n\n.. image:: https://github.com/pri22296/beautifultable/actions/workflows/build.yml/badge.svg?branch=master\n    :target: https://github.com/pri22296/beautifultable/actions/workflows/build.yml\n\n.. image:: https://readthedocs.org/projects/beautifultable/badge/?version=latest\n    :alt: Documentation Status\n    :target: http://beautifultable.readthedocs.io/en/latest/?badge=latest\n\n.. image:: https://img.shields.io/badge/Donate-PayPal-yellow.svg\n    :target: https://paypal.me/beautifultable\n\n.. inclusion-marker-badges-end\n\n\n.. inclusion-marker-introduction-start\n\n**************************************************************************\nIntroduction\n**************************************************************************\n\nThis Package provides BeautifulTable class for easily printing\ntabular data in a visually appealing format to a terminal. \n\nFeatures included but not limited to:\n\n* Full customization of the look and feel of the table\n* Build the Table as you wish, By adding rows, or by columns or even\n  mixing both these approaches.\n* Full support for *colors* using ANSI sequences or any library of your\n  choice. It just works.\n* Plenty of predefined *styles* for multiple use cases and option to\n  create custom ones.\n* Support for *Unicode* characters.\n* Supports streaming table when data is slow to retrieve.\n  \n.. inclusion-marker-introduction-end\n\n\n \n.. inclusion-marker-links-start\n\n**************************************************************************\nLinks\n**************************************************************************\n\n* `Documentation <http://beautifultable.readthedocs.io/en/latest/>`_\n\n* `Source <https://github.com/pri22296/beautifultable>`_\n\n* `API Reference <http://beautifultable.readthedocs.io/en/latest/source/beautifultable.html#module-beautifultable>`_\n\n\n.. inclusion-marker-links-end\n\n\n\n.. inclusion-marker-usage-start\n\n**************************************************************************\nUsage\n**************************************************************************\n\nHere is an example of how you can use beautifultable::\n\n    >>> from beautifultable import BeautifulTable\n    >>> table = BeautifulTable()\n    >>> table.rows.append([\"Jacob\", 1, \"boy\"])\n    >>> table.rows.append([\"Isabella\", 1, \"girl\"])\n    >>> table.rows.append([\"Ethan\", 2, \"boy\"])\n    >>> table.rows.append([\"Sophia\", 2, \"girl\"])\n    >>> table.rows.append([\"Michael\", 3, \"boy\"])\n    >>> table.rows.header = [\"S1\", \"S2\", \"S3\", \"S4\", \"S5\"]\n    >>> table.columns.header = [\"name\", \"rank\", \"gender\"]\n    >>> print(table)\n    +----+----------+------+--------+\n    |    |   name   | rank | gender |\n    +----+----------+------+--------+\n    | S1 |  Jacob   |  1   |  boy   |\n    +----+----------+------+--------+\n    | S2 | Isabella |  1   |  girl  |\n    +----+----------+------+--------+\n    | S3 |  Ethan   |  2   |  boy   |\n    +----+----------+------+--------+\n    | S4 |  Sophia  |  2   |  girl  |\n    +----+----------+------+--------+\n    | S5 | Michael  |  3   |  boy   |\n    +----+----------+------+--------+\n\n\nYou can learn more about beautifultable at this `Tutorial <http://beautifultable.readthedocs.io/en/latest/quickstart.html>`_\n\n.. inclusion-marker-usage-end\n\n\n\n.. inclusion-marker-install-start\n\n**************************************************************************\nInstallation\n**************************************************************************\n\n::\n\n    python3 -m pip install beautifultable\n\n.. inclusion-marker-install-end\n\n\n\n.. inclusion-marker-changelog-start\n\n**************************************************************************\nChangelog\n**************************************************************************\n\n===========\nDevelopment\n===========\n\n\n==========\nv1.1.0\n==========\n\n* Drop support for Python 3.4, 3.5 and 3.6\n* Add official support for python 3.9 and 3.10\n* Added `asdict` and `aslist` method on the row object. (Thanks to `@Agent-Hellboy <https://github.com/Agent-Hellboy>`_)\n* Added `from_csv` and `to_csv` methods to export/import a csv file. (Thanks to `@Agent-Hellboy <https://github.com/Agent-Hellboy>`_)\n* Added `from_df` and `to_df` methods to export/import a dataframe. (Thanks to `@Agent-Hellboy <https://github.com/Agent-Hellboy>`_)\n\n==========\nv1.0.1\n==========\n\n* Fixed an issue where appending a column with a header to an empty table left the table instance in\n  an inconsistent state.\n\n==========\nv1.0.0\n==========\n\n* Added two new views ``rows`` and ``columns`` to the ``BeautifulTable`` class. Most of the existing\n  methods have been deprecated. Methods of the form ``{}_row`` and ``{}_column`` have been moved to\n  views ``rows.{}`` and ``columns.{}``(ex. ``append_row`` is now ``rows.append``). Calling older\n  deprecated methods will now raise a ``FutureWarning``. Special methods such as ``__len__``, ``__iter__``,\n  etc. have also been moved to the respective views. For details, refer the\n  API documentation and the Updated Tutorial\n* The existing styling attributes have also been deprecated. A new ``border`` property can be accessed\n  to control all styling attributes affecting the border. Rest of the attributes can be accessed from\n  it's respective view.\n* Added support for row headers. As a result rows can now be accessed by their keys similar\n  to columns\n* Added two new methods ``to_csv`` and ``from_csv`` to directly export/import to a\n  csv file. (Thanks to `@dinko-pehar <https://github.com/dinko-pehar>`_)\n* Added ``BeautifulTable.rows.filter`` method to generate a new table with only certain rows\n* Added a new ``shape`` attribute to the ``BeautifulTable`` class which returns a tuple of form (nrow, ncol)\n* Added new attribute ``BeautifulTable.columns.header.alignment`` which can be used to have\n  a seperate header alignment. The default behaviour is to inherit ``BeautifulTable.columns.alignment``\n* Updated ``BeautifulTable.rows.sort`` (earlier ``BeautifulTable.sort``) method to now\n  also accept any callables as a key.\n* Updated behaviour of ``BeautifulTable.columns.width`` (earlier ``BeautifulTable.column_widths``).\n  It no longer overrides user specified widths by default. You can reset it to default\n  by setting it to **\"auto\"**\n* Deprecated attribute ``serialno`` and ``serialno_header``. User can now easily implement\n  this functionality by using row headers if required\n* Deprecated methods ``get_table_width()``, ``copy()`` and ``get_string()``.\n* Deprecated constructor arguments and class attributes named ``sign_mode``, ``numeric_precision``,\n  ``max_width`` and renamed to ``sign``, ``precision`` and ``maxwidth`` respectively\n* Fixed an issue where table was malformed if ``blessings`` module was used to generate colored strings.\n* Fixed issues with the existing implementation of ``__iter__``, ``__copy__`` and ``__deepcopy__`` which\n  should now work more reliably.\n* Fixed an issue where default padding could not be set to 0. (Thanks to `@furlongm <https://github.com/furlongm>`_)\n* Fixed several memory leak issues by ensuring that all internal objects hold only a weak reference\n  to the table instance.\n* Dropped support for Python 2\n\n==========\nv0.8.0\n==========\n\n* Dropped support for Python 3.3\n* Added support for streaming tables using a generator for cases  where data retrieval is slow\n* Alignment, padding, width can now be set for all columns using a simplified syntax like\n  ``table.column_alignments = beautifultable.ALIGN_LEFT``\n\n==========\nv0.7.0\n==========\n\n* Added 4 new styles, **STYLE_BOX**, **STYLE_BOX_DOUBLED**, **STYLE_BOX_ROUNDED**,\n  **STYLE_GRID**.\n* Renamed **STYLE_RESTRUCTURED_TEXT** to **STYLE_RST**\n* **wcwidth** is now an optional dependency\n* Updated the algorithm for calculating width of columns(better division of space among columns)\n* Added support for Paragraphs(using ``\\n`` character)\n* Added finer control for intersection characters using 12 new\n  attributes ``intersect_{top|header|row|bottom}_{left|mid|right}``\n* Added the ability to also accept bytestrings instead of unicode\n* Deprecated attribute ``intersection_char``\n* Deprecated methods ``get_top_border()``, ``get_bottom_border()``, ``get_header_separator()``,\n  ``get_row_separator()``, ``auto_calculate_width()``\n* Fixed an issue with **WEP_ELLIPSIS** and **WEP_STRIP** when using multibyte characters\n* Fixed an issue where table would not be in proper form if ``column_width`` is too low\n\n==========\nv0.6.0\n==========\n\n* Added support for handling Multi byte strings\n* Added support for colored strings using ANSI escape sequences\n* Added constraint where all strings must be unicode\n* Fixed an issue where sometimes width was calculated as higher than intended\n\n==========\nv0.5.3\n==========\n\n* Added support for handing color codes using ANSI escape sequences(experimental)\n* Fixed collections ABCs deprecation warning\n\n==========\nv0.5.2\n==========\n\n* Added new style **STYLE_NONE**\n* Fixed issue regarding improper conversion of non-string floats\n\n==========\nv0.5.1\n==========\n\n* Added ``detect_numerics`` boolean for toggling automatic numeric conversion\n\n==========\nv0.5.0\n==========\n\n* Added new property ``serialno_header``\n* Deprecated methods with misspelled *\"seperator\"* in their name.\n* Fixed an issue where table was corrupted when ``column_count`` was too high\n\n\n==========\nv0.4.0\n==========\n\n* Added predefined styles for easier customization\n* Added *reverse* argument to ``sort()`` method\n* Fixed *enum34* dependency for python versions prior to 3.4\n\n==========\nv0.3.0\n==========\n\n* Added property ``serialno`` for auto printing serial number\n* Fixed an issue with ``sign_mode`` related to str conversion\n* Fixed bugs related to python version prior to 3.3\n* Fixed exception on **WEP_ELLIPSIS** and token length less than 3\n* Fixed printing issues with empty table\n\n==========\nv0.2.0\n==========\n\n* Added python 2 support\n\n==========\nv0.1.3\n==========\n\n* Fixed minor issues\n\n==========\nv0.1.2\n==========\n\n* Added new property ``default_padding``\n* Added new method ``update_row``\n* Fixed an issue in ``auto_calculate_width()``\n\n==========\nv0.1.1\n==========\n\n* Initial release on PyPI\n\n\n.. inclusion-marker-changelog-end\n\n\n.. inclusion-marker-contribution-start\n\n**************************************************************************\nContribute\n**************************************************************************\n\nIf you have any suggestions or bug reports, Please create a Issue. Pull\nRequests are always welcome.\n\n.. inclusion-marker-contribution-end\n\n\n\n.. inclusion-marker-license-start\n\n**************************************************************************\nLicense\n**************************************************************************\n\nThis project is licensed under the MIT License - see the `LICENSE.txt <https://github.com/pri22296/beautifultable/blob/master/LICENSE.txt>`_ file for details.\n\n\n.. inclusion-marker-license-end\n\n\n\n.. inclusion-marker-donation-start\n\n**************************************************************************\nDonation\n**************************************************************************\n\nLove *beautifultable*? Consider supporting the development :)\n\n.. image:: https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif\n    :target: https://paypal.me/beautifultable\n\n\n.. inclusion-marker-donation-end\n"
  },
  {
    "path": "beautifultable/__init__.py",
    "content": "from .__version__ import __title__, __description__, __url__, __version__\nfrom .__version__ import __copyright__, __author__, __author_email__\nfrom .__version__ import __license__\n\nfrom .beautifultable import (  # noqa F401\n    BeautifulTable,\n    BTRowCollection,\n    BTColumnCollection,\n    BTRowHeader,\n    BTColumnHeader,\n    BTBorder,\n    __all__,\n)\nfrom . import enums\nfrom .enums import *  # noqa\n\n\n__all__ = __all__ + [\n    \"__title__\",\n    \"__description__\",\n    \"__url__\",\n    \"__version__\",\n    \"__copyright__\",\n    \"__author__\",\n    \"__author_email__\",\n    \"__license__\",\n]\n\n\n# To avoid duplicating enums name, dynamically add them to BeautifulTable\n# class and __all__\nfor token in dir(enums):\n    if (\n        token.startswith(\"WEP_\")\n        or token.startswith(\"ALIGN_\")\n        or token.startswith(\"SM_\")\n        or token.startswith(\"STYLE_\")\n    ):\n        setattr(BeautifulTable, token, getattr(enums, token))\n        __all__.append(token)\n"
  },
  {
    "path": "beautifultable/__version__.py",
    "content": "__title__ = \"beautifultable\"\n__description__ = \"Print text tables for terminals\"\n__url__ = \"https://github.com/pri22296/beautifultable\"\n__version__ = \"1.1.0\"\n__author__ = \"Priyam Singh\"\n__author_email__ = \"priyamsingh.22296@gmail.com\"\n__license__ = \"MIT\"\n__copyright__ = \"Copyright (c) 2022 Priyam Singh\"\n"
  },
  {
    "path": "beautifultable/ansi.py",
    "content": "\"\"\"Module Containing class required for handling ANSI and east asian chars\"\"\"\n\nfrom __future__ import unicode_literals\n\n\nimport re\n\ntry:\n    from wcwidth import wcwidth\nexcept ImportError:  # pragma: no cover\n    wcwidth = len  # pragma: no cover\n\nfrom .compat import to_unicode\n\n\nclass ANSIMultiByteString(object):\n\n    ANSI_REGEX = re.compile(r\"(\\x1B(?:[()][AB012]|[@-Z\\\\-_]|\\[[0-?]*[ -/]*[@-~]))\")\n    ANSI_RESET = \"\\x1b[0m\"\n\n    def __init__(self, string):\n        self._string = []\n        self._state = []\n        self._width = []\n        self._termwidth = 0\n\n        state = set()\n\n        for token in re.split(self.ANSI_REGEX, to_unicode(string)):\n            if token:\n                if re.match(self.ANSI_REGEX, token):\n                    if token == self.ANSI_RESET:\n                        state.clear()\n                    else:\n                        state.add(token)\n                else:\n                    s_copy = set(state)\n                    for char in token:\n                        w = wcwidth(char)\n                        if w == -1:\n                            raise ValueError(\n                                f\"Unsupported Literal {repr(char)} in string {repr(token)}\"\n                            )\n                        self._termwidth += w\n                        self._string.append(char)\n                        self._width.append(w)\n                        self._state.append(s_copy)\n\n    def __len__(self):\n        return len(self._string)\n\n    def __getitem__(self, key):\n        if isinstance(key, int):\n            if self._state[key]:\n                return \"\".join(self._state[key]) + self._string[key] + self.ANSI_RESET\n            return self._string[key]\n        if isinstance(key, slice):\n            return self._slice(key)\n        raise TypeError(\n            f\"table indices must be integers or slices, not {type(key).__name__}\"\n        )\n\n    def _slice(self, key):\n        res = []\n        prev_state = set()\n        for char, state in zip(self._string[key], self._state[key]):\n            if prev_state == state:\n                pass\n            elif prev_state <= state:\n                res.extend(state - prev_state)\n            else:\n                res.append(self.ANSI_RESET)\n                res.extend(state)\n            prev_state = state\n            res.append(char)\n        if prev_state:\n            res.append(self.ANSI_RESET)\n        return \"\".join(res)\n\n    def termwidth(self):\n        \"\"\"Returns the width of string as when printed to a terminal\"\"\"\n        return self._termwidth\n\n    def wrap(self, width):\n        \"\"\"Returns a partition of the string based on `width`\"\"\"\n        res = []\n        prev_state = set()\n        part = []\n        cwidth = 0\n        for char, _width, state in zip(self._string, self._width, self._state):\n            if cwidth + _width > width:\n                if prev_state:\n                    part.append(self.ANSI_RESET)\n                res.append(\"\".join(part))\n                prev_state = set()\n                part = []\n                cwidth = 0\n            cwidth += _width\n            if prev_state == state:\n                pass\n            elif prev_state <= state:\n                part.extend(state - prev_state)\n            else:\n                part.append(self.ANSI_RESET)\n                part.extend(state)\n            prev_state = state\n            part.append(char)\n        if prev_state:\n            part.append(self.ANSI_RESET)\n        if part:\n            res.append(\"\".join(part))\n        return res\n"
  },
  {
    "path": "beautifultable/base.py",
    "content": "import abc\nimport weakref\n\n\nclass BTBaseList(metaclass=abc.ABCMeta):\n    def __init__(self, table, value):\n        self._table = table\n        self._value = self._validate(list(value))\n\n    @property\n    def _table(self):\n        return self._table_ref()\n\n    @_table.setter\n    def _table(self, value):\n        self._table_ref = weakref.ref(value)\n\n    @property\n    def value(self):\n        return self._value\n\n    def __len__(self):\n        return len(self._value)\n\n    def __iter__(self):\n        return iter(self._value)\n\n    def __next__(self):\n        return next(self._value)\n\n    def __repr__(self):\n        class_ = type(self).__name__\n        data = \", \".join(repr(v) for v in self._value)\n        return \"{}<{}>\".format(class_, data)\n\n    def __eq__(self, other):\n        if len(self) != len(other):\n            return False\n        for i, j in zip(self, other):\n            if i != j:\n                return False\n        return True\n\n    def __contains__(self, item):\n        \"\"\"Returns whether `item` is present\"\"\"\n        return item in self._value\n\n    def _append(self, item):\n        self._value.append(item)\n\n    def _insert(self, i, item):\n        self._value.insert(i, item)\n\n    def _pop(self, i=-1):\n        return self._value.pop(self._get_canonical_key(i))\n\n    def _remove(self, item):\n        self._value.remove(item)\n\n    def _reverse(self):\n        self._value.reverse()\n\n    def _sort(self, key, reverse=False):\n        self._value.sort(key=key, reverse=reverse)\n\n    def _clear(self):\n        self._value.clear()\n\n    def count(self, item):\n        return self._value.count(item)\n\n    def index(self, item, *args):\n        \"\"\"Returns the index of `item`\"\"\"\n        try:\n            return self._value.index(item, *args)\n        except ValueError:\n            raise KeyError(f\"Key {item} is not available\")\n\n    def __getitem__(self, key):\n        \"\"\"Returns item at index or header `key`\"\"\"\n        return self._value[self._get_canonical_key(key)]\n\n    def __setitem__(self, key, value):\n        \"\"\"Updates item at index or header `key`\"\"\"\n        self._value[self._get_canonical_key(key)] = value\n\n    def __delitem__(self, key):\n        del self._value[self._get_canonical_key(key)]\n\n    def _validate(self, value):\n        if len(value) != self._get_ideal_length():\n            raise ValueError(\n                f\"'Expected iterable of length {self._get_ideal_length()}, got {len(value)}\"\n            )\n\n        return value\n\n    @abc.abstractmethod\n    def _get_canonical_key(self, key):\n        pass\n\n    @abc.abstractmethod\n    def _get_ideal_length(self):\n        pass\n\n\nclass BTBaseRow(BTBaseList):\n    def _get_canonical_key(self, key):\n        return self._table.columns._canonical_key(key)\n\n    def _get_ideal_length(self):\n        return self._table._ncol\n\n    def _validate(self, value):\n        if self._get_ideal_length() == 0 and len(value) > 0:\n            self._table.columns._reset_state(len(value))\n        return super(BTBaseRow, self)._validate(value)\n\n\nclass BTBaseColumn(BTBaseList):\n    def _get_canonical_key(self, key):\n        return self._table.rows._canonical_key(key)\n\n    def _get_ideal_length(self):\n        return len(self._table._data)\n\n    def _validate(self, value):\n        if self._get_ideal_length() == 0 and len(value) > 0:\n            self._table.rows._reset_state(len(value))\n        return super(BTBaseColumn, self)._validate(value)\n"
  },
  {
    "path": "beautifultable/beautifultable.py",
    "content": "\"\"\"This module provides BeautifulTable class\n\nIt is intended for printing Tabular data to terminals.\n\nExample\n-------\n>>> from beautifultable import BeautifulTable\n>>> table = BeautifulTable()\n>>> table.columns.header = ['1st column', '2nd column']\n>>> for i in range(5):\n...    table.rows.apppend([i, i*i])\n...\n>>> print(table)\n+------------+------------+\n| 1st column | 2nd column |\n+------------+------------+\n|     0      |     0      |\n+------------+------------+\n|     1      |     1      |\n+------------+------------+\n|     2      |     4      |\n+------------+------------+\n|     3      |     9      |\n+------------+------------+\n|     4      |     16     |\n+------------+------------+\n\"\"\"\nfrom __future__ import division, unicode_literals\n\nimport copy\nimport csv\nimport warnings\n\nfrom . import enums\n\nfrom .utils import (\n    pre_process,\n    termwidth,\n    deprecated,\n    deprecated_param,\n    deprecation_message,\n    ensure_type,\n)\nfrom .compat import basestring, Iterable, to_unicode\nfrom .base import BTBaseList\nfrom .helpers import (\n    BTRowCollection,\n    BTColumnCollection,\n    BTRowHeader,\n    BTColumnHeader,\n)\n\n\n__all__ = [\n    \"BeautifulTable\",\n    \"BTRowCollection\",\n    \"BTColumnCollection\",\n    \"BTRowHeader\",\n    \"BTColumnHeader\",\n    \"BTBorder\",\n]\n\n\nclass BTBorder:\n    \"\"\"Class to control how each section of the table's border is rendered.\n\n    To disable a behaviour, just set its corresponding attribute\n    to an empty string\n\n    Attributes\n    ----------\n\n    top : str\n        Character used to draw the top border.\n\n    left : str\n        Character used to draw the left border.\n\n    bottom : str\n        Character used to draw the bottom border.\n\n    right : str\n        Character used to draw the right border.\n\n    top_left : str\n        Left most character of the top border.\n\n    bottom_left : str\n        Left most character of the bottom border.\n\n    bottom_right : str\n        Right most character of the bottom border.\n\n    top_right : str\n        Right most character of the top border.\n\n    header_left : str\n        Left most character of the header separator.\n\n    header_right : str\n        Right most character of the header separator.\n\n    top_junction : str\n        Junction character for top border.\n\n    left_junction : str\n        Junction character for left border.\n\n    bottom_junction : str\n        Junction character for bottom border.\n\n    right_junction : str\n        Junction character for right border.\n    \"\"\"\n\n    def __init__(\n        self,\n        top,\n        left,\n        bottom,\n        right,\n        top_left,\n        bottom_left,\n        bottom_right,\n        top_right,\n        header_left,\n        header_right,\n        top_junction,\n        left_junction,\n        bottom_junction,\n        right_junction,\n    ):\n        self.top = top\n        self.left = left\n        self.bottom = bottom\n        self.right = right\n\n        self.top_left = top_left\n        self.bottom_left = bottom_left\n        self.bottom_right = bottom_right\n        self.top_right = top_right\n\n        self.header_left = header_left\n        self.header_right = header_right\n\n        self.top_junction = top_junction\n        self.left_junction = left_junction\n        self.bottom_junction = bottom_junction\n        self.right_junction = right_junction\n\n\ndef _make_getter(attr):\n    return lambda self: getattr(self, attr)\n\n\ndef _make_setter(attr):\n    return lambda self, value: setattr(self, attr, ensure_type(value, basestring))\n\n\nfor prop, attr in [\n    (x, \"_{}\".format(x))\n    for x in (\n        \"top\",\n        \"left\",\n        \"bottom\",\n        \"right\",\n        \"top_left\",\n        \"bottom_left\",\n        \"bottom_right\",\n        \"top_right\",\n        \"header_left\",\n        \"header_right\",\n        \"top_junction\",\n        \"left_junction\",\n        \"bottom_junction\",\n        \"right_junction\",\n    )\n]:\n    setattr(BTBorder, prop, property(_make_getter(attr), _make_setter(attr)))\n\n\nclass BTTableData(BTBaseList):\n    def __init__(self, table, value=None):\n        if value is None:\n            value = []\n        self._table = table\n        self._value = value\n\n    def _get_canonical_key(self, key):\n        return self._table.rows._canonical_key(key)\n\n    def _get_ideal_length(self):\n        pass\n\n\nclass BeautifulTable:\n    \"\"\"Utility Class to print data in tabular format to terminal.\n\n    Parameters\n    ----------\n    maxwidth: int, optional\n        maximum width of the table in number of characters. this is ignored\n        when manually setting the width of the columns. if this value is too\n        low with respect to the number of columns and width of padding, the\n        resulting table may override it(default 80).\n\n    default_alignment : int, optional\n        Default alignment for new columns(default beautifultable.ALIGN_CENTER).\n\n    default_padding : int, optional\n        Default width of the left and right padding for new columns(default 1).\n\n    precision : int, optional\n        All float values will have maximum number of digits after the decimal,\n        capped by this value(Default 3).\n\n    serialno : bool, optional\n        If true, a column will be rendered with serial numbers(**DEPRECATED**).\n\n    serialno_header: str, optional\n        The header of the serial number column if rendered(**DEPRECATED**).\n\n    detect_numerics : bool, optional\n        Whether numeric strings should be automatically detected(Default True).\n\n    sign : SignMode, optional\n        Parameter to control how signs in numeric data are displayed.\n        (default beautifultable.SM_MINUS).\n\n    Attributes\n    ----------\n    precision : int\n        All float values will have maximum number of digits after the decimal,\n        capped by this value(Default 3).\n\n    detect_numerics : bool\n        Whether numeric strings should be automatically detected(Default True).\n    \"\"\"\n\n    @deprecated_param(\"1.0.0\", \"1.2.0\", \"sign_mode\", \"sign\")\n    @deprecated_param(\"1.0.0\", \"1.2.0\", \"numeric_precision\", \"precision\")\n    @deprecated_param(\"1.0.0\", \"1.2.0\", \"max_width\", \"maxwidth\")\n    @deprecated_param(\"1.0.0\", \"1.2.0\", \"serialno\")\n    @deprecated_param(\"1.0.0\", \"1.2.0\", \"serialno_header\")\n    def __init__(\n        self,\n        maxwidth=80,\n        default_alignment=enums.ALIGN_CENTER,\n        default_padding=1,\n        precision=3,\n        serialno=False,\n        serialno_header=\"SN\",\n        detect_numerics=True,\n        sign=enums.SM_MINUS,\n        **kwargs,\n    ):\n\n        kwargs.setdefault(\"max_width\", None)\n        if kwargs[\"max_width\"] is not None:\n            maxwidth = kwargs[\"max_width\"]\n\n        kwargs.setdefault(\"numeric_precision\", None)\n        if kwargs[\"numeric_precision\"] is not None:\n            precision = kwargs[\"numeric_precision\"]\n\n        kwargs.setdefault(\"sign_mode\", None)\n        if kwargs[\"sign_mode\"] is not None:\n            sign = kwargs[\"sign_mode\"]\n\n        self.precision = precision\n        self._serialno = serialno\n        self._serialno_header = serialno_header\n        self.detect_numerics = detect_numerics\n\n        self._sign = sign\n        self.maxwidth = maxwidth\n\n        self._ncol = 0\n        self._data = BTTableData(self)\n\n        self.rows = BTRowCollection(self)\n        self.columns = BTColumnCollection(self, default_alignment, default_padding)\n\n        self._header_separator = \"\"\n        self._header_junction = \"\"\n        self._column_separator = \"\"\n        self._row_separator = \"\"\n        self.border = \"\"\n        self.set_style(enums.STYLE_DEFAULT)\n\n    def __copy__(self):\n        obj = type(self)()\n        obj.__dict__.update({k: copy.copy(v) for k, v in self.__dict__.items()})\n\n        obj.rows._table = obj\n        obj.rows.header._table = obj\n\n        obj.columns._table = obj\n        obj.columns.header._table = obj\n        obj.columns.alignment._table = obj\n        obj.columns.width._table = obj\n        obj.columns.padding_left._table = obj\n        obj.columns.padding_right._table = obj\n\n        obj._data._table = obj\n        for row in obj._data:\n            row._table = obj\n\n        return obj\n\n    def __deepcopy__(self, memo):\n        obj = type(self)()\n        obj.__dict__.update(\n            {k: copy.deepcopy(v, memo) for k, v in self.__dict__.items()}\n        )\n\n        obj.rows._table = obj\n        obj.rows.header._table = obj\n\n        obj.columns._table = obj\n        obj.columns.header._table = obj\n        obj.columns.alignment._table = obj\n        obj.columns.width._table = obj\n        obj.columns.padding_left._table = obj\n        obj.columns.padding_right._table = obj\n\n        obj._data._table = obj\n        for row in obj._data:\n            row._table = obj\n\n        return obj\n\n    def __setattr__(self, name, value):\n        attrs = (\n            \"left_border_char\",\n            \"right_border_char\",\n            \"top_border_char\",\n            \"bottom_border_char\",\n            \"header_separator_char\",\n            \"column_separator_char\",\n            \"row_separator_char\",\n            \"intersect_top_left\",\n            \"intersect_top_mid\",\n            \"intersect_top_right\",\n            \"intersect_header_left\",\n            \"intersect_header_mid\",\n            \"intersect_header_right\",\n            \"intersect_row_left\",\n            \"intersect_row_mid\",\n            \"intersect_row_right\",\n            \"intersect_bottom_left\",\n            \"intersect_bottom_mid\",\n            \"intersect_bottom_right\",\n        )\n        if to_unicode(name) in attrs:\n            warnings.warn(\n                deprecation_message(name, \"1.0.0\", \"1.2.0\", None),\n                FutureWarning,\n            )\n            value = ensure_type(value, basestring, name)\n        super(BeautifulTable, self).__setattr__(name, value)\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTRowCollection.__len__,\n        details=\"Use len(BeautifulTable.rows)' instead.\",\n    )\n    def __len__(self):  # pragma: no cover\n        return len(self.rows)\n\n    @deprecated(\n        \"1.0.0\" \"1.2.0\",\n        BTRowCollection.__iter__,\n        details=\"Use iter(BeautifulTable.rows)' instead.\",\n    )\n    def __iter__(self):  # pragma: no cover\n        return iter(self.rows)\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnCollection.__contains__,\n        details=\"Use ''value' in BeautifulTable.{columns|rows}' instead.\",\n    )\n    def __contains__(self, key):  # pragma: no cover\n        if isinstance(key, basestring):\n            return key in self.columns\n        elif isinstance(key, Iterable):\n            return key in self.rows\n        else:\n            raise TypeError(f\"'key' must be str or Iterable, not {type(key).__name__}\")\n\n    def __repr__(self):\n        return repr(self._data)\n\n    def __str__(self):\n        if len(self.rows) == 0 or len(self.columns) == 0:\n            return \"\"\n\n        string_ = []\n        for line in self._get_string([], append=False):\n            string_.append(line)\n\n        return \"\\n\".join(string_)\n\n    # ************************Properties Begin Here************************\n    @property\n    def shape(self):\n        \"\"\"Read only attribute which returns the shape of the table.\"\"\"\n        return (len(self.rows), len(self.columns))\n\n    @property\n    def sign(self):\n        \"\"\"Attribute to control how signs are displayed for numerical data.\n\n        It can be one of the following:\n\n        ========================  =============================================\n         Option                    Meaning\n        ========================  =============================================\n         beautifultable.SM_PLUS    A sign should be used for both +ve and -ve\n                                   numbers.\n\n         beautifultable.SM_MINUS   A sign should only be used for -ve numbers.\n\n         beautifultable.SM_SPACE   A leading space should be used for +ve\n                                   numbers and a minus sign for -ve numbers.\n        ========================  =============================================\n        \"\"\"\n        return self._sign\n\n    @sign.setter\n    def sign(self, value):\n        if not isinstance(value, enums.SignMode):\n            allowed = (f\"{type(self).__name__}.{i.name}\" for i in enums.SignMode)\n            error_msg = \"allowed values for sign are: \" + \", \".join(allowed)\n            raise ValueError(error_msg)\n        self._sign = value\n\n    @property\n    def border(self):\n        \"\"\"Characters used to draw the border of the table.\n\n        You can set this directly to a character or use it's several attribute\n        to control how each section of the table is rendered.\n        It is an instance of :class:`~.BTBorder`\n        \"\"\"\n        return self._border\n\n    @border.setter\n    def border(self, value):\n        self._border = BTBorder(\n            top=value,\n            left=value,\n            bottom=value,\n            right=value,\n            top_left=value,\n            bottom_left=value,\n            bottom_right=value,\n            top_right=value,\n            header_left=value,\n            header_right=value,\n            top_junction=value,\n            left_junction=value,\n            bottom_junction=value,\n            right_junction=value,\n        )\n\n    @property\n    def junction(self):\n        \"\"\"Character used to draw junctions in the row separator.\"\"\"\n        return self._junction\n\n    @junction.setter\n    def junction(self, value):\n        self._junction = ensure_type(value, basestring)\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.header.fget)\n    def serialno(self):  # pragma: no cover\n        return self._serialno\n\n    @serialno.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.header.fget)\n    def serialno(self, value):  # pragma: no cover\n        self._serialno = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\")\n    def serialno_header(self):  # pragma: no cover\n        return self._serialno_header\n\n    @serialno_header.setter\n    @deprecated(\"1.0.0\", \"1.2.0\")\n    def serialno_header(self, value):  # pragma: no cover\n        self._serialno_header = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", sign.fget)\n    def sign_mode(self):  # pragma: no cover\n        return self.sign\n\n    @sign_mode.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", sign.fget)\n    def sign_mode(self, value):  # pragma: no cover\n        self.sign = value\n\n    @property\n    def maxwidth(self):\n        \"\"\"get/set the maximum width of the table.\n\n        The width of the table is guaranteed to not exceed this value. If it\n        is not possible to print a given table with the width provided, this\n        value will automatically adjust.\n        \"\"\"\n        offset = (len(self.columns) - 1) * termwidth(self.columns.separator)\n        offset += termwidth(self.border.left)\n        offset += termwidth(self.border.right)\n        self._maxwidth = max(self._maxwidth, offset + len(self.columns))\n        return self._maxwidth\n\n    @maxwidth.setter\n    def maxwidth(self, value):\n        self._maxwidth = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", maxwidth.fget)\n    def max_table_width(self):  # pragma: no cover\n        return self.maxwidth\n\n    @max_table_width.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", maxwidth.fget)\n    def max_table_width(self, value):  # pragma: no cover\n        self.maxwidth = value\n\n    @property\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnCollection.__len__,\n        details=\"Use 'len(self.columns)' instead.\",\n    )\n    def column_count(self):  # pragma: no cover\n        return len(self.columns)\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.width_exceed_policy.fget)\n    def width_exceed_policy(self):  # pragma: no cover\n        return self.columns.width_exceed_policy\n\n    @width_exceed_policy.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.width_exceed_policy.fget)\n    def width_exceed_policy(self, value):  # pragma: no cover\n        self.columns.width_exceed_policy = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.default_alignment.fget)\n    def default_alignment(self):  # pragma: no cover\n        return self.columns.default_alignment\n\n    @default_alignment.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.default_alignment.fget)\n    def default_alignment(self, value):  # pragma: no cover\n        self.columns.default_alignment = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.default_padding.fget)\n    def default_padding(self):  # pragma: no cover\n        return self.columns.default_padding\n\n    @default_padding.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.default_padding.fget)\n    def default_padding(self, value):  # pragma: no cover\n        self.columns.default_padding = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.width.fget)\n    def column_widths(self):  # pragma: no cover\n        return self.columns.width\n\n    @column_widths.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.width.fget)\n    def column_widths(self, value):  # pragma: no cover\n        self.columns.width = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.header.fget)\n    def column_headers(self):  # pragma: no cover\n        return self.columns.header\n\n    @column_headers.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.header.fget)\n    def column_headers(self, value):  # pragma: no cover\n        self.columns.header = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.alignment.fget)\n    def column_alignments(self):  # pragma: no cover\n        return self.columns.alignment\n\n    @column_alignments.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.alignment.fget)\n    def column_alignments(self, value):  # pragma: no cover\n        self.columns.alignment = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.padding_left.fget)\n    def left_padding_widths(self):  # pragma: no cover\n        return self.columns.padding_left\n\n    @left_padding_widths.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.padding_left.fget)\n    def left_padding_widths(self, value):  # pragma: no cover\n        self.columns.padding_left = value\n\n    @property\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.padding_right.fget)\n    def right_padding_widths(self):  # pragma: no cover\n        return self.columns.padding_right\n\n    @right_padding_widths.setter\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.padding_right.fget)\n    def right_padding_widths(self, value):  # pragma: no cover\n        self.columns.padding_right = value\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnCollection.__getitem__,\n        details=\"Use 'BeautifulTable.{columns|rows}[key]' instead.\",\n    )\n    def __getitem__(self, key):  # pragma: no cover\n        return self.columns[key] if isinstance(key, basestring) else self.rows[key]\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnCollection.__setitem__,\n        details=\"Use 'BeautifulTable.{columns|rows}[key]' instead.\",\n    )\n    def __setitem__(self, key, value):  # pragma: no cover\n        if isinstance(key, basestring):\n            self.columns[key] = value\n        else:\n            self.rows[key] = value\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnCollection.__delitem__,\n        details=\"Use 'BeautifulTable.{columns|rows}[key]' instead.\",\n    )\n    def __delitem__(self, key):  # pragma: no cover\n        if isinstance(key, basestring):\n            del self.columns[key]\n        else:\n            del self.rows[key]\n\n    # *************************Properties End Here*************************\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnCollection.__getitem__,\n        details=\"Use 'BeautifulTable.columns[key]' instead.\",\n    )\n    def get_column(self, key):  # pragma: no cover\n        return self.columns[key]\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnHeader.__getitem__,\n        details=\"Use 'BeautifulTable.columns.header[key]' instead.\",\n    )\n    def get_column_header(self, index):  # pragma: no cover\n        return self.columns.header[index]\n\n    @deprecated(\n        \"1.0.0\",\n        \"1.2.0\",\n        BTColumnHeader.__getitem__,\n        details=\"Use 'BeautifulTable.columns.header.index(header)' instead.\",\n    )\n    def get_column_index(self, header):  # pragma: no cover\n        return self.columns.header.index(header)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.filter)\n    def filter(self, key):  # pragma: no cover\n        return self.rows.filter(key)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.sort)\n    def sort(self, key, reverse=False):  # pragma: no cover\n        self.rows.sort(key, reverse=reverse)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.reverse)\n    def reverse(self, value):  # pragma: no cover\n        self.rows.reverse()\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.pop)\n    def pop_row(self, index=-1):  # pragma: no cover\n        return self.rows.pop(index)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.insert)\n    def insert_row(self, index, row):  # pragma: no cover\n        return self.rows.insert(index, row)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.append)\n    def append_row(self, value):  # pragma: no cover\n        self.rows.append(value)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTRowCollection.update)\n    def update_row(self, key, value):  # pragma: no cover\n        self.rows.update(key, value)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.pop)\n    def pop_column(self, index=-1):  # pragma: no cover\n        return self.columns.pop(index)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.insert)\n    def insert_column(self, index, header, column):  # pragma: no cover\n        self.columns.insert(index, column, header)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.append)\n    def append_column(self, header, column):  # pragma: no cover\n        self.columns.append(column, header)\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.update)\n    def update_column(self, header, column):  # pragma: no cover\n        self.columns.update(header, column)\n\n    def set_style(self, style):\n        \"\"\"Set the style of the table from a predefined set of styles.\n\n        Parameters\n        ----------\n        style: Style\n\n            It can be one of the following:\n\n            * beautifultable.STYLE_DEFAULT\n            * beautifultable.STYLE_NONE\n            * beautifultable.STYLE_DOTTED\n            * beautifultable.STYLE_MYSQL\n            * beautifultable.STYLE_SEPARATED\n            * beautifultable.STYLE_COMPACT\n            * beautifultable.STYLE_MARKDOWN\n            * beautifultable.STYLE_RESTRUCTURED_TEXT\n            * beautifultable.STYLE_BOX\n            * beautifultable.STYLE_BOX_DOUBLED\n            * beautifultable.STYLE_BOX_ROUNDED\n            * beautifultable.STYLE_GRID\n        \"\"\"\n        if not isinstance(style, enums.Style):\n            allowed = (f\"{type(self).__name__}.{i.name}\" for i in enums.Style)\n            error_msg = \"allowed values for style are: \" + \", \".join(allowed)\n            raise ValueError(error_msg)\n        style_template = style.value\n        self.border.left = style_template.left_border_char\n        self.border.right = style_template.right_border_char\n        self.border.top = style_template.top_border_char\n        self.border.bottom = style_template.bottom_border_char\n\n        self.border.top_left = style_template.intersect_top_left\n        self.border.bottom_left = style_template.intersect_bottom_left\n        self.border.bottom_right = style_template.intersect_bottom_right\n        self.border.top_right = style_template.intersect_top_right\n\n        self.border.header_left = style_template.intersect_header_left\n        self.border.header_right = style_template.intersect_header_right\n\n        self.columns.header.separator = style_template.header_separator_char\n        self.columns.separator = style_template.column_separator_char\n        self.rows.separator = style_template.row_separator_char\n\n        self.border.top_junction = style_template.intersect_top_mid\n        self.border.left_junction = style_template.intersect_row_left\n        self.border.bottom_junction = style_template.intersect_bottom_mid\n        self.border.right_junction = style_template.intersect_row_right\n        self.columns.header.junction = style_template.intersect_header_mid\n        self.junction = style_template.intersect_row_mid\n\n    def _compute_width(self):\n        \"\"\"Calculate width of column automatically based on data.\"\"\"\n        table_width = self._width\n        lpw, rpw = self.columns.padding_left, self.columns.padding_right\n        pad_widths = [(lpw[i] + rpw[i]) for i in range(len(self.columns))]\n        maxwidths = [0 for index in range(len(self.columns))]\n        offset = table_width - sum(self.columns.width) + sum(pad_widths)\n        self._maxwidth = max(self._maxwidth, offset + len(self.columns))\n\n        for index, header in enumerate(self.columns.header):\n            max_length = 0\n            for i in pre_process(\n                header, self.detect_numerics, self.precision, self.sign.value\n            ).split(\"\\n\"):\n                output_str = pre_process(\n                    i,\n                    self.detect_numerics,\n                    self.precision,\n                    self.sign.value,\n                )\n                max_length = max(max_length, termwidth(output_str))\n            maxwidths[index] += max_length\n\n        for index, column in enumerate(zip(*self._data)):\n            max_length = maxwidths[index]\n            for i in column:\n                for j in pre_process(\n                    i, self.detect_numerics, self.precision, self.sign.value\n                ).split(\"\\n\"):\n                    output_str = pre_process(\n                        j,\n                        self.detect_numerics,\n                        self.precision,\n                        self.sign.value,\n                    )\n                    max_length = max(max_length, termwidth(output_str))\n            maxwidths[index] = max_length\n\n        sum_ = sum(maxwidths)\n        desired_sum = self._maxwidth - offset\n\n        # Set flag for columns who are within their fair share\n        temp_sum = 0\n        flag = [0] * len(maxwidths)\n        for i, width in enumerate(maxwidths):\n            if width <= int(desired_sum / len(self.columns)):\n                temp_sum += width\n                flag[i] = 1\n            else:\n                # Allocate atleast 1 character width to the column\n                temp_sum += 1\n\n        avail_space = desired_sum - temp_sum\n        actual_space = sum_ - temp_sum\n        shrinked_columns = {}\n\n        # Columns which exceed their fair share should be shrinked based on\n        # how much space is left for the table\n        for i, width in enumerate(maxwidths):\n            self.columns.width[i] = width\n            if not flag[i]:\n                new_width = 1 + int((width - 1) * avail_space / actual_space)\n                if new_width < width:\n                    self.columns.width[i] = new_width\n                    shrinked_columns[new_width] = i\n\n        # Divide any remaining space among shrinked columns\n        if shrinked_columns:\n            extra = self._maxwidth - offset - sum(self.columns.width)\n            actual_space = sum(shrinked_columns)\n\n            if extra > 0:\n                for i, width in enumerate(sorted(shrinked_columns)):\n                    index = shrinked_columns[width]\n                    extra_width = int(width * extra / actual_space)\n                    self.columns.width[i] += extra_width\n                    if i == (len(shrinked_columns) - 1):\n                        extra = self._maxwidth - offset - sum(self.columns.width)\n                        self.columns.width[index] += extra\n\n        for i in range(len(self.columns)):\n            self.columns.width[i] += pad_widths[i]\n\n    @deprecated(\"1.0.0\", \"1.2.0\", BTColumnCollection.padding.fget)\n    def set_padding_widths(self, pad_width):  # pragma: no cover\n        self.columns.padding_left = pad_width\n        self.columns.padding_right = pad_width\n\n    @deprecated(\"1.0.0\", \"1.2.0\")\n    def copy(self):\n        return copy.copy(self)\n\n    @deprecated_param(\"1.0.0\", \"1.2.0\", \"clear_metadata\", \"reset_columns\")\n    def clear(self, reset_columns=False, **kwargs):  # pragma: no cover\n        \"\"\"Clear the contents of the table.\n\n        Clear all rows of the table, and if specified clears all column\n        specific data.\n\n        Parameters\n        ----------\n        reset_columns : bool, optional\n            If it is true(default False), all metadata of columns such as their\n            alignment, padding, width, etc. are also cleared and number of\n            columns is set to 0.\n        \"\"\"\n        kwargs.setdefault(\"clear_metadata\", None)\n        if kwargs[\"clear_metadata\"]:\n            reset_columns = kwargs[\"clear_metadata\"]\n        self.rows.clear()\n        if reset_columns:\n            self.columns.clear()\n\n    def _get_horizontal_line(\n        self, char, intersect_left, intersect_mid, intersect_right, mask=None\n    ):\n        \"\"\"Get a horizontal line for the table.\n\n        Internal method used to draw all horizontal lines in the table.\n        Column width should be set prior to calling this method. This method\n        detects intersection and handles it according to the values of\n        `intersect_*_*` attributes.\n\n        Parameters\n        ----------\n        char : str\n            Character used to draw the line.\n\n        Returns\n        -------\n        str\n            String which will be printed as a line in the table.\n        \"\"\"\n        width = self._width\n\n        if mask is None:\n            mask = [True] * len(self.columns)\n\n        try:\n            line = list(char * (int(width / termwidth(char)) + 1))[:width]\n        except ZeroDivisionError:\n            line = [\" \"] * width\n\n        if len(line) == 0:\n            return \"\"\n\n        # Only if Special Intersection is enabled and horizontal line is\n        # visible\n        if not char.isspace():\n            # If left border is enabled and it is visible\n            visible_junc = not intersect_left.isspace()\n            if termwidth(self.border.left) > 0:\n                if not (self.border.left.isspace() and visible_junc):\n                    length = min(\n                        termwidth(self.border.left),\n                        termwidth(intersect_left),\n                    )\n                    for i in range(length):\n                        line[i] = intersect_left[i] if mask[0] else \" \"\n            visible_junc = not intersect_right.isspace()\n            # If right border is enabled and it is visible\n            if termwidth(self.border.right) > 0:\n                if not (self.border.right.isspace() and visible_junc):\n                    length = min(\n                        termwidth(self.border.right),\n                        termwidth(intersect_right),\n                    )\n                    for i in range(length):\n                        line[-i - 1] = intersect_right[-i - 1] if mask[-1] else \" \"\n            visible_junc = not intersect_mid.isspace()\n            # If column separator is enabled and it is visible\n            if termwidth(self.columns.separator):\n                if not (self.columns.separator.isspace() and visible_junc):\n                    index = termwidth(self.border.left)\n                    for i in range(len(self.columns) - 1):\n                        if not mask[i]:\n                            for j in range(self.columns.width[i]):\n                                line[index + j] = \" \"\n                        index += self.columns.width[i]\n                        length = min(\n                            termwidth(self.columns.separator),\n                            termwidth(intersect_mid),\n                        )\n                        for j in range(length):\n                            # TODO: we should also hide junctions based on mask\n                            line[index + j] = (\n                                intersect_mid[j] if (mask[i] or mask[i + 1]) else \" \"\n                            )\n                        index += termwidth(self.columns.separator)\n\n        return \"\".join(line)\n\n    def _get_top_border(self, *args, **kwargs):\n        return self._get_horizontal_line(\n            self.border.top,\n            self.border.top_left,\n            self.border.top_junction,\n            self.border.top_right,\n            *args,\n            **kwargs,\n        )\n\n    def _get_header_separator(self, *args, **kwargs):\n        return self._get_horizontal_line(\n            self.columns.header.separator,\n            self.border.header_left,\n            self.columns.header.junction,\n            self.border.header_right,\n            *args,\n            **kwargs,\n        )\n\n    def _get_row_separator(self, *args, **kwargs):\n        return self._get_horizontal_line(\n            self.rows.separator,\n            self.border.left_junction,\n            self.junction,\n            self.border.right_junction,\n            *args,\n            **kwargs,\n        )\n\n    def _get_bottom_border(self, *args, **kwargs):\n        return self._get_horizontal_line(\n            self.border.bottom,\n            self.border.bottom_left,\n            self.border.bottom_junction,\n            self.border.bottom_right,\n            *args,\n            **kwargs,\n        )\n\n    @property\n    def _width(self):\n        \"\"\"Get the actual width of the table as number of characters.\n\n        Column width should be set prior to calling this method.\n\n        Returns\n        -------\n        int\n            Width of the table as number of characters.\n        \"\"\"\n        if len(self.columns) == 0:\n            return 0\n        width = sum(self.columns.width)\n        width += (len(self.columns) - 1) * termwidth(self.columns.separator)\n        width += termwidth(self.border.left)\n        width += termwidth(self.border.right)\n        return width\n\n    @deprecated(\"1.0.0\", \"1.2.0\", _width.fget)\n    def get_table_width(self):  # pragma: no cover\n        return self._width\n\n    def _get_string(self, rows=None, append=False, recalculate_width=True):\n        row_header_visible = bool(\n            \"\".join(x if x is not None else \"\" for x in self.rows.header).strip()\n        ) and (len(self.columns) > 0)\n\n        column_header_visible = bool(\n            \"\".join(x if x is not None else \"\" for x in self.columns.header).strip()\n        ) and (len(self.rows) > 0 or rows is not None)\n\n        # Preparing table for printing serialno, row headers and column headers\n        if len(self.columns) > 0:\n            if self._serialno:\n                self.columns.insert(\n                    0, range(1, len(self.rows) + 1), self._serialno_header\n                )\n\n        if row_header_visible:\n            self.columns.insert(0, self.rows.header)\n\n        if column_header_visible:\n            self.rows.insert(0, self.columns.header)\n\n        if (self.columns._auto_width and recalculate_width) or sum(\n            self.columns.width\n        ) == 0:\n            self._compute_width()\n\n        try:\n            # Rendering the top border\n            if self.border.top:\n                yield self._get_top_border()\n\n            # Print column headers if not empty or only spaces\n            row_iterator = iter(self.rows)\n            if column_header_visible:\n                yield next(row_iterator)._get_string(\n                    align=self.columns.header.alignment\n                )\n                if self.columns.header.separator:\n                    yield self._get_header_separator()\n\n            # Printing rows\n            first_row_encountered = False\n            for i, row in enumerate(row_iterator):\n                if first_row_encountered and self.rows.separator:\n                    yield self._get_row_separator()\n                first_row_encountered = True\n                content = to_unicode(row)\n                yield content\n\n            if rows is not None:\n                # Printing additional rows\n                prev_length = len(self.rows)\n                for i, row in enumerate(rows, start=1):\n                    if first_row_encountered and self.rows.separator:\n                        yield self._get_row_separator()\n                    first_row_encountered = True\n                    if self._serialno:\n                        row.insert(0, prev_length + i)\n                    if row_header_visible:\n                        self.rows.append([None] + list(row))\n                    else:\n                        self.rows.append(row)\n                    content = to_unicode(self.rows[-1])\n                    if not append:\n                        self.rows.pop()\n                    yield content\n\n            # Rendering the bottom border\n            if self.border.bottom:\n                yield self._get_bottom_border()\n        except Exception:\n            raise\n        finally:\n            # Cleanup\n            if column_header_visible:\n                self.rows.pop(0)\n\n            if row_header_visible:\n                self.columns.pop(0)\n\n            if len(self.columns) > 0:\n                if self._serialno:\n                    self.columns.pop(0)\n        return\n\n    def stream(self, rows, append=False):\n        \"\"\"Get a generator for the table.\n\n        This should be used in cases where data takes time to retrieve and it\n        is required to be displayed as soon as possible. Any existing rows in\n        the table shall also be returned. It is essential that atleast one of\n        column header, width or existing rows set before calling this method.\n\n        Parameters\n        ----------\n        rows : iterable\n            A generator which yields one row at a time.\n\n        append : bool, optional\n            If rows should also be appended to the table.(Default False)\n\n        Returns\n        -------\n        iterable:\n            string representation of the table as a generators\n        \"\"\"\n        for line in self._get_string(rows, append=append, recalculate_width=False):\n            yield line\n\n    @deprecated(\"1.0.0\", \"1.2.0\", str)\n    def get_string(self):\n        return str(self)\n\n    def to_csv(self, file_name, *args, **kwargs):\n        \"\"\"Export table to CSV format.\n\n        Parameters\n        ----------\n        file_name : str\n            Path to CSV file.\n        \"\"\"\n\n        if not isinstance(file_name, str):\n            raise ValueError(\n                f\"Expected 'file_name' to be string, got {type(file_name).__name__}\"\n            )\n\n        with open(file_name, mode=\"wt\", newline=\"\") as csv_file:\n            csv_writer = csv.writer(csv_file, *args, **kwargs)\n            if bool(\n                \"\".join(x if x is not None else \"\" for x in self.columns.header).strip()\n            ):\n                csv_writer.writerow(self.columns.header)\n            csv_writer.writerows(self.rows)\n\n    def from_csv(self, file_name, header=True, **kwargs):\n        \"\"\"Create table from CSV file.\n\n        Parameters\n        ----------\n        file_name : str\n            Path to CSV file.\n        header : bool, optional\n            Whether First row in CSV file should be parsed as table header.\n\n        Raises\n        ------\n        ValueError\n            If `file_name` is not str type.\n        FileNotFoundError\n            If `file_name` is not valid path to file.\n        \"\"\"\n\n        if not isinstance(file_name, str):\n            raise ValueError(\n                f\"Expected 'file_name' to be string, got {type(file_name).__name__}\"\n            )\n\n        with open(file_name, mode=\"rt\", newline=\"\") as csv_file:\n            csv_reader = csv.reader(csv_file, **kwargs)\n\n            if header:\n                self.columns.header = next(csv_reader)\n            for row in csv_reader:\n                self.rows.append(row)\n            return self\n\n    def to_df(self):\n        \"\"\"Export table to dataframe.\n\n        This method requires that you have `pandas` already installed in your machine.\n\n        Returns\n        -------\n        pandas.Dataframe:\n            The exported dataframe\n        \"\"\"\n        try:\n            import pandas as pd\n        except ImportError:\n            warnings.warn(\n                \"This method requires that 'pandas' is installed.\", RuntimeWarning\n            )\n            raise\n\n        # If there are column headers then it will act as a column of dataframe\n        headers = list(self.columns.header)\n        if headers.count(None) == len(headers):\n            headers = None\n\n        # If there are row headers then it will act as an Index\n        index = list(self.rows.header)\n        if index.count(None) == len(index):\n            index = None\n\n        return pd.DataFrame(\n            [list(row) for row in self.rows], columns=headers, index=index\n        )\n\n    def from_df(self, df):\n        \"\"\"Import table from dataframe.\n\n        Parameters\n        ----------\n        df : pandas.Dataframe\n            input dataframe\n        \"\"\"\n        data = df.to_dict()\n\n        # Dataframe columns will act as a column headers\n        headers = list(data.keys())\n\n        # Index of dataframe will act as a row headers\n        row_header = list(df.index)\n\n        for header in headers:\n            self.columns.append(\n                [data[header][indx] for indx in row_header], header=str(header)\n            )\n\n        self.rows.header = row_header\n        return self\n"
  },
  {
    "path": "beautifultable/compat.py",
    "content": "from itertools import zip_longest  # noqa: F401\nfrom collections.abc import Iterable  # noqa: F401\n\nto_unicode = str\nbasestring = (str, bytes)\n"
  },
  {
    "path": "beautifultable/enums.py",
    "content": "from __future__ import unicode_literals\nimport enum\n\nfrom .styles import (\n    DefaultStyle,\n    NoStyle,\n    DottedStyle,\n    MySQLStyle,\n    SeparatedStyle,\n    CompactStyle,\n    MarkdownStyle,\n    RestructuredTextStyle,\n    BoxStyle,\n    DoubledBoxStyle,\n    RoundedStyle,\n    GridStyle,\n)\n\n\nclass WidthExceedPolicy(enum.Enum):\n    WEP_WRAP = 1\n    WEP_STRIP = 2\n    WEP_ELLIPSIS = 3\n\n    def __repr__(self):\n        return self.name\n\n\nclass SignMode(enum.Enum):\n    SM_PLUS = \"+\"\n    SM_MINUS = \"-\"\n    SM_SPACE = \" \"\n\n    def __repr__(self):\n        return self.name\n\n\nclass Alignment(enum.Enum):\n    ALIGN_LEFT = \"<\"\n    ALIGN_CENTER = \"^\"\n    ALIGN_RIGHT = \">\"\n\n    def __repr__(self):\n        return self.name\n\n\nclass Style(enum.Enum):\n    STYLE_DEFAULT = DefaultStyle\n    STYLE_NONE = NoStyle\n    STYLE_DOTTED = DottedStyle\n    STYLE_MYSQL = MySQLStyle\n    STYLE_SEPARATED = SeparatedStyle\n    STYLE_COMPACT = CompactStyle\n    STYLE_MARKDOWN = MarkdownStyle\n    STYLE_RST = RestructuredTextStyle\n    STYLE_BOX = BoxStyle\n    STYLE_BOX_DOUBLED = DoubledBoxStyle\n    STYLE_BOX_ROUNDED = RoundedStyle\n    STYLE_GRID = GridStyle\n\n    def __repr__(self):\n        return self.name\n\n\nWEP_WRAP = WidthExceedPolicy.WEP_WRAP\nWEP_STRIP = WidthExceedPolicy.WEP_STRIP\nWEP_ELLIPSIS = WidthExceedPolicy.WEP_ELLIPSIS\nSM_PLUS = SignMode.SM_PLUS\nSM_MINUS = SignMode.SM_MINUS\nSM_SPACE = SignMode.SM_SPACE\nALIGN_LEFT = Alignment.ALIGN_LEFT\nALIGN_CENTER = Alignment.ALIGN_CENTER\nALIGN_RIGHT = Alignment.ALIGN_RIGHT\nSTYLE_DEFAULT = Style.STYLE_DEFAULT\nSTYLE_NONE = Style.STYLE_NONE\nSTYLE_DOTTED = Style.STYLE_DOTTED\nSTYLE_SEPARATED = Style.STYLE_SEPARATED\nSTYLE_COMPACT = Style.STYLE_COMPACT\nSTYLE_MYSQL = Style.STYLE_MYSQL\nSTYLE_MARKDOWN = Style.STYLE_MARKDOWN\nSTYLE_RST = Style.STYLE_RST\nSTYLE_BOX = Style.STYLE_BOX\nSTYLE_BOX_DOUBLED = Style.STYLE_BOX_DOUBLED\nSTYLE_BOX_ROUNDED = Style.STYLE_BOX_ROUNDED\nSTYLE_GRID = Style.STYLE_GRID\n"
  },
  {
    "path": "beautifultable/helpers.py",
    "content": "import copy\nimport weakref\nimport operator\n\nfrom . import enums\nfrom .base import BTBaseRow, BTBaseColumn\nfrom .utils import pre_process, termwidth, textwrap, ensure_type\nfrom .compat import basestring, Iterable, to_unicode, zip_longest\nfrom .meta import AlignmentMetaData, NonNegativeIntegerMetaData\n\n\nclass BTRowHeader(BTBaseColumn):\n    def __init__(self, table, value):\n        for i in value:\n            self._validate_item(i)\n        super(BTRowHeader, self).__init__(table, value)\n\n    def __setitem__(self, key, value):\n        self._validate_item(value)\n        super(BTRowHeader, self).__setitem__(key, value)\n\n    def _validate_item(self, value):\n        if not (isinstance(value, basestring) or value is None):\n            raise TypeError(f\"header must be of type 'str', got {type(value).__name__}\")\n\n\nclass BTColumnHeader(BTBaseRow):\n    def __init__(self, table, value):\n        for i in value:\n            self._validate_item(i)\n        super(BTColumnHeader, self).__init__(table, value)\n        self.alignment = None\n\n    @property\n    def alignment(self):\n        \"\"\"get/set alignment of the column header of the table.\n\n        It can be any iterable containing only the following:\n\n        * beautifultable.ALIGN_LEFT\n        * beautifultable.ALIGN_CENTER\n        * beautifultable.ALIGN_RIGHT\n        \"\"\"\n        return self._alignment\n\n    @alignment.setter\n    def alignment(self, value):\n        if value is None:\n            self._alignment = None\n            return\n        if isinstance(value, enums.Alignment):\n            value = [value] * len(self)\n        self._alignment = AlignmentMetaData(self._table, value)\n\n    @property\n    def separator(self):\n        \"\"\"Character used to draw the line seperating header from the table.\"\"\"\n        return self._table._header_separator\n\n    @separator.setter\n    def separator(self, value):\n        self._table._header_separator = ensure_type(value, basestring)\n\n    @property\n    def junction(self):\n        \"\"\"Character used to draw junctions in the header separator.\"\"\"\n        return self._table._header_junction\n\n    @junction.setter\n    def junction(self, value):\n        self._table._header_junction = ensure_type(value, basestring)\n\n    def __setitem__(self, key, value):\n        self._validate_item(value)\n        super(BTColumnHeader, self).__setitem__(key, value)\n\n    def _validate_item(self, value):\n        if not (isinstance(value, basestring) or value is None):\n            raise TypeError(f\"header must be of type 'str', got {type(value).__name__}\")\n\n\nclass BTRowData(BTBaseRow):\n    def _get_padding(self):\n        return (\n            self._table.columns.padding_left,\n            self._table.columns.padding_right,\n        )\n\n    def _clamp_row(self, row):\n        \"\"\"Process a row so that it is clamped by column_width.\n\n        Parameters\n        ----------\n        row : array_like\n             A single row.\n\n        Returns\n        -------\n        list of list:\n            List representation of the `row` after it has been processed\n            according to width exceed policy.\n        \"\"\"\n        table = self._table\n        lpw, rpw = self._get_padding()\n        wep = table.columns.width_exceed_policy\n\n        result = []\n\n        if (\n            wep is enums.WidthExceedPolicy.WEP_STRIP\n            or wep is enums.WidthExceedPolicy.WEP_ELLIPSIS\n        ):\n\n            # Let's strip the row\n            delimiter = \"\" if wep is enums.WidthExceedPolicy.WEP_STRIP else \"...\"\n            row_item_list = []\n            for index, row_item in enumerate(row):\n                left_pad = table.columns._pad_character * lpw[index]\n                right_pad = table.columns._pad_character * rpw[index]\n                clmp_str = (\n                    left_pad\n                    + self._clamp_string(row_item, index, delimiter)\n                    + right_pad\n                )\n                row_item_list.append(clmp_str)\n            result.append(row_item_list)\n        elif wep is enums.WidthExceedPolicy.WEP_WRAP:\n\n            # Let's wrap the row\n            string_partition = []\n\n            for index, row_item in enumerate(row):\n                width = table.columns.width[index] - lpw[index] - rpw[index]\n                string_partition.append(textwrap(row_item, width))\n\n            for row_items in zip_longest(*string_partition, fillvalue=\"\"):\n                row_item_list = []\n                for index, row_item in enumerate(row_items):\n                    left_pad = table.columns._pad_character * lpw[index]\n                    right_pad = table.columns._pad_character * rpw[index]\n                    row_item_list.append(left_pad + row_item + right_pad)\n                result.append(row_item_list)\n\n        return result or [[\"\"] * len(table.columns)]\n\n    def _clamp_string(self, row_item, index, delimiter=\"\"):\n        \"\"\"Clamp `row_item` to fit in column referred by index.\n\n        This method considers padding and appends the delimiter if `row_item`\n        needs to be truncated.\n\n        Parameters\n        ----------\n        row_item: str\n            String which should be clamped.\n\n        index: int\n            Index of the column `row_item` belongs to.\n\n        delimiter: str\n            String which is to be appended to the clamped string.\n\n        Returns\n        -------\n        str\n            The modified string which fits in it's column.\n        \"\"\"\n        lpw, rpw = self._get_padding()\n        width = self._table.columns.width[index] - lpw[index] - rpw[index]\n\n        if termwidth(row_item) <= width:\n            return row_item\n        else:\n            if width - len(delimiter) >= 0:\n                clamped_string = (\n                    textwrap(row_item, width - len(delimiter))[0] + delimiter\n                )\n            else:\n                clamped_string = delimiter[:width]\n            return clamped_string\n\n    def _get_string(\n        self,\n        align=None,\n        mask=None,\n        draw_left_border=True,\n        draw_right_border=True,\n    ):\n        \"\"\"Return a string representation of a row.\"\"\"\n\n        rows = []\n\n        table = self._table\n        width = table.columns.width\n        sign = table.sign\n\n        if align is None:\n            align = table.columns.alignment\n\n        if mask is None:\n            mask = [True] * len(table.columns)\n\n        lpw, rpw = self._get_padding()\n\n        string = []\n        for i, item in enumerate(self._value):\n            if isinstance(item, type(table)):\n                # temporarily change the max width of the table\n                curr_maxwidth = item.maxwidth\n                item.maxwidth = width[i] - lpw[i] - rpw[i]\n                rows.append(\n                    pre_process(\n                        item,\n                        table.detect_numerics,\n                        table.precision,\n                        sign.value,\n                    ).split(\"\\n\")\n                )\n                item.maxwidth = curr_maxwidth\n            else:\n                rows.append(\n                    pre_process(\n                        item,\n                        table.detect_numerics,\n                        table.precision,\n                        sign.value,\n                    ).split(\"\\n\")\n                )\n        for row in map(list, zip_longest(*rows, fillvalue=\"\")):\n            for i in range(len(row)):\n                row[i] = pre_process(\n                    row[i],\n                    table.detect_numerics,\n                    table.precision,\n                    sign.value,\n                )\n            for row_ in self._clamp_row(row):\n                for i in range(len(table.columns)):\n                    # str.format method doesn't work for multibyte strings\n                    # hence, we need to manually align the texts instead\n                    # of using the align property of the str.format method\n                    pad_len = width[i] - termwidth(row_[i])\n                    if align[i].value == \"<\":\n                        right_pad = \" \" * pad_len\n                        row_[i] = to_unicode(row_[i]) + right_pad\n                    elif align[i].value == \">\":\n                        left_pad = \" \" * pad_len\n                        row_[i] = left_pad + to_unicode(row_[i])\n                    else:\n                        left_pad = \" \" * (pad_len // 2)\n                        right_pad = \" \" * (pad_len - pad_len // 2)\n                        row_[i] = left_pad + to_unicode(row_[i]) + right_pad\n                content = []\n                for j, item in enumerate(row_):\n                    if j > 0:\n                        content.append(\n                            table.columns.separator\n                            if (mask[j - 1] or mask[j])\n                            else \" \" * termwidth(table.columns.separator)\n                        )\n                    content.append(item)\n                content = \"\".join(content)\n                content = (\n                    table.border.left if mask[0] else \" \" * termwidth(table.border.left)\n                ) + content\n                content += (\n                    table.border.right\n                    if mask[-1]\n                    else \" \" * termwidth(table.border.right)\n                )\n                string.append(content)\n        return \"\\n\".join(string)\n\n    def __str__(self):\n        return self._get_string()\n\n    def aslist(self):\n        \"\"\"Return list of row values.\"\"\"\n        return self.value\n\n    def asdict(self):\n        \"\"\"\n        Return dictionary where key is column header and value as row value and\n        raise a Warning if coulmn header invalid(not provided) or empty.\n        \"\"\"\n        header_rowval_map = {}\n        for header, row_val in zip(self._table.columns.header, self.value):\n            if header is None or header == \"\":\n                raise Warning(\"Column header is not provided or invalid\")\n            header_rowval_map[header] = row_val\n        return header_rowval_map\n\n\nclass BTColumnData(BTBaseColumn):\n    def aslist(self):\n        \"\"\"Return list of column values.\"\"\"\n        return self.value\n\n    def asdict(self):\n        \"\"\"\n        Raise a NotImplementedError as currently it is not implemented\n        \"\"\"\n        raise NotImplementedError(\"Currently supported for rows only\")\n\n\nclass BTRowCollection(object):\n    def __init__(self, table):\n        self._table = table\n        self._reset_state(0)\n\n    @property\n    def _table(self):\n        return self._table_ref()\n\n    @_table.setter\n    def _table(self, value):\n        self._table_ref = weakref.ref(value)\n\n    def _reset_state(self, nrow):\n        self._table._data = type(self._table._data)(\n            self._table,\n            [BTRowData(self._table, [None] * self._table._ncol) for i in range(nrow)],\n        )\n        self.header = BTRowHeader(self._table, [None] * nrow)\n\n    @property\n    def header(self):\n        return self._header\n\n    @header.setter\n    def header(self, value):\n        self._header = BTRowHeader(self._table, value)\n\n    @property\n    def separator(self):\n        \"\"\"Character used to draw the line seperating two rows.\"\"\"\n        return self._table._row_separator\n\n    @separator.setter\n    def separator(self, value):\n        self._table._row_separator = ensure_type(value, basestring)\n\n    def _canonical_key(self, key):\n        if isinstance(key, (int, slice)):\n            return key\n        elif isinstance(key, basestring):\n            return self.header.index(key)\n        raise TypeError(\n            f\"row indices must be int, str or slices, not {type(key).__name__}\"\n        )\n\n    def __len__(self):\n        return len(self._table._data)\n\n    def __getitem__(self, key):\n        \"\"\"Get a particular row, or a new table by slicing.\n\n        Parameters\n        ----------\n        key : int, slice, str\n            If key is an `int`, returns a row at index `key`.\n            If key is an `str`, returns the first row with heading `key`.\n            If key is a slice object, returns a new sliced table.\n\n        Raises\n        ------\n        TypeError\n            If key is not of type int, slice or str.\n        IndexError\n            If `int` index is out of range.\n        KeyError\n            If `str` key is not found in header.\n        \"\"\"\n        if isinstance(key, slice):\n            new_table = copy.deepcopy(self._table)\n            new_table.rows.clear()\n            new_table.rows.header = self._table.rows.header[key]\n            for i, r in enumerate(self._table._data[key]):\n                new_table.rows[i] = r.value\n            return new_table\n        if isinstance(key, (int, basestring)):\n            return self._table._data[key]\n        raise TypeError(\n            f\"row indices must be int, str or a slice object, not {type(key).__name__}\"\n        )\n\n    def __delitem__(self, key):\n        \"\"\"Delete a row, or multiple rows by slicing.\n\n        Parameters\n        ----------\n        key : int, slice, str\n            If key is an `int`, deletes a row at index `key`.\n            If key is an `str`, deletes the first row with heading `key`.\n            If key is a slice object, deletes multiple rows.\n\n        Raises\n        ------\n        TypeError\n            If key is not of type int, slice or str.\n        IndexError\n            If `int` key is out of range.\n        KeyError\n            If `str` key is not in header.\n        \"\"\"\n        if isinstance(key, (int, basestring, slice)):\n            del self._table._data[key]\n            del self.header[key]\n        else:\n            raise TypeError(\n                f\"row indices must be int, str or a slice object, not {type(key).__name__}\"\n            )\n\n    def __setitem__(self, key, value):\n        \"\"\"Update a row, or multiple rows by slicing.\n\n        Parameters\n        ----------\n        key : int, slice, str\n            If key is an `int`, updates a row.\n            If key is an `str`, updates the first row with heading `key`.\n            If key is a slice object, updates multiple rows.\n\n        Raises\n        ------\n        TypeError\n            If key is not of type int, slice or str.\n        IndexError\n            If `int` key is out of range.\n        KeyError\n            If `str` key is not in header.\n        \"\"\"\n        if isinstance(key, (int, basestring)):\n            self._table._data[key] = BTRowData(self._table, value)\n        elif isinstance(key, slice):\n            value = [list(row) for row in value]\n            if len(self._table.columns) == 0:\n                self._table.columns._initialize(len(value[0]))\n            self._table._data[key] = [BTRowData(self._table, row) for row in value]\n        else:\n            raise TypeError(\"key must be int, str or a slice object\")\n\n    def __contains__(self, key):\n        if isinstance(key, basestring):\n            return key in self.header\n        elif isinstance(key, Iterable):\n            return key in self._table._data\n        else:\n            raise TypeError(f\"'key' must be str or Iterable, not {type(key).__name__}\")\n\n    def __iter__(self):\n        return BTCollectionIterator(self)\n\n    def __repr__(self):\n        return repr(self._table._data)\n\n    def __str__(self):\n        return str(self._table._data)\n\n    def reverse(self):\n        \"\"\"Reverse the table row-wise *IN PLACE*.\"\"\"\n        self._table._data._reverse()\n\n    def pop(self, index=-1):\n        \"\"\"Remove and return row at index (default last).\n\n        Parameters\n        ----------\n        index : int, str\n            index or heading of the row. Normal list rules apply.\n        \"\"\"\n        if not isinstance(index, (int, basestring)):\n            raise TypeError(f\"row index must be int or str, not {type(index).__name__}\")\n        if len(self._table._data) == 0:\n            raise IndexError(\"pop from empty table\")\n        else:\n            res = self._table._data._pop(index)\n            self.header._pop(index)\n            return res\n\n    def insert(self, index, row, header=None):\n        \"\"\"Insert a row before index in the table.\n\n        Parameters\n        ----------\n        index : int\n            List index rules apply\n\n        row : iterable\n            Any iterable of appropriate length.\n\n        header : str, optional\n            Heading of the row\n\n        Raises\n        ------\n        TypeError:\n            If `row` is not an iterable.\n\n        ValueError:\n            If size of `row` is inconsistent with the current number\n            of columns.\n        \"\"\"\n        if self._table._ncol == 0:\n            row = list(row)\n            self._table.columns._reset_state(len(row))\n        self.header._insert(index, header)\n        self._table._data._insert(index, BTRowData(self._table, row))\n\n    def append(self, row, header=None):\n        \"\"\"Append a row to end of the table.\n\n        Parameters\n        ----------\n        row : iterable\n            Any iterable of appropriate length.\n\n        header : str, optional\n            Heading of the row\n\n        \"\"\"\n        self.insert(len(self), row, header)\n\n    def update(self, key, value):\n        \"\"\"Update row(s) identified with `key` in the table.\n\n        `key` can be a index or a slice object.\n\n        Parameters\n        ----------\n        key : int or slice\n            index of the row, or a slice object.\n\n        value : iterable\n            If an index is specified, `value` should be an iterable\n            of appropriate length. Instead if a slice object is\n            passed as key, value should be an iterable of rows.\n\n        Raises\n        ------\n        IndexError:\n            If index specified is out of range.\n\n        TypeError:\n            If `value` is of incorrect type.\n\n        ValueError:\n            If length of row does not matches number of columns.\n        \"\"\"\n        self[key] = value\n\n    def clear(self):\n        self._reset_state(0)\n\n    def sort(self, key, reverse=False):\n        \"\"\"Stable sort of the table *IN-PLACE* with respect to a column.\n\n        Parameters\n        ----------\n        key: int, str\n            index or header of the column. Normal list rules apply.\n        reverse : bool\n            If `True` then table is sorted as if each comparison was reversed.\n        \"\"\"\n        if isinstance(key, (int, basestring)):\n            key = operator.itemgetter(key)\n        elif callable(key):\n            pass\n        else:\n            raise TypeError(\"'key' must either be 'int' or 'str' or a 'callable'\")\n\n        indices = sorted(\n            range(len(self)),\n            key=lambda x: key(self._table._data[x]),\n            reverse=reverse,\n        )\n        self._table._data._sort(key=key, reverse=reverse)\n        self.header = [self.header[i] for i in indices]\n\n    def filter(self, key):\n        \"\"\"Return a copy of the table with only those rows which satisfy a\n        certain condition.\n\n        Returns\n        -------\n        BeautifulTable:\n            Filtered copy of the BeautifulTable instance.\n        \"\"\"\n        new_table = self._table.rows[:]\n        new_table.rows.clear()\n        for row in filter(key, self):\n            new_table.rows.append(row)\n        return new_table\n\n\nclass BTCollectionIterator(object):\n    def __init__(self, collection):\n        self._collection = collection\n        self._index = -1\n\n    def __iter__(self):\n        return self\n\n    def __next__(self):\n        self._index += 1\n        if self._index == len(self._collection):\n            raise StopIteration\n        return self._collection[self._index]\n\n\nclass BTColumnCollection(object):\n    def __init__(self, table, default_alignment, default_padding):\n        self._table = table\n        self._width_exceed_policy = enums.WEP_WRAP\n        self._pad_character = \" \"\n        self.default_alignment = default_alignment\n        self.default_padding = default_padding\n\n        self._reset_state(0)\n\n    @property\n    def _table(self):\n        return self._table_ref()\n\n    @_table.setter\n    def _table(self, value):\n        self._table_ref = weakref.ref(value)\n\n    @property\n    def padding(self):\n        \"\"\"Set width for left and rigth padding of the columns of the table.\"\"\"\n        raise AttributeError(\n            \"cannot read attribute 'padding'. use 'padding_{left|right}'\"\n        )\n\n    @padding.setter\n    def padding(self, value):\n        self.padding_left = value\n        self.padding_right = value\n\n    def _reset_state(self, ncol):\n        self._table._ncol = ncol\n        self._header = BTColumnHeader(self._table, [None] * ncol)\n        self._auto_width = True\n        self._alignment = AlignmentMetaData(\n            self._table, [self.default_alignment] * ncol\n        )\n        self._width = NonNegativeIntegerMetaData(self._table, [0] * ncol)\n        self._padding_left = NonNegativeIntegerMetaData(\n            self._table, [self.default_padding] * ncol\n        )\n        self._padding_right = NonNegativeIntegerMetaData(\n            self._table, [self.default_padding] * ncol\n        )\n        self._table._data = type(self._table._data)(\n            self._table,\n            [\n                BTRowData(self._table, [None] * ncol)\n                for i in range(len(self._table._data))\n            ],\n        )\n\n    def _canonical_key(self, key):\n        if isinstance(key, (int, slice)):\n            return key\n        elif isinstance(key, basestring):\n            return self.header.index(key)\n        raise TypeError(\n            f\"column indices must be int, str or slices, not {type(key).__name__}\"\n        )\n\n    @property\n    def header(self):\n        \"\"\"get/set headings for the columns of the table.\n\n        It can be any iterable with all members an instance of `str` or None.\n        \"\"\"\n        return self._header\n\n    @header.setter\n    def header(self, value):\n        self._header = BTColumnHeader(self._table, value)\n\n    @property\n    def alignment(self):\n        \"\"\"get/set alignment of the columns of the table.\n\n        It can be any iterable containing only the following:\n\n        * beautifultable.ALIGN_LEFT\n        * beautifultable.ALIGN_CENTER\n        * beautifultable.ALIGN_RIGHT\n        \"\"\"\n        return self._alignment\n\n    @alignment.setter\n    def alignment(self, value):\n        if isinstance(value, enums.Alignment):\n            value = [value] * len(self)\n        self._alignment = AlignmentMetaData(self._table, value)\n\n    @property\n    def width(self):\n        \"\"\"get/set width for the columns of the table.\n\n        Width of the column specifies the max number of characters\n        a column can contain. Larger characters are handled according to\n        `width_exceed_policy`. This can be one of `'auto'`, a non-negative\n        integer or an iterable of the same length as the number of columns.\n        If set to anything other than 'auto', the user is responsible for\n        updating it if new columns are added or existing ones are updated.\n        \"\"\"\n        return self._width\n\n    @width.setter\n    def width(self, value):\n        if isinstance(value, str):\n            if value == \"auto\":\n                self._auto_width = True\n                return\n            raise ValueError(f\"Invalid value '{value}'\")\n        if isinstance(value, int):\n            value = [value] * len(self)\n        self._width = NonNegativeIntegerMetaData(self._table, value)\n        self._auto_width = False\n\n    @property\n    def padding_left(self):\n        \"\"\"get/set width for left padding of the columns of the table.\n\n        Left Width of the padding specifies the number of characters\n        on the left of a column reserved for padding. By Default It is 1.\n        \"\"\"\n        return self._padding_left\n\n    @padding_left.setter\n    def padding_left(self, value):\n        if isinstance(value, int):\n            value = [value] * len(self)\n        self._padding_left = NonNegativeIntegerMetaData(self._table, value)\n\n    @property\n    def padding_right(self):\n        \"\"\"get/set width for right padding of the columns of the table.\n\n        Right Width of the padding specifies the number of characters\n        on the rigth of a column reserved for padding. By default It is 1.\n        \"\"\"\n        return self._padding_right\n\n    @padding_right.setter\n    def padding_right(self, value):\n        if isinstance(value, int):\n            value = [value] * len(self)\n        self._padding_right = NonNegativeIntegerMetaData(self._table, value)\n\n    @property\n    def width_exceed_policy(self):\n        \"\"\"Attribute to control how exceeding column width should be handled.\n\n        It can be one of the following:\n\n        ============================  =========================================\n         Option                        Meaning\n        ============================  =========================================\n         beautifultable.WEP_WRAP       An item is wrapped so every line fits\n                                       within it's column width.\n\n         beautifultable.WEP_STRIP      An item is stripped to fit in it's\n                                       column.\n\n         beautifultable.WEP_ELLIPSIS   An item is stripped to fit in it's\n                                       column and appended with ...(Ellipsis).\n        ============================  =========================================\n        \"\"\"\n        return self._width_exceed_policy\n\n    @width_exceed_policy.setter\n    def width_exceed_policy(self, value):\n        if not isinstance(value, enums.WidthExceedPolicy):\n            allowed = (\n                f\"{type(self).__name__}.{i.name}\" for i in enums.WidthExceedPolicy\n            )\n            error_msg = \"allowed values for width_exceed_policy are: \" + \", \".join(\n                allowed\n            )\n            raise ValueError(error_msg)\n        self._width_exceed_policy = value\n\n    @property\n    def default_alignment(self):\n        \"\"\"Attribute to control the alignment of newly created columns.\n\n        It can be one of the following:\n\n        ============================  =========================================\n         Option                        Meaning\n        ============================  =========================================\n         beautifultable.ALIGN_LEFT     New columns are left aligned.\n\n         beautifultable.ALIGN_CENTER   New columns are center aligned.\n\n         beautifultable.ALIGN_RIGHT    New columns are right aligned.\n        ============================  =========================================\n        \"\"\"\n        return self._default_alignment\n\n    @default_alignment.setter\n    def default_alignment(self, value):\n        if not isinstance(value, enums.Alignment):\n            allowed = (f\"{type(self).__name__}.{i.name}\" for i in enums.Alignment)\n            error_msg = \"allowed values for default_alignment are: \" + \", \".join(\n                allowed\n            )\n            raise ValueError(error_msg)\n        self._default_alignment = value\n\n    @property\n    def default_padding(self):\n        \"\"\"Initial value for Left and Right padding widths for new columns.\"\"\"\n        return self._default_padding\n\n    @default_padding.setter\n    def default_padding(self, value):\n        if not isinstance(value, int):\n            raise TypeError(\"default_padding must be an integer\")\n        elif value < 0:\n            raise ValueError(\"default_padding must be a non-negative integer\")\n        else:\n            self._default_padding = value\n\n    @property\n    def separator(self):\n        \"\"\"Character used to draw the line seperating two columns.\"\"\"\n        return self._table._column_separator\n\n    @separator.setter\n    def separator(self, value):\n        self._table._column_separator = ensure_type(value, basestring)\n\n    def __len__(self):\n        return self._table._ncol\n\n    def __getitem__(self, key):\n        \"\"\"Get a column, or a new table by slicing.\n\n        Parameters\n        ----------\n\n        key : int, slice, str\n            If key is an `int`, returns column at index `key`.\n            If key is an `str`, returns first column with heading `key`.\n            If key is a slice object, returns a new sliced table.\n\n        Raises\n        ------\n\n        TypeError\n            If key is not of type int, slice or str.\n        IndexError\n            If `int` key is out of range.\n        KeyError\n            If `str` key is not in header.\n        \"\"\"\n        if isinstance(key, int):\n            pass\n        elif isinstance(key, slice):\n            new_table = copy.deepcopy(self._table)\n\n            new_table.columns.clear()\n            new_table.columns.header = self.header[key]\n            new_table.columns.alignment = self.alignment[key]\n            new_table.columns.padding_left = self.padding_left[key]\n            new_table.columns.padding_right = self.padding_right[key]\n            new_table.columns.width = self.width[key]\n            new_table.columns._auto_width = self._auto_width\n            for i, r in enumerate(self._table._data):\n                new_table.rows[i] = r.value[key]\n            return new_table\n        elif isinstance(key, basestring):\n            key = self.header.index(key)\n        else:\n            raise TypeError(\n                f\"column indices must be integers, strings or slices, not {type(key).__name__}\"\n            )\n\n        return BTColumnData(self._table, [row[key] for row in self._table._data])\n\n    def __delitem__(self, key):\n        \"\"\"Delete a column, or multiple columns by slicing.\n\n        Parameters\n        ----------\n\n        key : int, slice, str\n            If key is an `int`, deletes column at index `key`.\n            If key is a slice object, deletes multiple columns.\n            If key is an `str`, deletes the first column with heading `key`\n\n        Raises\n        ------\n\n        TypeError\n            If key is not of type int, slice or str.\n        IndexError\n            If `int` key is out of range.\n        KeyError\n            If `str` key is not in header.\n        \"\"\"\n        if isinstance(key, (int, basestring, slice)):\n            key = self._canonical_key(key)\n\n            del self.alignment[key]\n            del self.width[key]\n            del self.padding_left[key]\n            del self.padding_right[key]\n            for row in self._table.rows:\n                del row[key]\n            del self.header[key]\n            if self.header.alignment is not None:\n                del self.header.alignment[key]\n            self._table._ncol = len(self.header)\n            if self._table._ncol == 0:\n                del self._table.rows[:]\n        else:\n            raise TypeError(\n                f\"table indices must be int, str or slices, not {type(key).__name__}\"\n            )\n\n    def __setitem__(self, key, value):\n        \"\"\"Update a column, or multiple columns by slicing.\n\n        Parameters\n        ----------\n\n        key : int, slice, str\n            If key is an `int`, updates column at index `key`.\n            If key is an `str`, updates first column with heading `key`.\n            If key is a slice object, updates multiple columns.\n\n        Raises\n        ------\n\n        TypeError\n            If key is not of type int, slice or str.\n        IndexError\n            If `int` key is out of range.\n        KeyError\n            If `str` key is not in header\n        \"\"\"\n        if not isinstance(key, (int, basestring, slice)):\n            raise TypeError(\"column indices must be of type int, str or a slice object\")\n        for row, new_item in zip(self._table.rows, value):\n            row[key] = new_item\n\n    def __contains__(self, key):\n        if isinstance(key, basestring):\n            return key in self.header\n        elif isinstance(key, Iterable):\n            key = list(key)\n            return any(key == column for column in self)\n        else:\n            raise TypeError(f\"'key' must be str or Iterable, not {type(key).__name__}\")\n\n    def __iter__(self):\n        return BTCollectionIterator(self)\n\n    def __repr__(self):\n        return repr(self._table)\n\n    def __str__(self):\n        return str(self._table._data)\n\n    def clear(self):\n        self._reset_state(0)\n\n    def pop(self, index=-1):\n        \"\"\"Remove and return column at index (default last).\n\n        Parameters\n        ----------\n        index : int, str\n            index of the column, or the header of the column.\n            If index is specified, then normal list rules apply.\n\n        Raises\n        ------\n        TypeError:\n            If index is not an instance of `int`, or `str`.\n\n        IndexError:\n            If Table is empty.\n        \"\"\"\n        if not isinstance(index, (int, basestring)):\n            raise TypeError(\n                f\"column index must be int or str, not {type(index).__name__}\"\n            )\n        if self._table._ncol == 0:\n            raise IndexError(\"pop from empty table\")\n        else:\n            res = []\n            index = self._canonical_key(index)\n            for row in self._table.rows:\n                res.append(row._pop(index))\n            res = BTColumnData(self._table, res)\n            self.alignment._pop(index)\n            self.width._pop(index)\n            self.padding_left._pop(index)\n            self.padding_right._pop(index)\n            self.header._pop(index)\n\n            self._table._ncol = len(self.header)\n            if self._table._ncol == 0:\n                del self._table.rows[:]\n            return res\n\n    def update(self, key, value):\n        \"\"\"Update a column named `header` in the table.\n\n        If length of column is smaller than number of rows, lets say\n        `k`, only the first `k` values in the column is updated.\n\n        Parameters\n        ----------\n        key : int, str\n            If `key` is int, column at index `key` is updated.\n            If `key` is str, the first column with heading `key` is updated.\n\n        value : iterable\n            Any iterable of appropriate length.\n\n        Raises\n        ------\n        TypeError:\n            If length of `column` is shorter than number of rows.\n\n        ValueError:\n            If no column exists with heading `header`.\n        \"\"\"\n        self[key] = value\n\n    def insert(\n        self,\n        index,\n        column,\n        header=None,\n        padding_left=None,\n        padding_right=None,\n        alignment=None,\n    ):\n        \"\"\"Insert a column before `index` in the table.\n\n        If length of column is bigger than number of rows, lets say\n        `k`, only the first `k` values of `column` is considered.\n        If column is shorter than 'k', ValueError is raised.\n\n        Note that Table remains in consistent state even if column\n        is too short. Any changes made by this method is rolled back\n        before raising the exception.\n\n        Parameters\n        ----------\n        index : int\n            List index rules apply.\n\n        column : iterable\n            Any iterable of appropriate length.\n\n        header : str, optional\n            Heading of the column.\n\n        padding_left : int, optional\n            Left padding of the column.\n\n        padding_right : int, optional\n            Right padding of the column.\n\n        alignment : Alignment, optional\n            alignment of the column.\n\n        Raises\n        ------\n        TypeError:\n            If `header` is not of type `str`.\n\n        ValueError:\n            If length of `column` is shorter than number of rows.\n        \"\"\"\n        padding_left = self.default_padding if padding_left is None else padding_left\n        padding_right = self.default_padding if padding_right is None else padding_right\n        alignment = self.default_alignment if alignment is None else alignment\n        if not isinstance(padding_left, int):\n            raise TypeError(\n                f\"'padding_left' should be of type 'int' not '{type(padding_left).__name__}'\"\n            )\n\n        if not isinstance(padding_right, int):\n            raise TypeError(\n                f\"'padding_right' should be of type 'int' not '{type(padding_right).__name__}'\"\n            )\n\n        if not isinstance(alignment, enums.Alignment):\n            raise TypeError(\n                f\"alignment should be of type '{enums.Alignment.__name__}' not '{type(alignment).__name__}'\"\n            )\n\n        if self._table._ncol == 0:\n            self.header = [header]\n            self.padding_left = [padding_left]\n            self.padding_right = [padding_right]\n            self.alignment = [alignment]\n            self._table._data = type(self._table._data)(\n                self._table, [BTRowData(self._table, [i]) for i in column]\n            )\n        else:\n            if (not isinstance(header, basestring)) and (header is not None):\n                raise TypeError(\n                    f\"header must be of type 'str' not '{type(header).__name__}'\"\n                )\n            column_length = 0\n            for row, new_item in zip(self._table.rows, column):\n                row._insert(index, new_item)\n                column_length += 1\n            if column_length == len(self._table.rows):\n                self._table._ncol += 1\n                self.header._insert(index, header)\n                self.width._insert(index, 0)\n                self.alignment._insert(index, alignment)\n                self.padding_left._insert(index, padding_left)\n                self.padding_right._insert(index, padding_right)\n                if self.header.alignment is not None:\n                    self.header.alignment._insert(index, alignment)\n            else:\n                # Roll back changes so that table remains in consistent state\n                for j in range(column_length, -1, -1):\n                    self._table.rows[j]._pop(index)\n                raise ValueError(\n                    f\"length of 'column' should be atleast {len(self._table.rows)}, got {column_length}\"\n                )\n\n    def append(\n        self,\n        column,\n        header=None,\n        padding_left=None,\n        padding_right=None,\n        alignment=None,\n    ):\n        \"\"\"Append a column to end of the table.\n\n        Parameters\n        ----------\n        column : iterable\n            Any iterable of appropriate length.\n\n        header : str, optional\n            Heading of the column\n\n        padding_left : int, optional\n            Left padding of the column\n\n        padding_right : int,  optional\n            Right padding of the column\n\n        alignment : Alignment, optional\n            alignment of the column\n        \"\"\"\n        self.insert(\n            self._table._ncol,\n            column,\n            header,\n            padding_left,\n            padding_right,\n            alignment,\n        )\n"
  },
  {
    "path": "beautifultable/meta.py",
    "content": "from .base import BTBaseRow\nfrom .enums import Alignment\n\n\nclass MetaData(BTBaseRow):\n    def __init__(self, table, row):\n        for i in row:\n            self.validate(i)\n        super(MetaData, self).__init__(table, row)\n\n    def __setitem__(self, key, value):\n        self.validate(value)\n        super(MetaData, self).__setitem__(key, value)\n\n    def validate(self, value):\n        pass\n\n\nclass AlignmentMetaData(MetaData):\n    def validate(self, value):\n        if not isinstance(value, Alignment):\n            allowed = (f\"{type(self).__name__}.{i.name}\" for i in Alignment)\n            error_msg = (\n                \"allowed values for alignment are: \"\n                + \", \".join(allowed)\n                + f\", was {value}\"\n            )\n\n            raise TypeError(error_msg)\n\n\nclass NonNegativeIntegerMetaData(MetaData):\n    def validate(self, value):\n        if isinstance(value, int) and value >= 0:\n            pass\n        else:\n            raise TypeError(\n                (\"Value must a non-negative integer, \" \"was {}\").format(value)\n            )\n"
  },
  {
    "path": "beautifultable/styles.py",
    "content": "# -*- coding: utf-8 -*-\nfrom __future__ import unicode_literals\n\n\nclass NoStyle:\n    left_border_char = \"\"\n    right_border_char = \"\"\n    top_border_char = \"\"\n    bottom_border_char = \"\"\n    header_separator_char = \"\"\n    column_separator_char = \"\"\n    row_separator_char = \"\"\n    intersect_top_left = \"\"\n    intersect_top_mid = \"\"\n    intersect_top_right = \"\"\n    intersect_header_left = \"\"\n    intersect_header_mid = \"\"\n    intersect_header_right = \"\"\n    intersect_row_left = \"\"\n    intersect_row_mid = \"\"\n    intersect_row_right = \"\"\n    intersect_bottom_left = \"\"\n    intersect_bottom_mid = \"\"\n    intersect_bottom_right = \"\"\n\n\nclass DefaultStyle(NoStyle):\n    left_border_char = \"|\"\n    right_border_char = \"|\"\n    top_border_char = \"-\"\n    bottom_border_char = \"-\"\n    header_separator_char = \"-\"\n    column_separator_char = \"|\"\n    row_separator_char = \"-\"\n    intersect_top_left = \"+\"\n    intersect_top_mid = \"+\"\n    intersect_top_right = \"+\"\n    intersect_header_left = \"+\"\n    intersect_header_mid = \"+\"\n    intersect_header_right = \"+\"\n    intersect_row_left = \"+\"\n    intersect_row_mid = \"+\"\n    intersect_row_right = \"+\"\n    intersect_bottom_left = \"+\"\n    intersect_bottom_mid = \"+\"\n    intersect_bottom_right = \"+\"\n\n\nclass MySQLStyle(DefaultStyle):\n    pass\n\n\nclass SeparatedStyle(DefaultStyle):\n    top_border_char = \"=\"\n    header_separator_char = \"=\"\n\n\nclass CompactStyle(NoStyle):\n    header_separator_char = \"-\"\n    column_separator_char = \" \"\n    intersect_top_left = \" \"\n    intersect_top_mid = \" \"\n    intersect_top_right = \" \"\n    intersect_header_left = \" \"\n    intersect_header_mid = \" \"\n    intersect_header_right = \" \"\n    intersect_row_left = \" \"\n    intersect_row_mid = \" \"\n    intersect_row_right = \" \"\n    intersect_bottom_left = \" \"\n    intersect_bottom_mid = \" \"\n    intersect_bottom_right = \" \"\n\n\nclass DottedStyle(NoStyle):\n    left_border_char = \":\"\n    right_border_char = \":\"\n    top_border_char = \".\"\n    bottom_border_char = \".\"\n    header_separator_char = \".\"\n    column_separator_char = \":\"\n\n\nclass MarkdownStyle(NoStyle):\n    left_border_char = \"|\"\n    right_border_char = \"|\"\n    header_separator_char = \"-\"\n    column_separator_char = \"|\"\n    intersect_header_left = \"|\"\n    intersect_header_mid = \"|\"\n    intersect_header_right = \"|\"\n\n\nclass RestructuredTextStyle(CompactStyle):\n    top_border_char = \"=\"\n    bottom_border_char = \"=\"\n    header_separator_char = \"=\"\n\n\nclass BoxStyle(NoStyle):\n    left_border_char = \"│\"\n    right_border_char = \"│\"\n    top_border_char = \"─\"\n    bottom_border_char = \"─\"\n    header_separator_char = \"─\"\n    column_separator_char = \"│\"\n    row_separator_char = \"─\"\n    intersect_top_left = \"┌\"\n    intersect_top_mid = \"┬\"\n    intersect_top_right = \"┐\"\n    intersect_header_left = \"├\"\n    intersect_header_mid = \"┼\"\n    intersect_header_right = \"┤\"\n    intersect_row_left = \"├\"\n    intersect_row_mid = \"┼\"\n    intersect_row_right = \"┤\"\n    intersect_bottom_left = \"└\"\n    intersect_bottom_mid = \"┴\"\n    intersect_bottom_right = \"┘\"\n\n\nclass DoubledBoxStyle(NoStyle):\n    left_border_char = \"║\"\n    right_border_char = \"║\"\n    top_border_char = \"═\"\n    bottom_border_char = \"═\"\n    header_separator_char = \"═\"\n    column_separator_char = \"║\"\n    row_separator_char = \"═\"\n    intersect_top_left = \"╔\"\n    intersect_top_mid = \"╦\"\n    intersect_top_right = \"╗\"\n    intersect_header_left = \"╠\"\n    intersect_header_mid = \"╬\"\n    intersect_header_right = \"╣\"\n    intersect_row_left = \"╠\"\n    intersect_row_mid = \"╬\"\n    intersect_row_right = \"╣\"\n    intersect_bottom_left = \"╚\"\n    intersect_bottom_mid = \"╩\"\n    intersect_bottom_right = \"╝\"\n\n\nclass RoundedStyle(BoxStyle):\n    intersect_top_left = \"╭\"\n    intersect_top_right = \"╮\"\n    intersect_bottom_left = \"╰\"\n    intersect_bottom_right = \"╯\"\n\n\nclass GridStyle(BoxStyle):\n    left_border_char = \"║\"\n    right_border_char = \"║\"\n    top_border_char = \"═\"\n    bottom_border_char = \"═\"\n    intersect_top_left = \"╔\"\n    intersect_top_mid = \"╤\"\n    intersect_top_right = \"╗\"\n    intersect_header_left = \"╟\"\n    intersect_header_right = \"╢\"\n    intersect_row_left = \"╟\"\n    intersect_row_right = \"╢\"\n    intersect_bottom_left = \"╚\"\n    intersect_bottom_mid = \"╧\"\n    intersect_bottom_right = \"╝\"\n"
  },
  {
    "path": "beautifultable/utils.py",
    "content": "\"\"\"Module containing some utility methods\"\"\"\n\nimport warnings\nimport functools\n\nfrom .ansi import ANSIMultiByteString\nfrom .compat import to_unicode\n\n\ndef to_numeric(item):\n    \"\"\"\n    Helper method to convert a string to float or int if possible.\n\n    If the conversion is not possible, it simply returns the string.\n    \"\"\"\n    num_types = (int, float)\n    # We don't wan't to perform any conversions if item is already a number\n    if isinstance(item, num_types):\n        return item\n\n    # First try for an int conversion so that strings like \"5\" are converted\n    # to 5 instead of 5.0 . This is safe as a direct int cast for a non integer\n    # string raises a ValueError.\n    try:\n        num = int(to_unicode(item))\n    except ValueError:\n        try:\n            num = float(to_unicode(item))\n        except ValueError:\n            return item\n        else:\n            return num\n    except TypeError:\n        return item\n    else:\n        return num\n\n\ndef ensure_type(value, *types, varname=\"value\"):\n    if not isinstance(value, types):\n        expected_types_str = \"/\".join([t.__name__ for t in types])\n        raise TypeError(\n            (\"Expected '{}' to be of type '{}', \" \"got '{}'\").format(\n                varname, expected_types_str, type(value).__name__\n            )\n        )\n    return value\n\n\ndef pre_process(item, detect_numerics, precision, sign_value):\n    \"\"\"Returns the final string which should be displayed\"\"\"\n    if item is None:\n        return \"\"\n    if detect_numerics:\n        item = to_numeric(item)\n    if isinstance(item, float):\n        item = round(item, precision)\n    try:\n        item = \"{:{sign}}\".format(item, sign=sign_value)\n    except (ValueError, TypeError):\n        pass\n    return to_unicode(item)\n\n\ndef termwidth(item):\n    \"\"\"Returns the visible width of the string as shown on the terminal\"\"\"\n    obj = ANSIMultiByteString(to_unicode(item))\n    return obj.termwidth()\n\n\ndef textwrap(item, width):\n    obj = ANSIMultiByteString(to_unicode(item))\n    return obj.wrap(width)\n\n\ndef deprecation_message(\n    old_name, deprecated_in, removed_in, extra_msg\n):  # pragma: no cover\n    return f\"'{old_name}' has been deprecated in 'v{deprecated_in}' and will be removed in 'v{removed_in}'. {extra_msg}\"\n\n\ndef deprecated(\n    deprecated_in,\n    removed_in,\n    replacement=None,\n    details=None,\n):  # pragma: no cover\n    def decorator(f):\n        @functools.wraps(f)\n        def wrapper(*args, **kwds):\n            nonlocal details\n            if not details:\n                if replacement:\n                    details = replacement.__qualname__\n                    details = details.replace(\n                        \"BTColumns\",\n                        \"BeautifulTable.columns\",\n                    )\n                    details = details.replace(\n                        \"BTRows\",\n                        \"BeautifulTable.rows\",\n                    )\n                    details = details.replace(\n                        \"BTColumnHeader\",\n                        \"BeautifulTable.columns.header\",\n                    )\n                    details = details.replace(\n                        \"BTRowHeader\",\n                        \"BeautifulTable.rows.header\",\n                    )\n                    details = f\"Use '{details}' instead.\"\n                else:\n                    details = \"\"\n            message = deprecation_message(\n                f.__qualname__,\n                deprecated_in,\n                removed_in,\n                details,\n            )\n            if replacement:\n                f.__doc__ = \"{}\\n\\n{}\".format(replacement.__doc__, message)\n            warnings.warn(message, FutureWarning)\n            return f(*args, **kwds)\n\n        return wrapper\n\n    return decorator\n\n\ndef deprecated_param(\n    deprecated_in,\n    removed_in,\n    old_name,\n    new_name=None,\n    details=None,\n):  # pragma: no cover\n    def decorator(f):\n        @functools.wraps(f)\n        def wrapper(*args, **kwargs):\n            nonlocal details\n            if not details:\n                details = f\"Use '{new_name}' instead.\" if new_name else \"\"\n            message = deprecation_message(\n                old_name,\n                deprecated_in,\n                removed_in,\n                details,\n            )\n            if old_name in kwargs:\n                warnings.warn(message, FutureWarning)\n            return f(*args, **kwargs)\n\n        return wrapper\n\n    return decorator\n"
  },
  {
    "path": "coverage.xml",
    "content": "<?xml version=\"1.0\" ?>\n<coverage branch-rate=\"0.7541\" branches-covered=\"368\" branches-valid=\"488\" complexity=\"0\" line-rate=\"0.883\" lines-covered=\"1177\" lines-valid=\"1333\" timestamp=\"1640513662355\" version=\"6.2\">\n\t<!-- Generated by coverage.py: https://coverage.readthedocs.io -->\n\t<!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->\n\t<sources>\n\t\t<source>D:\\Workspace\\beautifultable\\beautifultable</source>\n\t</sources>\n\t<packages>\n\t\t<package branch-rate=\"0.7541\" complexity=\"0\" line-rate=\"0.883\" name=\".\">\n\t\t\t<classes>\n\t\t\t\t<class branch-rate=\"1\" complexity=\"0\" filename=\"__init__.py\" line-rate=\"1\" name=\"__init__.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"3\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"5\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"14\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"15\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"18\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"39\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"40\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"1\" complexity=\"0\" filename=\"__version__.py\" line-rate=\"1\" name=\"__version__.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"3\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"4\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"5\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"7\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"8\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"0.6579\" complexity=\"0\" filename=\"ansi.py\" line-rate=\"0.7284\" name=\"ansi.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"3\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"8\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"9\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"13\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"16\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"18\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"19\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"21\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"22\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"23\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"24\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"25\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"27\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"29\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"30\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"35\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"37\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"38\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"39\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"41\" number=\"40\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"41\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"46\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"47\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"48\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"49\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"51\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"52\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"54\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"56,59\" number=\"55\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"57,58\" number=\"56\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"57\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"58\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"60,61\" number=\"59\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"60\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"61\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"67\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"68\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"69\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"71,80\" number=\"70\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"71\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"74,76\" number=\"73\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"74\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"76\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"77\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"78\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"79\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"81,82\" number=\"80\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"81\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"82\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"84\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"86\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"88\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"90\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"91\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"92\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"93\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"94\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"95\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"96\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"97\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"98\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"99\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"100\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"101\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"102\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"103\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"105\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"106\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"108\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"109\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"110\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"111\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"112\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"113\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"114\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"115\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"116\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"0.8\" complexity=\"0\" filename=\"base.py\" line-rate=\"0.8659\" name=\"base.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"5\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"7\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"8\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"10\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"12\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"14\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"16\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"18\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"20\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"22\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"23\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"25\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"26\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"28\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"29\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"32\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,34\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"34\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"36\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"38\" number=\"37\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"38\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"39\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"40\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"41\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"42\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"44\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"46\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"48\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"49\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"51\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"52\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"54\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"55\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"57\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"58\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"60\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"61\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"63\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"64\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"66\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"67\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"69\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"70\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"72\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"74\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"75\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"76\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"77\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"79\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"81\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"83\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"85\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"87\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"88\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"90\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"92\" number=\"91\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"92\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"97\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"99\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"103\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"108\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"109\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"110\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"112\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"113\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"115\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"116\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"117\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"118\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"121\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"122\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"123\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"125\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"126\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"128\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"129\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"130\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"131\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"0.75\" complexity=\"0\" filename=\"beautifultable.py\" line-rate=\"0.8944\" name=\"beautifultable.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"28\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"30\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"34\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"36\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"44\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"45\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"46\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"54\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"64\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"116\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"133\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"134\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"135\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"136\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"138\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"139\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"140\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"141\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"143\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"144\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"146\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"147\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"148\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"149\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"152\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"153\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"156\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"157\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (3/3)\" hits=\"1\" number=\"160\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"179\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"182\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"183\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"184\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"185\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"186\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"187\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"189\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"190\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"192\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"196\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"240\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"241\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"242\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"243\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"244\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"245\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"258\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"260\" number=\"259\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"260\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"262\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"264\" number=\"263\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"264\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"266\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"268\" number=\"267\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"268\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"270\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"271\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"272\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"273\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"275\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"276\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"278\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"279\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"281\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"282\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"284\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"285\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"286\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"287\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"288\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"289\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"291\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"292\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,295\" number=\"293\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"295\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"296\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"298\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"299\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"300\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"301\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"302\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"303\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"305\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"307,309\" number=\"306\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"307\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"309\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"311\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"312\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"313\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"317\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"318\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"320\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"321\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"322\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"323\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"324\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"325\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"327\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"328\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"329\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"331\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"333\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"334\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"356\" number=\"355\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"356\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"360\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"361\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"363\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"372\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"380\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"396\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"397\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"399\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"400\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"401\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"403\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"404\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"405\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"407\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"410\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"413\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"415\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"433\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"435\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"438\" number=\"437\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,441\" number=\"438\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"441\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"442\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"443\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"445\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"453\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"455\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"457\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"474\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"477\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"479\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"481\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"483\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"484\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"488\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"489\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"493\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"494\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"498\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"499\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"503\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"504\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"508\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"509\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"513\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"521\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"522\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"523\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"524\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"525\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"527\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"529\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"531\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"532\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"536\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"537\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"541\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"542\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"551\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"552\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"556\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"557\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"561\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"562\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"566\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"567\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"571\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"572\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"576\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"577\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"581\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"582\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"586\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"587\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"591\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"592\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"596\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"597\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"601\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"602\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"606\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"607\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"611\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"612\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"616\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"617\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"621\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"622\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"626\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"627\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"631\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"642\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"654\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"668\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"677\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"686\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"695\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"699\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"703\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"707\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"711\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"715\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"719\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"723\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"727\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"731\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"735\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"739\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"762\" number=\"761\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,763\" number=\"762\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"763\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"764\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"765\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"766\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"767\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"768\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"769\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"771\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"772\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"773\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"774\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"776\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"777\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"779\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"780\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"781\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"783\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"784\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"785\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"786\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"787\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"788\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"790\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"792\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"793\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"794\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"795\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"796\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"797\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"799\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"800\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"801\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"804\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"810\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"811\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"813\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"814\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"815\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"816\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"819\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"825\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"826\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"828\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"829\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"832\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"833\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"834\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"835\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"836\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"837\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"840\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"842\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"843\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"844\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"848\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"849\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"850\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"851\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"852\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"853\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"854\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"857\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"858\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"859\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"861\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"862\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"863\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"864\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"865\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"866\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"867\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"868\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"870\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"871\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"873\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"878\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"880\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"882\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"903\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"923\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"928\" number=\"925\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"926\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"928\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"929\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"930\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"931\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"934\" number=\"933\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"934\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"980\" number=\"938\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"940\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"949\" number=\"941\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"949\" number=\"942\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"943\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"947\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"948\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"949\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"959\" number=\"951\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"959\" number=\"952\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"953\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"957\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"958\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"959\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"980\" number=\"961\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"980\" number=\"962\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"963\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"964\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"966\" number=\"965\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"967,968\" number=\"966\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"967\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"968\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"969\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"973\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"975\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"978\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"980\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"982\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"983\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"992\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"993\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1002\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1003\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1012\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1013\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1022\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1033\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1034\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1035\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1036\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1037\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1038\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1039\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1041\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1045\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1046\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1050\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1061\" number=\"1055\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1057\" number=\"1056\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1057\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1061\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1062\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1064\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1065\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1072\" number=\"1067\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1070\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1072\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1078\" number=\"1074\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1075\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1078\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1079\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1080\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1087\" number=\"1083\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1084\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1087\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1088\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1089\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1090\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1091\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1092\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1093\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1114\" number=\"1095\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1097\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1098\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1099\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1100\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1101\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1103\" number=\"1102\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1103\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1105\" number=\"1104\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1105\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1107\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1108\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1111\" number=\"1109\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1110\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1111\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1120\" number=\"1114\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1115\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1116\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1117\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1120\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1121\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1123\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1124\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"33% (1/3)\" hits=\"1\" missing-branches=\"exit,1129\" number=\"1126\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"33% (1/3)\" hits=\"1\" missing-branches=\"exit,1128\" number=\"1127\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,1129\" number=\"1128\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1129\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1131\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1152\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1153\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1155\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1157\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1159\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1168\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1169\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1175\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1176\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"66% (2/3)\" hits=\"1\" missing-branches=\"1181\" number=\"1177\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1180\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1181\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1183\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1201\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1202\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1208\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1209\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1211\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1212\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1213\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1214\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1215\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"1\" complexity=\"0\" filename=\"compat.py\" line-rate=\"1\" name=\"compat.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"4\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"5\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"1\" complexity=\"0\" filename=\"enums.py\" line-rate=\"0.9298\" name=\"enums.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"4\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"20\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"21\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"22\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"23\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"25\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"26\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"29\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"30\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"34\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"35\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"38\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"39\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"40\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"41\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"43\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"44\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"47\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"48\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"49\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"50\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"51\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"52\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"53\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"54\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"55\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"56\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"57\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"58\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"59\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"61\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"62\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"65\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"66\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"67\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"68\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"69\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"70\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"71\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"72\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"73\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"74\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"75\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"76\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"77\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"78\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"79\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"80\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"81\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"82\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"83\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"84\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"85\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"0.7424\" complexity=\"0\" filename=\"helpers.py\" line-rate=\"0.8618\" name=\"helpers.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"3\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"5\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"7\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"8\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"9\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"12\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"13\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"14\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"15\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"16\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"18\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"19\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"20\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"22\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"24\" number=\"23\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"24\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"29\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"30\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"34\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"36\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"46\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"48\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"53\" number=\"50\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"51\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"52\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"54,55\" number=\"53\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"54\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"55\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"57\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"60\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"62\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"64\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"66\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"69\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"71\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"73\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"75\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"76\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"77\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"79\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"81\" number=\"80\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"81\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"86\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"87\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"88\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"93\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"107\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"108\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"109\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"111\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"113\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"119\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"120\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"121\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"122\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"123\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"124\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"129\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"130\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"148\" number=\"131\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"134\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"136\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"137\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"138\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"140\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"141\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"142\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"143\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"144\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"145\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"146\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"148\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"150\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"172\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"173\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"175\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"176\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"178\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"179\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"183\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"184\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"186\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"195\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"197\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"198\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"199\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"204\" number=\"201\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"202\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"207\" number=\"204\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"205\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"207\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"209\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"210\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"213\" number=\"211\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"213\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"214\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"215\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"223\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"225\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"233\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"234\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"235\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"241\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"242\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"246\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"247\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"248\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"249\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"250\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"251\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"252\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"254\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"255\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"256\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"257\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"258\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"259\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"260\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"265\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"266\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"267\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"270\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"275\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"276\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"278\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"279\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"281\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"283\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"285\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"290\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"291\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"293\" number=\"292\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"293\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"294\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"295\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"298\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"299\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"301\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"303\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"310\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"311\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"312\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"313\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"315\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"317\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"319\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"321\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"323\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"324\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"328\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"330\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"332\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"334\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"336\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"338\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"341\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"343\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"345\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"347\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"348\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"349\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"352\" number=\"350\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"351\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"352\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"358\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"359\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"361\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"380\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"381\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"382\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"383\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"384\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"385\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"386\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"389\" number=\"387\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"388\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"389\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"395\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"418\" number=\"414\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"415\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"416\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"418\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"424\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"443\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"444\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"451\" number=\"445\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"446\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"448\" number=\"447\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"448\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"449\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"451\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"453\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"455\" number=\"454\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"455\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"459\" number=\"456\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"457\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"459\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"463\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"464\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"466\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"467\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"469\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"470\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"472\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"474\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"476\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"485\" number=\"484\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"485\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"489\" number=\"488\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"489\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"491\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"492\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"493\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"495\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"518\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"519\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"520\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"521\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"522\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"524\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"536\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"538\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"564\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"566\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"567\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"569\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"579\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"580\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"581\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"584\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"586\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"591\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"592\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"594\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"603\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"604\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"605\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"606\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"607\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"610\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"611\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"612\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"613\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"615\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"616\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"618\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"619\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"620\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"621\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"622\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"625\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"626\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"627\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"628\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"629\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"630\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"631\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"633\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"635\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"637\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"639\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"641\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"643\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"646\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"650\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"652\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"653\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"655\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"656\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"657\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"658\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"659\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"662\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"663\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"666\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"669\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"677\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"678\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"679\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"682\" number=\"680\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"681\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"682\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"688\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"694\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"696\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"698\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"700\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"710\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"712\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"714\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"715\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"716\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"718\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"729\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"731\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"734\" number=\"733\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"735,737\" number=\"734\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"735\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"736\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"737\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"739\" number=\"738\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"739\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"740\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"741\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"743\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"750\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"752\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"755\" number=\"754\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"755\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"756\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"758\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"765\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"767\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"770\" number=\"769\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"770\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"771\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"773\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"792\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"794\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"797\" number=\"796\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,801\" number=\"797\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"801\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"804\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"805\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"807\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"823\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"825\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"828\" number=\"827\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,831\" number=\"828\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"831\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"834\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"835\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"837\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"840\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"842\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"845\" number=\"844\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"845\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"847\" number=\"846\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"847\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"849\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"851\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"854\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"856\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"858\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"860\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"861\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"863\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"884\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"886\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"887\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"889\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"890\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"891\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"892\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"893\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"894\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"895\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"896\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"897\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"898\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"902\" number=\"899\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"900\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"902\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"907\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"909\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"946\" number=\"930\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"931\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"933\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"934\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"935\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"936\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"937\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"938\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"939\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"941\" number=\"940\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"941\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"942\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"944\" number=\"943\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"944\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"946\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"952\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"974\" number=\"973\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"974\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"975\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"976\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"978\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"980\" number=\"979\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"980\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"985\" number=\"981\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"982\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"983\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"985\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"989\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"990\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"992\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"993\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"995\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"996\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"998\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"999\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1001\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1019\" number=\"1018\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1019\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1025\" number=\"1024\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1025\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1027\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1028\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1029\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1030\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1031\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1032\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1033\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1034\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1035\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1036\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1038\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1039\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1040\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1041\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1043\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1066\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1068\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1115\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1116\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1117\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1119\" number=\"1118\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1119\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1125\" number=\"1124\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1125\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1131\" number=\"1130\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1131\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1137\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1138\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1139\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1140\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1141\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1142\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1147\" number=\"1146\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1147\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1152\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"1153\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1154\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1155\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1167\" number=\"1156\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1157\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1158\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1159\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1160\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1161\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1162\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"1164\" number=\"1163\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1164\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"1168,1169\" number=\"1167\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1168\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"1169\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1175\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1202\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"0.75\" complexity=\"0\" filename=\"meta.py\" line-rate=\"0.8095\" name=\"meta.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"1\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"5\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"7\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"8\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"9\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"11\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"12\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"13\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"15\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"19\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"20\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"22\" number=\"21\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,23\" number=\"22\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"23\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"28\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"36\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"1\" complexity=\"0\" filename=\"styles.py\" line-rate=\"1\" name=\"styles.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"2\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"5\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"7\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"8\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"9\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"10\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"11\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"12\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"13\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"14\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"15\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"16\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"17\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"18\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"19\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"20\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"21\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"22\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"23\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"24\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"27\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"28\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"29\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"30\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"31\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"34\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"35\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"36\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"37\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"38\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"39\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"40\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"41\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"42\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"43\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"44\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"45\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"46\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"49\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"53\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"54\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"55\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"58\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"59\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"60\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"61\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"62\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"63\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"64\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"65\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"66\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"67\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"68\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"69\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"70\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"71\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"72\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"75\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"76\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"77\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"78\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"79\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"80\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"81\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"84\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"85\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"86\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"87\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"88\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"89\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"90\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"91\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"94\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"95\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"96\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"97\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"100\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"101\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"102\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"103\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"104\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"105\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"106\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"107\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"108\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"109\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"110\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"111\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"112\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"113\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"114\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"115\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"116\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"117\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"118\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"119\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"122\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"123\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"124\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"125\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"126\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"127\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"128\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"129\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"130\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"131\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"132\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"133\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"134\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"135\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"136\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"137\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"138\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"139\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"140\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"141\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"144\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"145\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"146\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"147\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"148\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"151\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"152\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"153\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"154\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"155\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"156\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"157\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"158\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"159\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"160\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"161\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"162\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"163\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"164\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"165\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t\t<class branch-rate=\"0.5714\" complexity=\"0\" filename=\"utils.py\" line-rate=\"0.8537\" name=\"utils.py\">\n\t\t\t\t\t<methods/>\n\t\t\t\t\t<lines>\n\t\t\t\t\t\t<line hits=\"1\" number=\"3\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"4\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"6\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"7\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"10\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"16\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"18\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"19\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"24\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"25\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"33\" number=\"26\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"27\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"28\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"29\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"30\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"32\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"33\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"34\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"36\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"39\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"41\" number=\"40\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"0% (0/2)\" hits=\"0\" missing-branches=\"exit,42\" number=\"41\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"42\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"47\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"50\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"100% (2/2)\" hits=\"1\" number=\"52\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"53\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"56\" number=\"54\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"55\"/>\n\t\t\t\t\t\t<line branch=\"true\" condition-coverage=\"50% (1/2)\" hits=\"1\" missing-branches=\"57\" number=\"56\"/>\n\t\t\t\t\t\t<line hits=\"0\" number=\"57\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"58\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"59\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"60\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"62\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"65\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"67\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"68\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"71\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"72\"/>\n\t\t\t\t\t\t<line hits=\"1\" number=\"73\"/>\n\t\t\t\t\t</lines>\n\t\t\t\t</class>\n\t\t\t</classes>\n\t\t</package>\n\t</packages>\n</coverage>\n"
  },
  {
    "path": "docs/Makefile",
    "content": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS    =\nSPHINXBUILD   = sphinx-build\nSPHINXPROJ    = BeautifulTable\nSOURCEDIR     = .\nBUILDDIR      = _build\n\n# Put it first so that \"make\" without argument is like \"make help\".\nhelp:\n\t@$(SPHINXBUILD) -M help \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)\n\n.PHONY: help Makefile\n\n# Catch-all target: route all unknown targets to Sphinx using the new\n# \"make mode\" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).\n%: Makefile\n\t@$(SPHINXBUILD) -M $@ \"$(SOURCEDIR)\" \"$(BUILDDIR)\" $(SPHINXOPTS) $(O)"
  },
  {
    "path": "docs/badges.rst",
    "content": ".. include:: ../README.rst\n   :start-after: inclusion-marker-badges-start\n   :end-before: inclusion-marker-badges-end"
  },
  {
    "path": "docs/changelog.rst",
    "content": ".. include:: ../README.rst\n   :start-after: inclusion-marker-changelog-start\n   :end-before: inclusion-marker-changelog-end\n"
  },
  {
    "path": "docs/conf.py",
    "content": "#!/usr/bin/env python3\n# -*- coding: utf-8 -*-\n#\n# BeautifulTable documentation build configuration file, created by\n# sphinx-quickstart on Sun Dec 18 15:59:32 2016.\n#\n# This file is execfile()d with the current directory set to its\n# containing dir.\n#\n# Note that not all possible configuration values are present in this\n# autogenerated file.\n#\n# All configuration values have a default; values that are commented out\n# serve to show the default.\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\n#\nimport os\nimport sys\n\nsys.path.insert(0, os.path.abspath(\"../\"))\n\nimport beautifultable  # noqa E402\n\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n#\n# needs_sphinx = '1.0'\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\nextensions = [\n    \"sphinx.ext.autodoc\",\n    \"sphinx.ext.intersphinx\",\n    \"sphinx.ext.todo\",\n    \"sphinx.ext.coverage\",\n    \"sphinx.ext.ifconfig\",\n    \"sphinx.ext.viewcode\",\n    \"sphinx.ext.napoleon\",\n]\n\nnapoleon_google_docstring = False\nnapoleon_include_special_with_doc = False\n# napoleon_use_param = False\n# napoleon_use_ivar = True\n\nautodoc_member_order = \"bysource\"\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The suffix(es) of source filenames.\n# You can specify multiple suffix as a list of string:\n#\n# source_suffix = ['.rst', '.md']\nsource_suffix = \".rst\"\n\n# The master toctree document.\nmaster_doc = \"index\"\n\n# General information about the project.\nproject = \"BeautifulTable\"\ncopyright = \"2022, Priyam Singh\"\nauthor = beautifultable.__author__\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The short X.Y version.\nversion = beautifultable.__version__\n# The full version, including alpha/beta/rc tags.\nrelease = beautifultable.__version__\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n#\n# This is also used if you do content translation via gettext catalogs.\n# Usually you set \"language\" from the command line for these cases.\nlanguage = None\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\n# This patterns also effect to html_static_path and html_extra_path\nexclude_patterns = [\"_build\", \"Thumbs.db\", \".DS_Store\"]\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = \"sphinx\"\n\n# If true, `todo` and `todoList` produce output, else they produce nothing.\ntodo_include_todos = True\n\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\n#\nhtml_theme = \"default\"\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\n#\n# html_theme_options = {}\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\n\n\n# -- Options for HTMLHelp output ------------------------------------------\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = \"BeautifulTabledoc\"\n\n\n# -- Options for LaTeX output ---------------------------------------------\n\nlatex_elements = {\n    # The paper size ('letterpaper' or 'a4paper').\n    #\n    # 'papersize': 'letterpaper',\n    # The font size ('10pt', '11pt' or '12pt').\n    #\n    # 'pointsize': '10pt',\n    # Additional stuff for the LaTeX preamble.\n    #\n    # 'preamble': '',\n    # Latex figure (float) alignment\n    #\n    # 'figure_align': 'htbp',\n}\n\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\nlatex_documents = [\n    (\n        master_doc,\n        \"BeautifulTable.tex\",\n        \"BeautifulTable Documentation\",\n        \"Priyam Singh\",\n        \"manual\",\n    ),\n]\n\n\n# -- Options for manual page output ---------------------------------------\n\n# One entry per manual page. List of tuples\n# (source start file, name, description, authors, manual section).\nman_pages = [\n    (master_doc, \"beautifultable\", \"BeautifulTable Documentation\", [author], 1)\n]\n\n\n# -- Options for Texinfo output -------------------------------------------\n\n# Grouping the document tree into Texinfo files. List of tuples\n# (source start file, target name, title, author,\n#  dir menu entry, description, category)\ntexinfo_documents = [\n    (\n        master_doc,\n        \"BeautifulTable\",\n        \"BeautifulTable Documentation\",\n        author,\n        \"BeautifulTable\",\n        \"One line description of project.\",\n        \"Miscellaneous\",\n    ),\n]\n\n\n# Example configuration for intersphinx: refer to the Python standard library.\nintersphinx_mapping = {\"https://docs.python.org/\": None}\n"
  },
  {
    "path": "docs/donation.rst",
    "content": ".. include:: ../README.rst\n   :start-after: inclusion-marker-donation-start\n   :end-before: inclusion-marker-donation-end"
  },
  {
    "path": "docs/index.rst",
    "content": ".. BeautifulTable documentation master file, created by\n   sphinx-quickstart on Sun Dec 18 15:59:32 2016.\n   You can adapt this file completely to your liking, but it should at least\n   contain the root `toctree` directive.\n\n##########################################\nWelcome to beautifultable's documentation!\n##########################################\n\n.. include:: badges.rst\n\n.. include:: introduction.rst\n   \n.. include:: links.rst\n\n\n******************************************\nContents\n******************************************\n\n.. toctree::\n   :maxdepth: 3\n   \n   install\n   quickstart\n   changelog\n\n\n.. include:: donation.rst\n"
  },
  {
    "path": "docs/install.rst",
    "content": ".. include:: ../README.rst\n   :start-after: inclusion-marker-install-start\n   :end-before: inclusion-marker-install-end"
  },
  {
    "path": "docs/introduction.rst",
    "content": ".. include:: ../README.rst\n   :start-after: inclusion-marker-introduction-start\n   :end-before: inclusion-marker-introduction-end"
  },
  {
    "path": "docs/links.rst",
    "content": ".. include:: ../README.rst\n   :start-after: inclusion-marker-links-start\n   :end-before: inclusion-marker-links-end"
  },
  {
    "path": "docs/make.bat",
    "content": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=sphinx-build\n)\nset SOURCEDIR=.\nset BUILDDIR=_build\nset SPHINXPROJ=PrinterTools\n\nif \"%1\" == \"\" goto help\n\n%SPHINXBUILD% >NUL 2>NUL\nif errorlevel 9009 (\n\techo.\n\techo.The 'sphinx-build' command was not found. Make sure you have Sphinx\n\techo.installed, then set the SPHINXBUILD environment variable to point\n\techo.to the full path of the 'sphinx-build' executable. Alternatively you\n\techo.may add the Sphinx directory to PATH.\n\techo.\n\techo.If you don't have Sphinx installed, grab it from\n\techo.http://sphinx-doc.org/\n\texit /b 1\n)\n\n%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%\ngoto end\n\n:help\n%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%\n\n:end\npopd\n"
  },
  {
    "path": "docs/quickstart.rst",
    "content": "*************************************************************************\nQuickstart\n*************************************************************************\n\n=========================================================================\nBuilding the Table\n=========================================================================\n\nBuilding a table is very easy. :class:`.BeautifulTable` provides two views\n``rows`` and ``columns``. You can use them to modify their respective properties.\n\nLet's create our first table and add some rows.\n\n.. code:: python\n\n   >>> from beautifultable import BeautifulTable\n   >>> table = BeautifulTable()\n   >>> table.rows.append([\"Jacob\", 1, \"boy\"])\n   >>> table.rows.append([\"Isabella\", 1, \"girl\"])\n   >>> table.rows.append([\"Ethan\", 2, \"boy\"])\n   >>> table.rows.append([\"Sophia\", 2, \"girl\"])\n   >>> table.rows.append([\"Michael\", 3, \"boy\"])\n   >>> table.columns.header = [\"name\", \"rank\", \"gender\"]\n   >>> table.rows.header = [\"S1\", \"S2\", \"S3\", \"S4\", \"S5\"]\n   >>> print(table)\n   +----+----------+------+--------+\n   |    |   name   | rank | gender |\n   +----+----------+------+--------+\n   | S1 |  Jacob   |  1   |  boy   |\n   +----+----------+------+--------+\n   | S2 | Isabella |  1   |  girl  |\n   +----+----------+------+--------+\n   | S3 |  Ethan   |  2   |  boy   |\n   +----+----------+------+--------+\n   | S4 |  Sophia  |  2   |  girl  |\n   +----+----------+------+--------+\n   | S5 | Michael  |  3   |  boy   |\n   +----+----------+------+--------+\n\nBeautifulTable initializes the shape lazily. Here when you appended the first row,\nthe number of columns was set to 3. Further rows had to be of length 3. If you had\nset the columns and/or row headers beforehand as follows, the table shape would already be\nset to (5, 3). Hence you would just set the rows directly using their indices or keys.\n\n.. code:: python\n\n   >>> from beautifultable import BeautifulTable\n   >>> table = BeautifulTable()\n   >>> table.columns.header = [\"name\", \"rank\", \"gender\"]\n   >>> table.rows.header = [\"S1\", \"S2\", \"S3\", \"S4\", \"S5\"]\n   >>> table.rows[0] = [\"Jacob\", 1, \"boy\"]\n   >>> table.rows[1] = [\"Isabella\", 1, \"girl\"]\n   >>> table.rows[2] = [\"Ethan\", 2, \"boy\"]\n   >>> table.rows[3] = [\"Sophia\", 2, \"girl\"]\n   >>> table.rows[4]  =[\"Michael\", 3, \"boy\"]\n   >>> print(table)\n   +----+----------+------+--------+\n   |    |   name   | rank | gender |\n   +----+----------+------+--------+\n   | S1 |  Jacob   |  1   |  boy   |\n   +----+----------+------+--------+\n   | S2 | Isabella |  1   |  girl  |\n   +----+----------+------+--------+\n   | S3 |  Ethan   |  2   |  boy   |\n   +----+----------+------+--------+\n   | S4 |  Sophia  |  2   |  girl  |\n   +----+----------+------+--------+\n   | S5 | Michael  |  3   |  boy   |\n   +----+----------+------+--------+\n\n\nSo, We created our first table. Let's add a new column.\n\n.. code:: python\n\n   >>> table.columns.append([\"2010\", \"2012\", \"2008\", \"2010\", \"2011\"], header=\"year\")\n   >>> print(table)\n   +----+----------+------+--------+------+\n   |    |   name   | rank | gender | year |\n   +----+----------+------+--------+------+\n   | S1 |  Jacob   |  1   |  boy   | 2010 |\n   +----+----------+------+--------+------+\n   | S2 | Isabella |  1   |  girl  | 2012 |\n   +----+----------+------+--------+------+\n   | S3 |  Ethan   |  2   |  boy   | 2008 |\n   +----+----------+------+--------+------+\n   | S4 |  Sophia  |  2   |  girl  | 2010 |\n   +----+----------+------+--------+------+\n   | S5 | Michael  |  3   |  boy   | 2011 |\n   +----+----------+------+--------+------+\n\nYou can also build a :class:`.BeautifulTable` using slicing. Slicing creates a\nnew table with it's own copy of data. But it retains the properties\nof the original object. You can slice both rows or columns.\n\n.. code:: python\n\n   >>> new_table = table.rows[:3]\n   >>> print(new_table)\n   +----+----------+------+--------+------+\n   |    |   name   | rank | gender | year |\n   +----+----------+------+--------+------+\n   | S1 |  Jacob   |  1   |  boy   | 2010 |\n   +----+----------+------+--------+------+\n   | S2 | Isabella |  1   |  girl  | 2012 |\n   +----+----------+------+--------+------+\n   | S3 |  Ethan   |  2   |  boy   | 2008 |\n   +----+----------+------+--------+------+\n\n\n.. code:: python\n\n   >>> new_table = table.columns[:3]\n   >>> print(new_table)\n   +----+----------+------+--------+\n   |    |   name   | rank | gender |\n   +----+----------+------+--------+\n   | S1 |  Jacob   |  1   |  boy   |\n   +----+----------+------+--------+\n   | S2 | Isabella |  1   |  girl  |\n   +----+----------+------+--------+\n   | S3 |  Ethan   |  2   |  boy   |\n   +----+----------+------+--------+\n   | S4 |  Sophia  |  2   |  girl  |\n   +----+----------+------+--------+\n   | S5 | Michael  |  3   |  boy   |\n   +----+----------+------+--------+\n\nAs you can see how easy it is to create a Table with **beautifultable**.\nNow lets move on to see some common use cases. For details, please refer the API Documentation.\n\n\n=========================================================================\nAccessing Rows\n=========================================================================\n\nYou can access a row using it's index or it's header. It returns a **BTRowData** object.\n\n.. code:: python\n\n   >>> print(list(table.rows[3]))\n   ['Sophia', 2, 'girl', '2010']\n\nTo access a particular field of a row, you can again use the index, or the header\nof the required column.\n\n.. code:: python\n\n   >>> print(table.rows[3][2])\n   girl\n   >>> print(table.rows[3]['gender'])\n   girl\n\n\n=========================================================================\nAccessing Columns\n=========================================================================\n\nYou can access a column using it's index or it's header. It returns a **BTColumnData** object.\n\n.. code:: python\n\n   >>> print(list(table.columns['name']))\n   ['Jacob', 'Isabella', 'Ethan', 'Sophia', 'Michael']\n\nTo access a particular field of a column, you can again use the index, or the header\nof the required row.\n\n.. code:: python\n\n   >>> print(table.columns[2][3])\n   girl\n   >>> print(table.columns[2]['S4'])\n   girl\n\n=========================================================================\nCounting Rows and Columns\n=========================================================================\n\nYou can get the number of columns or rows in the table by using the\n``len`` function. You can also use the :attr:`.BeautifulTable.shape`\nattribute.\n\n.. code:: python\n\n   >>> print(len(table.columns))\n   3\n   >>> print(len(table.rows))\n   5\n   >>> print(table.shape)\n   (5,3)\n\n=========================================================================\nInserting Rows and Columns\n=========================================================================\n\nBeautifulTable provides 2 methods, :meth:`.BTRowCollection.insert` and\n:meth:`.BTColumnCollection.insert` for this purpose.\n\n.. code:: python\n\n   >>> table.rows.insert(3, ['Gary', 2, 'boy', 2009], header='S6')\n   >>> table.columns.insert(2, [78, 67, 82, 56, 86, 74], header='marks')\n   >>> print(table)\n   +----+----------+------+-------+--------+------+\n   |    |   name   | rank | marks | gender | year |\n   +----+----------+------+-------+--------+------+\n   | S1 |  Jacob   |  1   |  78   |  boy   | 2010 |\n   +----+----------+------+-------+--------+------+\n   | S2 | Isabella |  1   |  67   |  girl  | 2012 |\n   +----+----------+------+-------+--------+------+\n   | S3 |  Ethan   |  2   |  82   |  boy   | 2008 |\n   +----+----------+------+-------+--------+------+\n   | S6 |   Gary   |  2   |  56   |  boy   | 2009 |\n   +----+----------+------+-------+--------+------+\n   | S4 |  Sophia  |  2   |  86   |  girl  | 2010 |\n   +----+----------+------+-------+--------+------+\n   | S5 | Michael  |  3   |  74   |  boy   | 2011 |\n   +----+----------+------+-------+--------+------+\n\n\n=========================================================================\nRemoving Rows and Columns\n=========================================================================\n\nRemoving a row or column is very easy. Just delete it using ``del``\nstatement.\n\n.. code:: python\n\n   >>> del table.rows[3]\n   >>> del table.columns['year']\n   >>> print(table)\n   +----+----------+------+-------+--------+\n   |    |   name   | rank | marks | gender |\n   +----+----------+------+-------+--------+\n   | S1 |  Jacob   |  1   |  78   |  boy   |\n   +----+----------+------+-------+--------+\n   | S2 | Isabella |  1   |  67   |  girl  |\n   +----+----------+------+-------+--------+\n   | S3 |  Ethan   |  2   |  82   |  boy   |\n   +----+----------+------+-------+--------+\n   | S4 |  Sophia  |  2   |  86   |  girl  |\n   +----+----------+------+-------+--------+\n   | S5 | Michael  |  3   |  74   |  boy   |\n   +----+----------+------+-------+--------+\n\nYou can also use the helper methods :meth:`.BTRowCollection.pop`,\n:meth:`.BTColumnCollection.pop` to do the same thing. Both these\nmethods take the index or header of the row/column to be removed.\n\nTherefore the following 2 snippets are equivalent.\n\n.. code:: python\n\n   >>> table.columns.pop('marks')\n\n.. code:: python\n\n   >>> table.columns.pop(2)\n\n\n=========================================================================\nUpdating data in the Table\n=========================================================================\n\nLet's change the name in the 4th row to ``'Sophie'``.\n\n.. code:: python\n\n   >>> table.rows[3][0] = 'Sophie' # index of 4th row is 3\n   >>> print(list(table.rows[3]))\n   ['Sophie', 2, 86, 'girl']\n\nYou could have done the same thing using the header.\n\n.. code:: python\n\n   >>> table.rows[3]['name'] = 'Sophie'\n\n\nOr, you can also change the entire row, or even multiple rows\nusing slicing.\n\n.. code:: python\n\n   >>> table.rows[3] = ['Sophie', 2, 56, 'girl']\n\n\nYou can also update existing columns as shown below.\n\n.. code:: python\n\n   >>> table.columns['marks'] = [75, 46, 89, 56, 82]\n   >>> print(table)\n   +----+----------+------+-------+--------+\n   |    |   name   | rank | marks | gender |\n   +----+----------+------+-------+--------+\n   | S1 |  Jacob   |  1   |  75   |  boy   |\n   +----+----------+------+-------+--------+\n   | S2 | Isabella |  1   |  46   |  girl  |\n   +----+----------+------+-------+--------+\n   | S3 |  Ethan   |  2   |  89   |  boy   |\n   +----+----------+------+-------+--------+\n   | S4 |  Sophie  |  2   |  56   |  girl  |\n   +----+----------+------+-------+--------+\n   | S5 | Michael  |  3   |  82   |  boy   |\n   +----+----------+------+-------+--------+\n\nThe methods :meth:`.BTRowCollection.update` and :meth:`.BTColumnCollection.update`\ncan be used to perform the operations discussed in this section.\n\nNote that you can only update existing columns but can't create\na new column using this method. For that you need to use the\nmethods :meth:`.BTRowCollection.append`, :meth:`.BTRowCollection.insert`,\n:meth:`.BTColumnCollection.append` or :meth:`.BTColumnCollection.insert`.\n\n\n=========================================================================\nSearching for rows or columns headers\n=========================================================================\n\nCheking if a column header is in the table.\n\n.. code:: python\n\n   >>> 'rank' in table.columns.header\n   True\n\nCheking if a row header is in the table.\n\n.. code:: python\n\n   >>> 'S2' in table.rows.header\n   True\n\nCheking if a row is in table\n\n.. code:: python\n\n   >>> [\"Ethan\", 2, 89, \"boy\"] in table.rows\n   True\n\nCheking if a column is in table\n\n.. code:: python\n\n   >>> [\"Jacob\", \"Isabella\", \"Ethan\", \"Sophie\", \"Michael\"] in table.columns\n   True\n\n=========================================================================\nSorting based on a Column\n=========================================================================\n\nYou can also :meth:`.BTRowCollection.sort` the table based on a column\nby specifying it's index or it's header.\n\n.. code:: python\n\n   >>> table.rows.sort('marks')\n   >>> print(table)\n   +----+----------+------+-------+--------+\n   |    |   name   | rank | marks | gender |\n   +----+----------+------+-------+--------+\n   | S2 | Isabella |  1   |  46   |  girl  |\n   +----+----------+------+-------+--------+\n   | S4 |  Sophia  |  2   |  56   |  girl  |\n   +----+----------+------+-------+--------+\n   | S1 |  Jacob   |  1   |  75   |  boy   |\n   +----+----------+------+-------+--------+\n   | S5 | Michael  |  3   |  82   |  boy   |\n   +----+----------+------+-------+--------+\n   | S3 |  Ethan   |  2   |  89   |  boy   |\n   +----+----------+------+-------+--------+\n\n=========================================================================\nCustomizing the look of the Table\n=========================================================================\n\n-------------------------------------------------------------------------\nAlignment\n-------------------------------------------------------------------------\n\nLet's change the way some columns are aligned in our table.\n\n.. code:: python\n\n   >>> table.columns.alignment['name'] = BeautifulTable.ALIGN_LEFT\n   >>> table.columns.alignment['gender'] = BeautifulTable.ALIGN_RIGHT\n   >>> print(table)\n   +----+----------+------+-------+--------+\n   |    | name     | rank | marks | gender |\n   +----+----------+------+-------+--------+\n   | S2 | Isabella |  1   |  46   |   girl |\n   +----+----------+------+-------+--------+\n   | S4 | Sophia   |  2   |  56   |   girl |\n   +----+----------+------+-------+--------+\n   | S1 | Jacob    |  1   |  75   |    boy |\n   +----+----------+------+-------+--------+\n   | S5 | Michael  |  3   |  82   |    boy |\n   +----+----------+------+-------+--------+\n   | S3 | Ethan    |  2   |  89   |    boy |\n   +----+----------+------+-------+--------+\n\nYou can also set all columns to a specific alignment\n\n.. code:: python\n\n   >>> table.columns.alignment = BeautifulTable.ALIGN_RIGHT\n   >>> print(table)\n   +----+----------+------+-------+--------+\n   |    |     name | rank | marks | gender |\n   +----+----------+------+-------+--------+\n   | S2 | Isabella |    1 |    46 |   girl |\n   +----+----------+------+-------+--------+\n   | S4 |   Sophia |    2 |    56 |   girl |\n   +----+----------+------+-------+--------+\n   | S1 |    Jacob |    1 |    75 |    boy |\n   +----+----------+------+-------+--------+\n   | S5 |  Michael |    3 |    82 |    boy |\n   +----+----------+------+-------+--------+\n   | S3 |    Ethan |    2 |    89 |    boy |\n   +----+----------+------+-------+--------+\n\nHeaders can have a different alignment that the column.\n\n.. code:: python\n\n   >>> table.columns.header.alignment= BeautifulTable.ALIGN_RIGHT\n   >>> table.columns.alignment = BeautifulTable.ALIGN_LEFT\n   >>> print(table)\n   +----+----------+------+-------+--------+\n   |    |     name | rank | marks | gender |\n   +----+----------+------+-------+--------+\n   | S2 | Isabella | 1    | 46    | girl   |\n   +----+----------+------+-------+--------+\n   | S4 | Sophia   | 2    | 56    | girl   |\n   +----+----------+------+-------+--------+\n   | S1 | Jacob    | 1    | 75    | boy    |\n   +----+----------+------+-------+--------+\n   | S5 | Michael  | 3    | 82    | boy    |\n   +----+----------+------+-------+--------+\n   | S3 | Ethan    | 2    | 89    | boy    |\n   +----+----------+------+-------+--------+\n\n\n-------------------------------------------------------------------------\nPadding\n-------------------------------------------------------------------------\n\nYou can change the padding for individual column similar to\nthe alignment.\n\n.. code:: python\n\n   >>> table.columns.padding_left['rank'] = 5\n   >>> table.columns.padding_right['rank'] = 3\n   >>> print(table)\n   +----+----------+------------+--------+\n   |    |   name   |     rank   | gender |\n   +----+----------+------------+--------+\n   | S1 |  Jacob   |      1     |  boy   |\n   +----+----------+------------+--------+\n   | S2 | Isabella |      1     |  girl  |\n   +----+----------+------------+--------+\n   | S3 |  Ethan   |      2     |  boy   |\n   +----+----------+------------+--------+\n   | S4 |  Sophia  |      2     |  girl  |\n   +----+----------+------------+--------+\n   | S5 | Michael  |      3     |  boy   |\n   +----+----------+------------+--------+\n\n\nYou can use a helper attribute :attr:`.BTColumnCollection.padding` to\nset the left and right padding to a common value.\n\n\n-------------------------------------------------------------------------\nStyling\n-------------------------------------------------------------------------\n\n**beautifultable** comes with several predefined styles for various use cases.\nYou can use the :meth:`.BeautifulTable.set_style` method to set the style\nof the table. The following styles are available:\n\n* **STYLE_DEFAULT**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_DEFAULT)\n     >>> print(table)\n     +----+----------+------+--------+\n     |    |   name   | rank | gender |\n     +----+----------+------+--------+\n     | S1 |  Jacob   |  1   |  boy   |\n     +----+----------+------+--------+\n     | S2 | Isabella |  1   |  girl  |\n     +----+----------+------+--------+\n     | S3 |  Ethan   |  2   |  boy   |\n     +----+----------+------+--------+\n     | S4 |  Sophia  |  2   |  girl  |\n     +----+----------+------+--------+\n     | S5 | Michael  |  3   |  boy   |\n     +----+----------+------+--------+\n\n* **STYLE_NONE**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_NONE)\n     >>> print(table)\n           name    rank  gender\n     S1   Jacob     1     boy\n     S2  Isabella   1     girl\n     S3   Ethan     2     boy\n     S4   Sophia    2     girl\n     S5  Michael    3     boy\n\n* **STYLE_DOTTED**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_DOTTED)\n     >>> print(table)\n     .................................\n     :    :   name   : rank : gender :\n     .................................\n     : S1 :  Jacob   :  1   :  boy   :\n     : S2 : Isabella :  1   :  girl  :\n     : S3 :  Ethan   :  2   :  boy   :\n     : S4 :  Sophia  :  2   :  girl  :\n     : S5 : Michael  :  3   :  boy   :\n     .................................\n\n* **STYLE_SEPARATED**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_SEPARATED)\n     >>> print(table)\n     +====+==========+======+========+\n     |    |   name   | rank | gender |\n     +====+==========+======+========+\n     | S1 |  Jacob   |  1   |  boy   |\n     +----+----------+------+--------+\n     | S2 | Isabella |  1   |  girl  |\n     +----+----------+------+--------+\n     | S3 |  Ethan   |  2   |  boy   |\n     +----+----------+------+--------+\n     | S4 |  Sophia  |  2   |  girl  |\n     +----+----------+------+--------+\n     | S5 | Michael  |  3   |  boy   |\n     +----+----------+------+--------+\n\n* **STYLE_COMPACT**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_COMPACT)\n     >>> print(table)\n             name     rank   gender\n     ---- ---------- ------ --------\n     S1    Jacob      1      boy\n     S2   Isabella    1      girl\n     S3    Ethan      2      boy\n     S4    Sophia     2      girl\n     S5   Michael     3      boy\n\n* **STYLE_MYSQL**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_MYSQL)\n     >>> print(table)  # Yes, the default style is same as this style\n     +----+----------+------+--------+\n     |    |   name   | rank | gender |\n     +----+----------+------+--------+\n     | S1 |  Jacob   |  1   |  boy   |\n     +----+----------+------+--------+\n     | S2 | Isabella |  1   |  girl  |\n     +----+----------+------+--------+\n     | S3 |  Ethan   |  2   |  boy   |\n     +----+----------+------+--------+\n     | S4 |  Sophia  |  2   |  girl  |\n     +----+----------+------+--------+\n     | S5 | Michael  |  3   |  boy   |\n     +----+----------+------+--------+\n\n* **STYLE_MARKDOWN**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_MARKDOWN)\n     >>> print(table)  # Markdown alignment not supported currently\n     |    |   name   | rank | gender |\n     |----|----------|------|--------|\n     | S1 |  Jacob   |  1   |  boy   |\n     | S2 | Isabella |  1   |  girl  |\n     | S3 |  Ethan   |  2   |  boy   |\n     | S4 |  Sophia  |  2   |  girl  |\n     | S5 | Michael  |  3   |  boy   |\n\n* **STYLE_RST**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_RST)\n     >>> print(table)\n     ==== ========== ====== ========\n             name     rank   gender\n     ==== ========== ====== ========\n     S1    Jacob      1      boy\n     S2   Isabella    1      girl\n     S3    Ethan      2      boy\n     S4    Sophia     2      girl\n     S5   Michael     3      boy\n     ==== ========== ====== ========\n\n* **STYLE_BOX**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_BOX)\n     >>> print(table)\n     ┌────┬──────────┬──────┬────────┐\n     │    │   name   │ rank │ gender │\n     ├────┼──────────┼──────┼────────┤\n     │ S1 │  Jacob   │  1   │  boy   │\n     ├────┼──────────┼──────┼────────┤\n     │ S2 │ Isabella │  1   │  girl  │\n     ├────┼──────────┼──────┼────────┤\n     │ S3 │  Ethan   │  2   │  boy   │\n     ├────┼──────────┼──────┼────────┤\n     │ S4 │  Sophia  │  2   │  girl  │\n     ├────┼──────────┼──────┼────────┤\n     │ S5 │ Michael  │  3   │  boy   │\n     └────┴──────────┴──────┴────────┘\n\n* **STYLE_BOX_DOUBLED**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_BOX_DOUBLED)\n     >>> print(table)\n     ╔════╦══════════╦══════╦════════╗\n     ║    ║   name   ║ rank ║ gender ║\n     ╠════╬══════════╬══════╬════════╣\n     ║ S1 ║  Jacob   ║  1   ║  boy   ║\n     ╠════╬══════════╬══════╬════════╣\n     ║ S2 ║ Isabella ║  1   ║  girl  ║\n     ╠════╬══════════╬══════╬════════╣\n     ║ S3 ║  Ethan   ║  2   ║  boy   ║\n     ╠════╬══════════╬══════╬════════╣\n     ║ S4 ║  Sophia  ║  2   ║  girl  ║\n     ╠════╬══════════╬══════╬════════╣\n     ║ S5 ║ Michael  ║  3   ║  boy   ║\n     ╚════╩══════════╩══════╩════════╝\n\n* **STYLE_BOX_ROUNDED**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_BOX_ROUNDED)\n     >>> print(table)\n     ╭────┬──────────┬──────┬────────╮\n     │    │   name   │ rank │ gender │\n     ├────┼──────────┼──────┼────────┤\n     │ S1 │  Jacob   │  1   │  boy   │\n     ├────┼──────────┼──────┼────────┤\n     │ S2 │ Isabella │  1   │  girl  │\n     ├────┼──────────┼──────┼────────┤\n     │ S3 │  Ethan   │  2   │  boy   │\n     ├────┼──────────┼──────┼────────┤\n     │ S4 │  Sophia  │  2   │  girl  │\n     ├────┼──────────┼──────┼────────┤\n     │ S5 │ Michael  │  3   │  boy   │\n     ╰────┴──────────┴──────┴────────╯\n\n* **STYLE_GRID**\n\n  .. code:: python\n\n     >>> table.set_style(BeautifulTable.STYLE_GRID)\n     >>> print(table)\n     ╔════╤══════════╤══════╤════════╗\n     ║    │   name   │ rank │ gender ║\n     ╟────┼──────────┼──────┼────────╢\n     ║ S1 │  Jacob   │  1   │  boy   ║\n     ╟────┼──────────┼──────┼────────╢\n     ║ S2 │ Isabella │  1   │  girl  ║\n     ╟────┼──────────┼──────┼────────╢\n     ║ S3 │  Ethan   │  2   │  boy   ║\n     ╟────┼──────────┼──────┼────────╢\n     ║ S4 │  Sophia  │  2   │  girl  ║\n     ╟────┼──────────┼──────┼────────╢\n     ║ S5 │ Michael  │  3   │  boy   ║\n     ╚════╧══════════╧══════╧════════╝\n\nFor more finer customization, you can change what characters are used to draw\nvarious parts of the table. Here we show you an example of how you can use\nthis feature. You can read the API Reference for more details.\n\n.. code:: python\n\n   >>> table.set_style(BeautifulTable.STYLE_NONE)  # clear all formatting\n   >>> table.border.left = 'o'\n   >>> table.border.right = 'o'\n   >>> table.border.top = '<~>'\n   >>> table.border.bottom = '='\n   >>> table.columns.header.separator = '^'\n   >>> table.columns.separator = ':'\n   >>> table.rows.separator = '~'\n   >>> print(table)\n   <~><~><~><~><~><~><~><~><~><~><~>\n   o    :   name   : rank : gender o\n   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n   o S1 :  Jacob   :  1   :  boy   o\n   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   o S2 : Isabella :  1   :  girl  o\n   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   o S3 :  Ethan   :  2   :  boy   o\n   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   o S4 :  Sophia  :  2   :  girl  o\n   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n   o S5 : Michael  :  3   :  boy   o\n   =================================\n\nAs you can see, you can change quite a lot about your *BeautifulTable* instance.\nFor further sections, We switch the look of the table to *default* again.\n\n-------------------------------------------------------------------------\nColored Tables\n-------------------------------------------------------------------------\n\n**beautifultable** comes with out of the box support for colored tables using\nansi escape sequences. You can also use any library which makes use of\nthese sequences to produce colored text output.\n\n::\n\n    python3 -m pip install termcolor\n\n.. code:: python\n\n   >>> from termcolor import colored\n   >>> table.rows.append([colored(\"John\", 'red'), 4, colored(\"boy\", 'blue')])\n   >>> print(table)\n\n.. raw:: html\n\n   <p style=\"font-family: monospace; background-color: #eeffcc;\">\n   +----+----------+------+--------+<br />\n   |&nbsp;&nbsp;&nbsp; |&nbsp;&nbsp; name&nbsp;&nbsp; | rank | gender |<br />\n   +----+----------+------+--------+<br />\n   | S1 |&nbsp; Jacob&nbsp;&nbsp; |&nbsp; 1 &nbsp; |&nbsp; boy&nbsp;&nbsp; |<br />\n   +----+----------+------+--------+<br />\n   | S2 | Isabella |&nbsp; 1&nbsp;&nbsp; |&nbsp; girl&nbsp; |<br />\n   +----+----------+------+--------+<br />\n   | S3 |&nbsp; Ethan&nbsp;&nbsp; |&nbsp; 2&nbsp;&nbsp; |&nbsp; boy&nbsp;&nbsp; |<br />\n   +----+----------+------+--------+<br />\n   | S4 |&nbsp; Sophia&nbsp; |&nbsp; 2&nbsp;&nbsp; |&nbsp; girl&nbsp; |<br />\n   +----+----------+------+--------+<br />\n   | S5 | Michael&nbsp; |&nbsp; 3&nbsp;&nbsp; |&nbsp; boy&nbsp;&nbsp; |<br />\n   +----+----------+------+--------+<br />\n   | S6 |&nbsp;&nbsp; <span style=\"color: #ff0000;\">John</span>&nbsp;&nbsp; |&nbsp; 4&nbsp;&nbsp; |&nbsp; <span style=\"color: #0000ff;\">boy</span>&nbsp;&nbsp; |<br />\n   +----+----------+------+--------+\n   </p>\n\nYou can also use these sequences for making texts bold, italics, etc.\n\n-------------------------------------------------------------------------\nParagraphs\n-------------------------------------------------------------------------\n\nA cell can contain multiple paragraphs such that each one start from\na new line. **beautifultable** parses ``\\n`` as a paragraph change.\n\n.. code:: python\n\n   >>> new_table = BeautifulTable(max_width=40)\n   >>> new_table.columns.header = [\"Heading 1\", \"Heading 2\"]\n   >>> new_table.rows.append([\"first Line\\nsecond Line\", \"single line\"])\n   >>> new_table.rows.append([\"first Line\\nsecond Line\\nthird Line\", \"first Line\\nsecond Line\"])\n   >>> new_table.rows.append([\"single line\", \"this is a very long first line\\nThis is a very long second line\"])\n   >>> print(new_table)\n   +-------------+------------------------+\n   |  Heading 1  |       Heading 2        |\n   +-------------+------------------------+\n   | first Line  |      single line       |\n   | second Line |                        |\n   +-------------+------------------------+\n   | first Line  |       first Line       |\n   | second Line |      second Line       |\n   | third Line  |                        |\n   +-------------+------------------------+\n   | single line | this is a very long fi |\n   |             |        rst line        |\n   |             | This is a very long se |\n   |             |       cond line        |\n   +-------------+------------------------+\n\n-------------------------------------------------------------------------\nSubtables\n-------------------------------------------------------------------------\n\nYou can even render a :class:`.BeautifulTable` instance inside another\ntable. To do that, just pass the table as any regular text and it just\nworks.\n\n.. code:: python\n\n   >>> # Setting up the inner table\n   >>> subtable = BeautifulTable()\n   >>> subtable.rows.append([\"Jacob\", 1, \"boy\"])\n   >>> subtable.rows.append([\"Isabella\", 1, \"girl\"])\n   >>> subtable.border.left = ''\n   >>> subtable.border.right = ''\n   >>> subtable.border.top = ''\n   >>> subtable.border.right = ''\n   >>>\n   >>> # Setting up the outer table\n   >>> table = BeautifulTable()\n   >>> table.columns.header = [\"Heading 1\", \"Heading 2\"]\n   >>> table.rows.append([\"Sample text\", \"Another sample text\"])\n   >>> table.rows.append([subtable, \"More sample text\"])\n   >>> table.columns.padding_left[0] = 0\n   >>> table.columns.padding_right[0] = 0\n   >>> print(table)\n   +---------------------+---------------------+\n   |      Heading 1      |      Heading 2      |\n   +---------------------+---------------------+\n   |     Sample text     | Another sample text |\n   +---------------------+---------------------+\n   |  Jacob   | 1 | boy  |  More sample text   |\n   |----------+---+------|                     |\n   | Isabella | 1 | girl |                     |\n   +---------------------+---------------------+\n\n=========================================================================\nStreaming Tables\n=========================================================================\n\nThere are situations where data retrieval is slow such as when data is\nrecieved over a network and you want to display the data as soon as\npossible. In these cases, you can use streaming tables to render the table\nwith the help of a generator.\n\nStreaming table do have their limitation. The width calculation routine\nrequires you to either set it manually or specify the column header or\nadd atleast 1 row. You also cannot have row headers for streaming tables.\n\n.. code:: python\n\n   >>> import time\n   >>> def time_taking_process():\n   ...     for i in range(5):\n   ...         time.sleep(1)\n   ...         yield [i, i**2]\n   ...\n   ...\n   >>> table = BeautifulTable()\n   >>> table.columns.header = [\"Number\", \"It's Square\"]\n   >>> for line in table.stream(time_taking_process()):\n   ...     print(line)\n   ...\n   +--------+-------------+\n   | Number | It's Square |\n   +--------+-------------+\n   |   0    |      0      |\n   +--------+-------------+\n   |   1    |      1      |\n   +--------+-------------+\n   |   2    |      4      |\n   +--------+-------------+\n   |   3    |      9      |\n   +--------+-------------+\n   |   4    |     16      |\n   +--------+-------------+\n\n=========================================================================\nSupport for Multibyte Unicode characters\n=========================================================================\n\n**beautifultable** comes with built-in support for multibyte unicode such as\neast-asian characters.\n\nYou can do much more with BeautifulTable but this much should give you a\ngood start. Those of you who are interested to have more control can\nread the API Documentation.\n"
  },
  {
    "path": "docs/source/beautifultable.rst",
    "content": "beautifultable package\n======================\n\nModule contents\n---------------\n\n.. automodule:: beautifultable\n    :imported-members:\n    :show-inheritance:\n\n.. autoclass:: beautifultable.BeautifulTable\n    :members:\n\n.. autoclass:: beautifultable.BTRowCollection\n    :members:\n\n.. autoclass:: beautifultable.BTColumnCollection\n    :members:\n\n.. autoclass:: beautifultable.BTRowHeader\n    :members:\n    :inherited-members:\n\n.. autoclass:: beautifultable.BTColumnHeader\n    :members:\n    :inherited-members:\n\n.. autoclass:: beautifultable.BTBorder\n    :members:\n"
  },
  {
    "path": "docs/source/modules.rst",
    "content": "beautifultable\n==============\n\n.. toctree::\n   :maxdepth: 2\n\n   beautifultable\n"
  },
  {
    "path": "requirements.txt",
    "content": "wcwidth\npandas"
  },
  {
    "path": "setup.cfg",
    "content": "[bdist_wheel]\nuniversal=1\n"
  },
  {
    "path": "setup.py",
    "content": "import os\nimport codecs\nimport itertools\n\nfrom setuptools import setup\n\ninstall_requires = [\"wcwidth\"]\n\nextras_require = {\n    \"dev\": [\"pandas\"],\n}\n\nextras_require[\"all\"] = list(\n    set(itertools.chain.from_iterable(extras_require.values()))\n)\n\nthis_dir = os.path.abspath(os.path.dirname(__file__))\nversion_path = os.path.join(this_dir, \"beautifultable\", \"__version__.py\")\n\nabout = {}\nwith codecs.open(version_path, \"r\", \"utf-8\") as f:\n    exec(f.read(), about)\n\nwith codecs.open(\"README.rst\", \"r\", \"utf-8\") as f:\n    readme = f.read()\n\ndownload_url = \"{}/tarball/{}\".format(about[\"__url__\"], about[\"__version__\"])\n\nsetup(\n    name=about[\"__title__\"],\n    version=about[\"__version__\"],\n    description=about[\"__description__\"],\n    long_description=readme,\n    author=about[\"__author__\"],\n    author_email=about[\"__author_email__\"],\n    packages=[\"beautifultable\"],\n    url=about[\"__url__\"],\n    download_url=download_url,\n    license=about[\"__license__\"],\n    keywords=\"table terminal ascii\",\n    extras_require=extras_require,\n    install_requires=install_requires,\n    classifiers=[\n        \"Development Status :: 4 - Beta\",\n        \"Environment :: Console\",\n        \"Intended Audience :: Developers\",\n        \"License :: OSI Approved :: MIT License\",\n        \"Programming Language :: Python\",\n        \"Programming Language :: Python :: 3.7\",\n        \"Programming Language :: Python :: 3.8\",\n        \"Programming Language :: Python :: 3.9\",\n        \"Programming Language :: Python :: 3.10\",\n        \"Programming Language :: Python :: Implementation :: CPython\",\n        \"Programming Language :: Python :: Implementation :: PyPy\",\n        \"Topic :: Printing\",\n        \"Topic :: Text Processing\",\n    ],\n)\n"
  },
  {
    "path": "test.py",
    "content": "# -*- coding: utf-8 -*-\n\n\nimport os\nimport unittest\nimport itertools\n\nfrom beautifultable import BeautifulTable\n\ntry:\n    import pandas as pd\nexcept ImportError:\n    pd = None\n    PANDAS_INSTALLED = False\nelse:\n    PANDAS_INSTALLED = True\n\nREQUIRED_PANDAS_MESSAGE = \"requires 'pandas' to be installed\"\n\n\nclass TableOperationsTestCase(unittest.TestCase):\n    def setUp(self):\n        self.create_table()\n\n    def create_table(self, maxwidth=80):\n        table = BeautifulTable(maxwidth=maxwidth)\n\n        table.rows.append([\"Jacob\", 1, \"boy\"])\n        table.rows.append([\"Isabella\", 1, \"girl\"])\n        table.rows.append([\"Ethan\", 2, \"boy\"])\n        table.rows.append([\"Sophia\", 2, \"girl\"])\n        table.rows.append([\"Michael\", 3, \"boy\"])\n\n        table.columns.header = [\"name\", \"rank\", \"gender\"]\n        table.rows.header = [\"S1\", \"S2\", \"S3\", \"S4\", \"S5\"]\n\n        self.table = table\n\n    def create_dataframe(self):\n        return self.table.to_df()\n\n    def compare_iterable(self, iterable1, iterable2):\n        for item1, item2 in itertools.zip_longest(iterable1, iterable2):\n            self.assertEqual(item1, item2)\n\n    # Test for table operations\n\n    def test_filter(self):\n        new_table = self.table.rows.filter(lambda x: x[\"rank\"] > 1)\n        self.assertEqual(len(self.table.rows), 5)\n        rows = [\n            [\"Ethan\", 2, \"boy\"],\n            [\"Sophia\", 2, \"girl\"],\n            [\"Michael\", 3, \"boy\"],\n        ]\n        for row_t, row in zip(new_table.rows, rows):\n            self.compare_iterable(row_t, row)\n\n    def test_sort_by_index(self):\n        self.table.rows.sort(0)\n        rows = [\n            [\"Ethan\", 2, \"boy\"],\n            [\"Isabella\", 1, \"girl\"],\n            [\"Jacob\", 1, \"boy\"],\n            [\"Michael\", 3, \"boy\"],\n            [\"Sophia\", 2, \"girl\"],\n        ]\n        for row_t, row in zip(self.table.rows, rows):\n            self.compare_iterable(row_t, row)\n\n    def test_sort_by_index_reversed(self):\n        self.table.rows.sort(0, reverse=True)\n        rows = [\n            [\"Ethan\", 2, \"boy\"],\n            [\"Isabella\", 1, \"girl\"],\n            [\"Jacob\", 1, \"boy\"],\n            [\"Michael\", 3, \"boy\"],\n            [\"Sophia\", 2, \"girl\"],\n        ]\n        for row_t, row in zip(self.table.rows, reversed(rows)):\n            self.compare_iterable(row_t, row)\n\n    def test_sort_by_header(self):\n        self.table.rows.sort(\"name\")\n        rows = [\n            [\"Ethan\", 2, \"boy\"],\n            [\"Isabella\", 1, \"girl\"],\n            [\"Jacob\", 1, \"boy\"],\n            [\"Michael\", 3, \"boy\"],\n            [\"Sophia\", 2, \"girl\"],\n        ]\n        for row_t, row in zip(self.table.rows, rows):\n            self.compare_iterable(row_t, row)\n\n    def test_sort_by_callable(self):\n        self.table.rows.sort(lambda x: (x[1], x[0]))\n        rows = [\n            [\"Isabella\", 1, \"girl\"],\n            [\"Jacob\", 1, \"boy\"],\n            [\"Ethan\", 2, \"boy\"],\n            [\"Sophia\", 2, \"girl\"],\n            [\"Michael\", 3, \"boy\"],\n        ]\n        for row_t, row in zip(self.table.rows, rows):\n            self.compare_iterable(row_t, row)\n\n    def test_sort_raises_exception(self):\n        with self.assertRaises(TypeError):\n            self.table.rows.sort(None)\n\n    # Tests for column operations\n\n    def test_column_aslist(self):\n        self.assertEqual(\n            [column.aslist() for column in self.table.columns],\n            [\n                [\"Jacob\", \"Isabella\", \"Ethan\", \"Sophia\", \"Michael\"],\n                [1, 1, 2, 2, 3],\n                [\"boy\", \"girl\", \"boy\", \"girl\", \"boy\"],\n            ],\n        )\n\n    def test_column_asdict(self):\n        with self.assertRaises(NotImplementedError):\n            header_colval_map = [column.asdict() for column in self.table.columns]\n\n    def test_column_count(self):\n        self.assertEqual(len(self.table.columns), 3)\n\n    def test_access_column_by_header(self):\n        column = [\"Jacob\", \"Isabella\", \"Ethan\", \"Sophia\", \"Michael\"]\n        self.compare_iterable(column, self.table.columns[\"name\"])\n        with self.assertRaises(KeyError):\n            self.table.columns[\"name1\"]\n\n    def test_access_column_element_by_index(self):\n        self.assertEqual(self.table.columns[0][2], \"Ethan\")\n\n    def test_access_column_element_by_header(self):\n        self.assertEqual(self.table.columns[\"name\"][2], \"Ethan\")\n\n    def test_get_column_index(self):\n        self.assertEqual(self.table.columns.header.index(\"gender\"), 2)\n        with self.assertRaises(KeyError):\n            self.table.columns.header.index(\"rank1\")\n\n    def test_get_column_header(self):\n        self.assertEqual(self.table.columns.header[2], \"gender\")\n        with self.assertRaises(IndexError):\n            self.table.columns.header[len(self.table.columns)]\n\n    def test_append_column(self):\n        title = \"year\"\n        column = [\"2010\", \"2012\", \"2008\", \"2010\", \"2011\"]\n        self.table.columns.append(column, title)\n        self.assertEqual(len(self.table.columns), 4)\n        last_column = self.table.columns[len(self.table.columns) - 1]\n        self.compare_iterable(column, last_column)\n\n    def test_append_column_empty_table(self):\n        self.table = BeautifulTable()\n        title = \"year\"\n        column = [\"2010\", \"2012\", \"2008\", \"2010\", \"2011\"]\n        self.table.columns.append(column, header=title)\n        string = \"\"\"+------+\n| year |\n+------+\n| 2010 |\n+------+\n| 2012 |\n+------+\n| 2008 |\n+------+\n| 2010 |\n+------+\n| 2011 |\n+------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_insert_column(self):\n        column = [\"2010\", \"2012\", \"2008\", \"2010\", \"2011\"]\n        title = \"year\"\n        position = 2\n        self.table.columns.insert(position, column, title)\n        self.assertEqual(len(self.table.columns), 4)\n        self.compare_iterable(column, self.table.columns[position])\n\n    def test_pop_column_by_position(self):\n        position = 2\n        header = self.table.columns.header[position]\n        self.table.columns.pop(position)\n        self.assertEqual(len(self.table.columns), 2)\n        with self.assertRaises(KeyError):\n            self.table.columns[header]\n\n    def test_pop_column_by_header(self):\n        header = \"gender\"\n        self.table.columns.pop(header)\n        self.assertEqual(len(self.table.columns), 2)\n        with self.assertRaises(KeyError):\n            self.table.columns[header]\n\n    def test_update_column_by_index(self):\n        index = 1\n        column = [3, 2, 1, 2, 4]\n        self.table.columns.update(index, column)\n        self.assertEqual(len(self.table.columns), 3)\n        self.compare_iterable(column, self.table.columns[index])\n\n    def test_update_column_by_header(self):\n        header = \"rank\"\n        column = [3, 2, 1, 2, 4]\n        self.table.columns.update(header, column)\n        self.assertEqual(len(self.table.columns), 3)\n        self.compare_iterable(column, self.table.columns[header])\n\n    def test_update_column_slice(self):\n        columns = [\n            [5, \"girl\"],\n            [4, \"boy\"],\n            [4, \"boy\"],\n            [2, \"girl\"],\n            [1, \"boy\"],\n        ]\n        self.table.columns.update(slice(1, 3, 1), columns)\n        self.assertEqual(len(self.table.columns), 3)\n        self.compare_iterable(self.table.columns[1], [c[0] for c in columns])\n        self.compare_iterable(self.table.columns[2], [c[1] for c in columns])\n\n    # Tests for row operations\n\n    def test_row_asdict(self):\n        self.assertEqual(\n            [row.asdict() for row in self.table.rows],\n            [\n                {\"name\": \"Jacob\", \"rank\": 1, \"gender\": \"boy\"},\n                {\"name\": \"Isabella\", \"rank\": 1, \"gender\": \"girl\"},\n                {\"name\": \"Ethan\", \"rank\": 2, \"gender\": \"boy\"},\n                {\"name\": \"Sophia\", \"rank\": 2, \"gender\": \"girl\"},\n                {\"name\": \"Michael\", \"rank\": 3, \"gender\": \"boy\"},\n            ],\n        )\n\n    def test_row_aslist(self):\n        self.assertEqual(\n            [row.aslist() for row in self.table.rows],\n            [\n                [\"Jacob\", 1, \"boy\"],\n                [\"Isabella\", 1, \"girl\"],\n                [\"Ethan\", 2, \"boy\"],\n                [\"Sophia\", 2, \"girl\"],\n                [\"Michael\", 3, \"boy\"],\n            ],\n        )\n\n    def test_row_count(self):\n        self.assertEqual(len(self.table.rows), 5)\n\n    def test_access_row_by_index(self):\n        row = [\"Sophia\", 2, \"girl\"]\n        self.compare_iterable(row, self.table.rows[3])\n        with self.assertRaises(IndexError):\n            self.table.rows[len(self.table.rows)]\n\n    def test_access_row_by_header(self):\n        row = [\"Sophia\", 2, \"girl\"]\n        self.compare_iterable(row, self.table.rows[\"S4\"])\n        with self.assertRaises(IndexError):\n            self.table.rows[len(self.table.rows)]\n\n    def test_access_row_element_by_index(self):\n        self.assertEqual(self.table.rows[2][0], \"Ethan\")\n\n    def test_access_row_element_by_header(self):\n        self.assertEqual(self.table.rows[2][\"name\"], \"Ethan\")\n\n    def test_append_row(self):\n        row = [\"Gary\", 2, \"boy\"]\n        self.table.rows.append(row, header=\"S6\")\n        self.assertEqual(len(self.table.rows), 6)\n        self.compare_iterable(self.table.rows[5], row)\n\n    def test_insert_row(self):\n        row = [\"Gary\", 2, \"boy\"]\n        position = 2\n        self.table.rows.insert(position, row, header=\"S6\")\n        self.assertEqual(len(self.table.rows), 6)\n        self.compare_iterable(self.table.rows[position], row)\n\n    def test_pop_row_by_position(self):\n        position = 2\n        self.table.rows.pop(position)\n        self.assertEqual(len(self.table.rows), 4)\n\n    def test_pop_row_by_header(self):\n        header = \"S3\"\n        self.table.rows.pop(header)\n        self.assertEqual(len(self.table.rows), 4)\n\n    def test_update_row_by_index(self):\n        row = [\"Sophie\", 5, \"girl\"]\n        position = 3\n        self.table.rows.update(position, row)\n        self.compare_iterable(self.table.rows[position], row)\n\n    def test_update_row_by_header(self):\n        row = [\"Sophie\", 5, \"girl\"]\n        header = \"S4\"\n        self.table.rows.update(header, row)\n        self.compare_iterable(self.table.rows[header], row)\n\n    def test_update_row_slice(self):\n        rows = [[\"Sophie\", 5, \"girl\"], [\"Mike\", 4, \"boy\"]]\n        self.table.rows.update(slice(3, 5, 1), rows)\n        self.assertEqual(len(self.table.rows), 5)\n        self.compare_iterable(self.table.rows[3], rows[0])\n        self.compare_iterable(self.table.rows[4], rows[1])\n\n    # Tests for special row methods\n\n    def test_row_getitem_slice(self):\n        new_table = self.table.rows[:3]\n        self.assertEqual(len(new_table.rows), 3)\n        self.assertEqual(len(self.table.rows), 5)\n\n    def test_row_delitem_int(self):\n        del self.table.rows[1]\n        self.assertEqual(len(self.table.rows), 4)\n\n    def test_row_delitem_slice(self):\n        del self.table.rows[2:]\n        self.assertEqual(len(self.table.rows), 2)\n\n    def test_row_delitem_str(self):\n        del self.table.rows[\"S2\"]\n        self.assertEqual(len(self.table.rows), 4)\n        with self.assertRaises(KeyError):\n            self.table.rows[\"S2\"]\n\n    def test_row_setitem_int(self):\n        position = 3\n        row = [\"Sophie\", 5, \"girl\"]\n        self.table.rows[position] = row\n        self.compare_iterable(self.table.rows[position], row)\n\n    def test_row_setitem_slice(self):\n        rows = [[\"Sophie\", 5, \"girl\"], [\"Mike\", 4, \"boy\"]]\n        self.table.rows[3:] = rows\n        self.assertEqual(len(self.table.rows), 5)\n        self.compare_iterable(self.table.rows[3], rows[0])\n        self.compare_iterable(self.table.rows[4], rows[1])\n\n    def test_row_setitem_str(self):\n        header = \"S2\"\n        row = [\"Mike\", 4, \"Boy\"]\n        self.table.rows[header] = row\n        self.assertEqual(len(self.table.rows), 5)\n        self.compare_iterable(row, self.table.rows[header])\n\n    def test_row_contains(self):\n        self.assertTrue([\"Isabella\", 1, \"girl\"] in self.table.rows)\n        self.assertFalse([\"Ethan\", 3, \"boy\"] in self.table.rows)\n\n    def test_row_header_contains(self):\n        self.assertTrue(\"S3\" in self.table.rows.header)\n        self.assertFalse(\"S6\" in self.table.rows.header)\n\n    # Test for special column methods\n\n    def test_column_getitem_slice(self):\n        new_table = self.table.columns[:2]\n        self.assertEqual(len(self.table.columns), 3)\n        self.assertEqual(len(new_table.columns), 2)\n\n    def test_column_delitem_int(self):\n        del self.table.columns[1]\n        self.assertEqual(len(self.table.columns), 2)\n\n    def test_column_delitem_slice(self):\n        del self.table.columns[2:]\n        self.assertEqual(len(self.table.columns), 2)\n\n    def test_column_delitem_str(self):\n        del self.table.columns[\"rank\"]\n        self.assertEqual(len(self.table.columns), 2)\n        with self.assertRaises(KeyError):\n            self.table.columns[\"rank\"]\n\n    def test_column_setitem_int(self):\n        position = 2\n        row = [3, 4, 5, 6, 7]\n        self.table.columns[position] = row\n        self.compare_iterable(self.table.columns[position], row)\n\n    def test_column_setitem_slice(self):\n        columns = [\n            [5, \"girl\"],\n            [4, \"boy\"],\n            [4, \"boy\"],\n            [2, \"girl\"],\n            [1, \"boy\"],\n        ]\n        self.table.columns[1:] = columns\n        self.assertEqual(len(self.table.columns), 3)\n        self.compare_iterable(self.table.columns[1], [c[0] for c in columns])\n        self.compare_iterable(self.table.columns[2], [c[1] for c in columns])\n\n    def test_column_setitem_str(self):\n        header = \"rank\"\n        column = [3, 2, 1, 2, 4]\n        self.table.columns[header] = column\n        self.assertEqual(len(self.table.columns), 3)\n        self.compare_iterable(column, self.table.columns[header])\n\n    def test_column_header_contains(self):\n        self.assertTrue(\"rank\" in self.table.columns.header)\n        self.assertFalse(\"score\" in self.table.columns.header)\n\n    def test_column_contains(self):\n        self.assertTrue([\"boy\", \"girl\", \"boy\", \"girl\", \"boy\"] in self.table.columns)\n        self.assertFalse([\"boy\", \"girl\", \"girl\", \"girl\", \"boy\"] in self.table.columns)\n\n    # Test for printing operations\n\n    def test_get_string(self):\n        string = \"\"\"+----+----------+------+--------+\n|    |   name   | rank | gender |\n+----+----------+------+--------+\n| S1 |  Jacob   |  1   |  boy   |\n+----+----------+------+--------+\n| S2 | Isabella |  1   |  girl  |\n+----+----------+------+--------+\n| S3 |  Ethan   |  2   |  boy   |\n+----+----------+------+--------+\n| S4 |  Sophia  |  2   |  girl  |\n+----+----------+------+--------+\n| S5 | Michael  |  3   |  boy   |\n+----+----------+------+--------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_stream(self):\n        def generator():\n            for i in range(1, 6):\n                yield [i, i**2]\n\n        table = BeautifulTable()\n        table.columns.header = [\"Number\", \"It's Square\"]\n        self.compare_iterable(\n            table.stream(generator()),\n            [\n                \"+--------+-------------+\",\n                \"| Number | It's Square |\",\n                \"+--------+-------------+\",\n                \"|   1    |      1      |\",\n                \"+--------+-------------+\",\n                \"|   2    |      4      |\",\n                \"+--------+-------------+\",\n                \"|   3    |      9      |\",\n                \"+--------+-------------+\",\n                \"|   4    |     16      |\",\n                \"+--------+-------------+\",\n                \"|   5    |     25      |\",\n                \"+--------+-------------+\",\n            ],\n        )\n\n    def test_left_align(self):\n        self.table.columns.alignment[0] = self.table.ALIGN_LEFT\n        string = \"\"\"+----+----------+------+--------+\n|    | name     | rank | gender |\n+----+----------+------+--------+\n| S1 | Jacob    |  1   |  boy   |\n+----+----------+------+--------+\n| S2 | Isabella |  1   |  girl  |\n+----+----------+------+--------+\n| S3 | Ethan    |  2   |  boy   |\n+----+----------+------+--------+\n| S4 | Sophia   |  2   |  girl  |\n+----+----------+------+--------+\n| S5 | Michael  |  3   |  boy   |\n+----+----------+------+--------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_right_align(self):\n        self.table.columns.alignment[0] = self.table.ALIGN_RIGHT\n        string = \"\"\"+----+----------+------+--------+\n|    |     name | rank | gender |\n+----+----------+------+--------+\n| S1 |    Jacob |  1   |  boy   |\n+----+----------+------+--------+\n| S2 | Isabella |  1   |  girl  |\n+----+----------+------+--------+\n| S3 |    Ethan |  2   |  boy   |\n+----+----------+------+--------+\n| S4 |   Sophia |  2   |  girl  |\n+----+----------+------+--------+\n| S5 |  Michael |  3   |  boy   |\n+----+----------+------+--------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_mixed_align(self):\n        self.table.columns.alignment = [\n            self.table.ALIGN_LEFT,\n            self.table.ALIGN_CENTER,\n            self.table.ALIGN_RIGHT,\n        ]\n        string = \"\"\"+----+----------+------+--------+\n|    | name     | rank | gender |\n+----+----------+------+--------+\n| S1 | Jacob    |  1   |    boy |\n+----+----------+------+--------+\n| S2 | Isabella |  1   |   girl |\n+----+----------+------+--------+\n| S3 | Ethan    |  2   |    boy |\n+----+----------+------+--------+\n| S4 | Sophia   |  2   |   girl |\n+----+----------+------+--------+\n| S5 | Michael  |  3   |    boy |\n+----+----------+------+--------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_align_all(self):\n        self.table.columns.alignment = self.table.ALIGN_LEFT\n        string = \"\"\"+----+----------+------+--------+\n|    | name     | rank | gender |\n+----+----------+------+--------+\n| S1 | Jacob    | 1    | boy    |\n+----+----------+------+--------+\n| S2 | Isabella | 1    | girl   |\n+----+----------+------+--------+\n| S3 | Ethan    | 2    | boy    |\n+----+----------+------+--------+\n| S4 | Sophia   | 2    | girl   |\n+----+----------+------+--------+\n| S5 | Michael  | 3    | boy    |\n+----+----------+------+--------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_sign_plus(self):\n        self.table.sign = self.table.SM_PLUS\n        string = \"\"\"+----+----------+------+--------+\n|    |   name   | rank | gender |\n+----+----------+------+--------+\n| S1 |  Jacob   |  +1  |  boy   |\n+----+----------+------+--------+\n| S2 | Isabella |  +1  |  girl  |\n+----+----------+------+--------+\n| S3 |  Ethan   |  +2  |  boy   |\n+----+----------+------+--------+\n| S4 |  Sophia  |  +2  |  girl  |\n+----+----------+------+--------+\n| S5 | Michael  |  +3  |  boy   |\n+----+----------+------+--------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_wep_wrap(self):\n        self.create_table(20)\n        self.table.columns.width_exceed_policy = self.table.WEP_WRAP\n        string = \"\"\"+---+------+---+---+\n|   | name | r | g |\n|   |      | a | e |\n|   |      | n | n |\n|   |      | k | d |\n|   |      |   | e |\n|   |      |   | r |\n+---+------+---+---+\n| S | Jaco | 1 | b |\n| 1 |  b   |   | o |\n|   |      |   | y |\n+---+------+---+---+\n| S | Isab | 1 | g |\n| 2 | ella |   | i |\n|   |      |   | r |\n|   |      |   | l |\n+---+------+---+---+\n| S | Etha | 2 | b |\n| 3 |  n   |   | o |\n|   |      |   | y |\n+---+------+---+---+\n| S | Soph | 2 | g |\n| 4 |  ia  |   | i |\n|   |      |   | r |\n|   |      |   | l |\n+---+------+---+---+\n| S | Mich | 3 | b |\n| 5 | ael  |   | o |\n|   |      |   | y |\n+---+------+---+---+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_wep_strip(self):\n        self.create_table(20)\n        self.table.columns.width_exceed_policy = self.table.WEP_STRIP\n        string = \"\"\"+---+------+---+---+\n|   | name | r | g |\n+---+------+---+---+\n| S | Jaco | 1 | b |\n+---+------+---+---+\n| S | Isab | 1 | g |\n+---+------+---+---+\n| S | Etha | 2 | b |\n+---+------+---+---+\n| S | Soph | 2 | g |\n+---+------+---+---+\n| S | Mich | 3 | b |\n+---+------+---+---+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_wep_ellipsis(self):\n        self.create_table(20)\n        self.table.columns.width_exceed_policy = self.table.WEP_ELLIPSIS\n        string = \"\"\"+---+------+---+---+\n|   | name | . | . |\n+---+------+---+---+\n| . | J... | 1 | . |\n+---+------+---+---+\n| . | I... | 1 | . |\n+---+------+---+---+\n| . | E... | 2 | . |\n+---+------+---+---+\n| . | S... | 2 | . |\n+---+------+---+---+\n| . | M... | 3 | . |\n+---+------+---+---+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_empty_header(self):\n        self.table.columns.header = [\"\", \" \", \"  \"]\n        string = \"\"\"+----+----------+---+------+\n| S1 |  Jacob   | 1 | boy  |\n+----+----------+---+------+\n| S2 | Isabella | 1 | girl |\n+----+----------+---+------+\n| S3 |  Ethan   | 2 | boy  |\n+----+----------+---+------+\n| S4 |  Sophia  | 2 | girl |\n+----+----------+---+------+\n| S5 | Michael  | 3 | boy  |\n+----+----------+---+------+\"\"\"\n        self.assertEqual(string, str(self.table))\n\n    def test_eastasian_characters(self):\n        string = \"\"\"+----+------------+------+--------+\n|    |    name    | rank | gender |\n+----+------------+------+--------+\n| S1 |   Jacob    |  1   |  boy   |\n+----+------------+------+--------+\n| S2 |  Isabella  |  1   |  girl  |\n+----+------------+------+--------+\n| S3 |   Ethan    |  2   |  boy   |\n+----+------------+------+--------+\n| S4 |   Sophia   |  2   |  girl  |\n+----+------------+------+--------+\n| S5 |  Michael   |  3   |  boy   |\n+----+------------+------+--------+\n| S6 | こんにちは |  2   |  boy   |\n+----+------------+------+--------+\"\"\"\n        self.table.rows.append([\"こんにちは\", 2, \"boy\"], header=\"S6\")\n        self.assertEqual(string, str(self.table))\n\n    def test_newline(self):\n        string = \"\"\"+---+---+\n| 0 | a |\n|   | b |\n+---+---+\"\"\"\n        table = BeautifulTable()\n        table.rows.append([\"0\", \"a\\nb\"])\n        self.assertEqual(string, str(table))\n\n    def test_newline_multiple_columns(self):\n        string = \"\"\"+---+---+\n| a | p |\n| b | q |\n| c |   |\n+---+---+\"\"\"\n        table = BeautifulTable()\n        table.rows.append([\"a\\nb\\nc\", \"p\\nq\"])\n        self.assertEqual(string, str(table))\n\n    # Test for ANSI sequences\n\n    def test_ansi_sequences(self):\n        table = BeautifulTable()\n        string = \"\"\"+------+---+-----+\n| \\x1b[31mAdam\\x1b[0m | 2 | boy |\n+------+---+-----+\"\"\"\n        table.rows.append([\"\\x1b[31mAdam\\x1b[0m\", 2, \"boy\"])\n        self.assertEqual(string, str(table))\n\n    def test_ansi_wrap(self):\n        table = BeautifulTable(maxwidth=30)\n        string = \"\"\"+-----------------+---+------+\n| \\x1b[31mThis is a very \\x1b[0m | 2 | girl |\n|    \\x1b[32mlong name\\x1b[0m    |   |      |\n+-----------------+---+------+\"\"\"\n        long_string = \"\\x1b[31mThis is a very \\x1b[0m\\x1b[32mlong name\\x1b[0m\"\n        table.rows.append([long_string, 2, \"girl\"])\n        self.assertEqual(string, str(table))\n\n    def test_ansi_wrap_mb(self):\n        table = BeautifulTable(maxwidth=30)\n        string = \"\"\"+-----------------+---+------+\n| \\x1b[31mこれは非常に長\\x1b[0m  | 2 | girl |\n|   \\x1b[31mい\\x1b[0m\\x1b[32m名前です\\x1b[0m    |   |      |\n+-----------------+---+------+\"\"\"\n        long_string = \"\\x1b[31mこれは非常に長い\\x1b[0m\\x1b[32m名前です\\x1b[0m\"\n        table.rows.append([long_string, 2, \"girl\"])\n        self.assertEqual(string, str(table))\n\n    def test_ansi_ellipsis(self):\n        table = BeautifulTable(maxwidth=30)\n        table.columns.width_exceed_policy = table.WEP_ELLIPSIS\n        string = \"\"\"+-----------------+---+------+\n| \\x1b[31mThis is a ve\\x1b[0m... | 2 | girl |\n+-----------------+---+------+\"\"\"\n        long_string = \"\\x1b[31mThis is a very \\x1b[0m\\x1b[32mlong name\\x1b[0m\"\n        table.rows.append([long_string, 2, \"girl\"])\n        self.assertEqual(string, str(table))\n\n    def test_ansi_ellipsis_mb(self):\n        table = BeautifulTable(maxwidth=30)\n        table.columns.width_exceed_policy = table.WEP_ELLIPSIS\n        string = \"\"\"+-----------------+---+------+\n| \\x1b[31mこれは非常に\\x1b[0m... | 2 | girl |\n+-----------------+---+------+\"\"\"\n        long_string = \"\\x1b[31mこれは非常に長い\\x1b[0m\\x1b[32m名前です\\x1b[0m\"\n        table.rows.append([long_string, 2, \"girl\"])\n        self.assertEqual(string, str(table))\n\n    def test_ansi_strip(self):\n        table = BeautifulTable(maxwidth=30)\n        table.columns.width_exceed_policy = table.WEP_STRIP\n        string = \"\"\"+-----------------+---+------+\n| \\x1b[31mThis is a very \\x1b[0m | 2 | girl |\n+-----------------+---+------+\"\"\"\n        long_string = \"\\x1b[31mThis is a very \\x1b[0m\\x1b[32mlong name\\x1b[0m\"\n        table.rows.append([long_string, 2, \"girl\"])\n        self.assertEqual(string, str(table))\n\n    def test_ansi_strip_mb(self):\n        table = BeautifulTable(maxwidth=30)\n        table.columns.width_exceed_policy = table.WEP_STRIP\n        string = \"\"\"+-----------------+---+------+\n| \\x1b[31mこれは非常に長\\x1b[0m  | 2 | girl |\n+-----------------+---+------+\"\"\"\n        long_string = \"\\x1b[31mこれは非常に長い\\x1b[0m\\x1b[32m名前です\\x1b[0m\"\n        table.rows.append([long_string, 2, \"girl\"])\n        self.assertEqual(string, str(table))\n\n    # Test on empty table\n\n    def test_empty_table_by_column(self):\n        self.create_table(20)\n        for i in range(3):\n            self.table.columns.pop()\n        self.assertEqual(str(self.table), \"\")\n\n    def test_empty_table_by_row(self):\n        self.create_table(20)\n        for i in range(5):\n            self.table.rows.pop()\n        self.assertEqual(str(self.table), \"\")\n\n    def test_table_width_zero(self):\n        self.create_table(20)\n        self.table.clear(True)\n        self.assertEqual(self.table._width, 0)\n\n    def test_table_auto_width(self):\n        row_list = [\"abcdefghijklmopqrstuvwxyz\", 1234, \"none\"]\n\n        self.create_table(200)\n        self.table.rows.append(row_list)\n        len_for_max_width_200 = len(str(self.table))\n\n        self.create_table(80)\n        self.table.rows.append(row_list)\n        len_for_max_width_80 = len(str(self.table))\n\n        self.assertEqual(len_for_max_width_80, len_for_max_width_200)\n\n    def test_csv_export(self):\n        # Create csv files in path.\n        self.table.to_csv(\"beautiful_table.csv\")\n        self.table.to_csv(\"./docs/beautiful_table.csv\")\n\n        with self.assertRaises(ValueError):\n            self.table.to_csv(1)\n\n        # Check if csv files exist.\n        self.assertTrue(os.path.exists(\"beautiful_table.csv\"))\n        self.assertTrue(os.path.exists(\"./docs/beautiful_table.csv\"))\n\n        # Teardown step.\n        os.remove(\"beautiful_table.csv\")\n        os.remove(\"./docs/beautiful_table.csv\")\n\n    def test_csv_import(self):\n        # Export table as CSV file and import it back.\n        self.table.to_csv(\"beautiful_table.csv\")\n\n        test_table = BeautifulTable()\n        test_table.from_csv(\"beautiful_table.csv\")\n\n        with self.assertRaises(ValueError):\n            self.table.from_csv(1)\n\n        self.assertEqual(len(self.table.rows), len(test_table.rows))\n        self.assertEqual(self.table.columns.header, test_table.columns.header)\n\n        test_table = BeautifulTable()\n        test_table.from_csv(\"beautiful_table.csv\", header=False)\n        self.assertEqual(len(self.table.rows), len(test_table.rows) - 1)\n\n        # Teardown step.\n        os.remove(\"beautiful_table.csv\")\n\n    @unittest.skipUnless(PANDAS_INSTALLED, REQUIRED_PANDAS_MESSAGE)\n    def test_df_export(self):\n        df = self.table.to_df()\n        self.assertEqual(self.table.rows.header, df.index)\n        self.assertEqual(self.table.columns.header, list(df.columns))\n        self.assertEqual(\n            [list(row) for row in list(df.values)],\n            [list(row) for row in list(self.table._data)],\n        )\n\n    @unittest.skipUnless(PANDAS_INSTALLED, REQUIRED_PANDAS_MESSAGE)\n    def test_df_import(self):\n        df = self.create_dataframe()\n        table = BeautifulTable()\n        table = table.from_df(df)\n        self.assertEqual(table.rows.header, df.index)\n        self.assertEqual(table.columns.header, list(df.columns))\n        self.assertEqual(\n            [list(row) for row in list(df.values)],\n            [list(row) for row in list(table.rows)],\n        )\n\n    @unittest.skipUnless(PANDAS_INSTALLED, REQUIRED_PANDAS_MESSAGE)\n    def test_df_export_scenario1(self):\n        table = BeautifulTable()\n        table.rows.append([\"Jacob\", 1, \"boy\"])\n        table.rows.append([\"Isabella\", 2, \"girl\"])\n        df = table.to_df()\n        self.assertEqual(table.rows.header, [None, None])\n        self.assertEqual(table.columns.header, [None, None, None])\n        self.assertEqual(list(df.index), [0, 1])\n        self.assertEqual(list(df.columns), [0, 1, 2])\n\n    @unittest.skipUnless(PANDAS_INSTALLED, REQUIRED_PANDAS_MESSAGE)\n    def test_df_export_scenario2(self):\n        table = BeautifulTable()\n        table.rows.append([\"Jacob\", 1, \"boy\"])\n        table.rows.append([\"Isabella\", 2, \"girl\"])\n        table.columns.header = [None, \"rank\", \"gender\"]\n        df = table.to_df()\n        self.assertEqual(table.rows.header, [None, None])\n        self.assertEqual(table.columns.header, [None, \"rank\", \"gender\"])\n        self.assertEqual(list(df.index), [0, 1])\n        self.assertEqual(list(df.columns), [None, \"rank\", \"gender\"])\n\n\nif __name__ == \"__main__\":\n    unittest.main()\n"
  }
]