diff --git a/.clang-format b/.clang-format
deleted file mode 100644
index 96a12b2..0000000
--- a/.clang-format
+++ /dev/null
@@ -1,13 +0,0 @@
-BasedOnStyle: LLVM
-AlignConsecutiveMacros: AcrossEmptyLines
-AllowShortFunctionsOnASingleLine: Inline
-AlwaysBreakAfterReturnType: TopLevelDefinitions
-BinPackArguments: false
-BinPackParameters: false
-BreakBeforeBraces: Linux
-ColumnLimit: 88
-IndentPPDirectives: AfterHash
-IndentWidth: 4
-SpaceAfterCStyleCast: true
-StatementMacros:
-  - PyObject_HEAD
diff --git a/.coveragerc b/.coveragerc
deleted file mode 100644
index 909a0e2..0000000
--- a/.coveragerc
+++ /dev/null
@@ -1,8 +0,0 @@
-[report]
-exclude_lines =
-	pragma: no cover
-	raise NotImplementedError()
-partial_branches =
-    pragma: no branch
-    if py3k:
-    if not py3k:
diff --git a/.github/workflows/build-wheels.yml b/.github/workflows/build-wheels.yml
deleted file mode 100644
index 255c0f8..0000000
--- a/.github/workflows/build-wheels.yml
+++ /dev/null
@@ -1,68 +0,0 @@
-name: Build wheels
-
-on: push
-
-jobs:
-  build-linux:
-    runs-on: ubuntu-latest
-    steps:
-    - uses: actions/checkout@v2
-    - name: Set up QEMU
-      uses: docker/setup-qemu-action@v1
-    - name: Build manylinux1 x86-64 wheels
-      uses: earwig/python-wheels-manylinux-build@latest-manylinux1_x86_64
-      with:
-        python-versions: 'cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39'
-    - name: Build manylinux2014 x86-64 wheels
-      uses: earwig/python-wheels-manylinux-build@latest-manylinux2014_x86_64
-      with:
-        python-versions: 'cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39 cp310-cp310'
-    - name: Build manylinux 2014 aarch64 wheels
-      uses: earwig/python-wheels-manylinux-build@latest-manylinux2014_aarch64
-      with:
-        python-versions: 'cp36-cp36m cp37-cp37m cp38-cp38 cp39-cp39 cp310-cp310'
-    - uses: actions/upload-artifact@v2
-      with:
-        name: wheels
-        path: dist/*.whl
-    - name: Publish package to PyPI
-      # Only actually publish if a new tag was pushed
-      if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
-      uses: pypa/gh-action-pypi-publish@37e305e7413032d8422456179fee28fac7d25187
-      with:
-        user: __token__
-        password: ${{ secrets.pypi_password }}
-
-  build-macos:
-    runs-on: macos-latest
-    strategy:
-      matrix:
-        python-version:
-          - '3.6'
-          - '3.7'
-          - '3.8'
-          - '3.9'
-          - '3.10'
-    steps:
-    - uses: actions/checkout@v2
-    - uses: actions/setup-python@v2
-      with:
-        python-version: ${{ matrix.python-version }}
-    - name: Build wheels
-      run: |
-        python -m pip install --upgrade pip wheel setuptools
-        pip wheel . -w dist/
-        ls dist/
-    - uses: actions/upload-artifact@v2
-      with:
-        name: wheels
-        path: dist/*.whl
-    - name: Publish package to PyPI
-      # Only actually publish if a new tag was pushed
-      if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
-      # We can't use the pypa action because of https://github.com/pypa/gh-action-pypi-publish/issues/15
-      run: |
-        pip install twine
-        TWINE_USERNAME="__token__" \
-        TWINE_PASSWORD="${{ secrets.pypi_password }}" \
-        twine upload dist/*
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index b966a55..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,18 +0,0 @@
-*.pyc
-*.pyd
-*.so
-*.dll
-*.egg
-*.egg-info
-.coverage
-.eggs
-.DS_Store
-__pycache__
-build
-dist
-docs/_build
-scripts/*.log
-htmlcov/
-compile_commands.json
-.idea/
-.pytest_cache/
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
deleted file mode 100644
index daac892..0000000
--- a/.pre-commit-config.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-repos:
--   repo: https://github.com/psf/black
-    rev: 21.8b0
-    hooks:
-    -   id: black
--   repo: https://github.com/doublify/pre-commit-clang-format
-    rev: 62302476d0da01515660132d76902359bed0f782
-    hooks:
-    -   id: clang-format
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index babbf91..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,21 +0,0 @@
-dist: focal
-language: python
-python:
-    - 3.6
-    - 3.7
-    - 3.8
-    - 3.9
-arch:
-  - amd64
-  - ppc64le
-install:
-    - pip install coveralls pytest
-    - python setup.py develop
-script:
-    - coverage run --source=mwparserfromhell -m pytest
-after_success:
-    - coveralls
-env:
-  matrix:
-    - WITHOUT_EXTENSION=0
-    - WITHOUT_EXTENSION=1
diff --git a/CHANGELOG b/CHANGELOG
index 1b35cf4..d3e07cc 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,7 @@
+v0.7 (unreleased):
+
+- ...
+
 v0.6.4 (released February 14, 2022):
 
 - Dropped support for end-of-life Python 3.5.
diff --git a/PKG-INFO b/PKG-INFO
new file mode 100644
index 0000000..7769829
--- /dev/null
+++ b/PKG-INFO
@@ -0,0 +1,246 @@
+Metadata-Version: 2.1
+Name: mwparserfromhell
+Version: 0.7.dev0
+Summary: MWParserFromHell is a parser for MediaWiki wikicode.
+Home-page: https://github.com/earwig/mwparserfromhell
+Author: Ben Kurtovic
+Author-email: ben.kurtovic@gmail.com
+License: MIT License
+Download-URL: https://github.com/earwig/mwparserfromhell/tarball/v0.7.dev0
+Keywords: earwig mwparserfromhell wikipedia wiki mediawiki wikicode template parsing
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Topic :: Text Processing :: Markup
+Requires-Python: >= 3.6
+License-File: LICENSE
+
+mwparserfromhell
+================
+
+.. image:: https://api.travis-ci.com/earwig/mwparserfromhell.svg
+  :alt: Build Status
+  :target: https://travis-ci.org/earwig/mwparserfromhell
+
+.. image:: https://img.shields.io/coveralls/earwig/mwparserfromhell/main.svg
+  :alt: Coverage Status
+  :target: https://coveralls.io/r/earwig/mwparserfromhell
+
+**mwparserfromhell** (the *MediaWiki Parser from Hell*) is a Python package
+that provides an easy-to-use and outrageously powerful parser for MediaWiki_
+wikicode. It supports Python 3.5+.
+
+Developed by Earwig_ with contributions from `Σ`_, Legoktm_, and others.
+Full documentation is available on ReadTheDocs_. Development occurs on GitHub_.
+
+Installation
+------------
+
+The easiest way to install the parser is through the `Python Package Index`_;
+you can install the latest release with ``pip install mwparserfromhell``
+(`get pip`_). Make sure your pip is up-to-date first, especially on Windows.
+
+Alternatively, get the latest development version::
+
+    git clone https://github.com/earwig/mwparserfromhell.git
+    cd mwparserfromhell
+    python setup.py install
+
+The comprehensive unit testing suite requires `pytest`_ (``pip install pytest``)
+and can be run with ``python -m pytest``.
+
+Usage
+-----
+
+Normal usage is rather straightforward (where ``text`` is page text):
+
+>>> import mwparserfromhell
+>>> wikicode = mwparserfromhell.parse(text)
+
+``wikicode`` is a ``mwparserfromhell.Wikicode`` object, which acts like an
+ordinary ``str`` object with some extra methods. For example:
+
+>>> text = "I has a template! {{foo|bar|baz|eggs=spam}} See it?"
+>>> wikicode = mwparserfromhell.parse(text)
+>>> print(wikicode)
+I has a template! {{foo|bar|baz|eggs=spam}} See it?
+>>> templates = wikicode.filter_templates()
+>>> print(templates)
+['{{foo|bar|baz|eggs=spam}}']
+>>> template = templates[0]
+>>> print(template.name)
+foo
+>>> print(template.params)
+['bar', 'baz', 'eggs=spam']
+>>> print(template.get(1).value)
+bar
+>>> print(template.get("eggs").value)
+spam
+
+Since nodes can contain other nodes, getting nested templates is trivial:
+
+>>> text = "{{foo|{{bar}}={{baz|{{spam}}}}}}"
+>>> mwparserfromhell.parse(text).filter_templates()
+['{{foo|{{bar}}={{baz|{{spam}}}}}}', '{{bar}}', '{{baz|{{spam}}}}', '{{spam}}']
+
+You can also pass ``recursive=False`` to ``filter_templates()`` and explore
+templates manually. This is possible because nodes can contain additional
+``Wikicode`` objects:
+
+>>> code = mwparserfromhell.parse("{{foo|this {{includes a|template}}}}")
+>>> print(code.filter_templates(recursive=False))
+['{{foo|this {{includes a|template}}}}']
+>>> foo = code.filter_templates(recursive=False)[0]
+>>> print(foo.get(1).value)
+this {{includes a|template}}
+>>> print(foo.get(1).value.filter_templates()[0])
+{{includes a|template}}
+>>> print(foo.get(1).value.filter_templates()[0].get(1).value)
+template
+
+Templates can be easily modified to add, remove, or alter params. ``Wikicode``
+objects can be treated like lists, with ``append()``, ``insert()``,
+``remove()``, ``replace()``, and more. They also have a ``matches()`` method
+for comparing page or template names, which takes care of capitalization and
+whitespace:
+
+>>> text = "{{cleanup}} '''Foo''' is a [[bar]]. {{uncategorized}}"
+>>> code = mwparserfromhell.parse(text)
+>>> for template in code.filter_templates():
+...     if template.name.matches("Cleanup") and not template.has("date"):
+...         template.add("date", "July 2012")
+...
+>>> print(code)
+{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{uncategorized}}
+>>> code.replace("{{uncategorized}}", "{{bar-stub}}")
+>>> print(code)
+{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}
+>>> print(code.filter_templates())
+['{{cleanup|date=July 2012}}', '{{bar-stub}}']
+
+You can then convert ``code`` back into a regular ``str`` object (for
+saving the page!) by calling ``str()`` on it:
+
+>>> text = str(code)
+>>> print(text)
+{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}
+>>> text == code
+True
+
+Limitations
+-----------
+
+While the MediaWiki parser generates HTML and has access to the contents of
+templates, among other things, mwparserfromhell acts as a direct interface to
+the source code only. This has several implications:
+
+* Syntax elements produced by a template transclusion cannot be detected. For
+  example, imagine a hypothetical page ``"Template:End-bold"`` that contained
+  the text ``</b>``. While MediaWiki would correctly understand that
+  ``<b>foobar{{end-bold}}`` translates to ``<b>foobar</b>``, mwparserfromhell
+  has no way of examining the contents of ``{{end-bold}}``. Instead, it would
+  treat the bold tag as unfinished, possibly extending further down the page.
+
+* Templates adjacent to external links, as in ``http://example.com{{foo}}``,
+  are considered part of the link. In reality, this would depend on the
+  contents of the template.
+
+* When different syntax elements cross over each other, as in
+  ``{{echo|''Hello}}, world!''``, the parser gets confused because this cannot
+  be represented by an ordinary syntax tree. Instead, the parser will treat the
+  first syntax construct as plain text. In this case, only the italic tag would
+  be properly parsed.
+
+  **Workaround:** Since this commonly occurs with text formatting and text
+  formatting is often not of interest to users, you may pass
+  *skip_style_tags=True* to ``mwparserfromhell.parse()``. This treats ``''``
+  and ``'''`` as plain text.
+
+  A future version of mwparserfromhell may include multiple parsing modes to
+  get around this restriction more sensibly.
+
+Additionally, the parser lacks awareness of certain wiki-specific settings:
+
+* `Word-ending links`_ are not supported, since the linktrail rules are
+  language-specific.
+
+* Localized namespace names aren't recognized, so file links (such as
+  ``[[File:...]]``) are treated as regular wikilinks.
+
+* Anything that looks like an XML tag is treated as a tag, even if it is not a
+  recognized tag name, since the list of valid tags depends on loaded MediaWiki
+  extensions.
+
+Integration
+-----------
+
+``mwparserfromhell`` is used by and originally developed for EarwigBot_;
+``Page`` objects have a ``parse`` method that essentially calls
+``mwparserfromhell.parse()`` on ``page.get()``.
+
+If you're using Pywikibot_, your code might look like this:
+
+.. code-block:: python
+
+    import mwparserfromhell
+    import pywikibot
+
+    def parse(title):
+        site = pywikibot.Site()
+        page = pywikibot.Page(site, title)
+        text = page.get()
+        return mwparserfromhell.parse(text)
+
+If you're not using a library, you can parse any page with the following
+Python 3 code (using the API_ and the requests_ library):
+
+.. code-block:: python
+
+    import mwparserfromhell
+    import requests
+
+    API_URL = "https://en.wikipedia.org/w/api.php"
+
+    def parse(title):
+        params = {
+            "action": "query",
+            "prop": "revisions",
+            "rvprop": "content",
+            "rvslots": "main",
+            "rvlimit": 1,
+            "titles": title,
+            "format": "json",
+            "formatversion": "2",
+        }
+        headers = {"User-Agent": "My-Bot-Name/1.0"}
+        req = requests.get(API_URL, headers=headers, params=params)
+        res = req.json()
+        revision = res["query"]["pages"][0]["revisions"][0]
+        text = revision["slots"]["main"]["content"]
+        return mwparserfromhell.parse(text)
+
+.. _MediaWiki:              https://www.mediawiki.org
+.. _ReadTheDocs:            https://mwparserfromhell.readthedocs.io
+.. _Earwig:                 https://en.wikipedia.org/wiki/User:The_Earwig
+.. _Σ:                      https://en.wikipedia.org/wiki/User:%CE%A3
+.. _Legoktm:                https://en.wikipedia.org/wiki/User:Legoktm
+.. _GitHub:                 https://github.com/earwig/mwparserfromhell
+.. _Python Package Index:   https://pypi.org/
+.. _get pip:                https://pypi.org/project/pip/
+.. _pytest:                 https://docs.pytest.org/
+.. _Word-ending links:      https://www.mediawiki.org/wiki/Help:Links#linktrail
+.. _EarwigBot:              https://github.com/earwig/earwigbot
+.. _Pywikibot:              https://www.mediawiki.org/wiki/Manual:Pywikibot
+.. _API:                    https://www.mediawiki.org/wiki/API:Main_page
+.. _requests:               https://2.python-requests.org
+
+
diff --git a/README.rst b/README.rst
index 8f59561..44f1c8d 100644
--- a/README.rst
+++ b/README.rst
@@ -1,11 +1,11 @@
 mwparserfromhell
 ================
 
-.. image:: https://api.travis-ci.com/earwig/mwparserfromhell.svg?branch=develop
+.. image:: https://api.travis-ci.com/earwig/mwparserfromhell.svg
   :alt: Build Status
   :target: https://travis-ci.org/earwig/mwparserfromhell
 
-.. image:: https://img.shields.io/coveralls/earwig/mwparserfromhell/develop.svg
+.. image:: https://img.shields.io/coveralls/earwig/mwparserfromhell/main.svg
   :alt: Coverage Status
   :target: https://coveralls.io/r/earwig/mwparserfromhell
 
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 56acc42..0000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,79 +0,0 @@
-# This config file is used by appveyor.com to build Windows release binaries
-
-version: 0.6.4-b{build}
-
-branches:
-  only:
-    - master
-    - develop
-
-skip_tags: true
-
-image: Visual Studio 2019
-
-environment:
-  global:
-    # See: http://stackoverflow.com/a/13751649/163740
-    WRAPPER: "cmd /E:ON /V:ON /C .\\scripts\\win_wrapper.cmd"
-    PYEXE:   "%WRAPPER% %PYTHON%\\python.exe"
-    SETUPPY: "%PYEXE% setup.py --with-extension"
-    PIP:     "%PYEXE% -m pip"
-    TWINE:   "%PYEXE% -m twine"
-    PYPI_USERNAME: "earwigbot"
-    PYPI_PASSWORD:
-      secure: gOIcvPxSC2ujuhwOzwj3v8xjq3CCYd8keFWVnguLM+gcL0e02qshDHy7gwZZwj0+
-
-  matrix:
-    - PYTHON:         "C:\\Python36"
-      PYTHON_VERSION: "3.6"
-      PYTHON_ARCH:    "32"
-
-    - PYTHON:         "C:\\Python36-x64"
-      PYTHON_VERSION: "3.6"
-      PYTHON_ARCH:    "64"
-
-    - PYTHON:         "C:\\Python37"
-      PYTHON_VERSION: "3.7"
-      PYTHON_ARCH:    "32"
-
-    - PYTHON:         "C:\\Python37-x64"
-      PYTHON_VERSION: "3.7"
-      PYTHON_ARCH:    "64"
-
-    - PYTHON:         "C:\\Python38"
-      PYTHON_VERSION: "3.8"
-      PYTHON_ARCH:    "32"
-
-    - PYTHON:         "C:\\Python38-x64"
-      PYTHON_VERSION: "3.8"
-      PYTHON_ARCH:    "64"
-
-    - PYTHON:         "C:\\Python39"
-      PYTHON_VERSION: "3.9"
-      PYTHON_ARCH:    "32"
-
-    - PYTHON:         "C:\\Python39-x64"
-      PYTHON_VERSION: "3.9"
-      PYTHON_ARCH:    "64"
-
-install:
-  - "%PIP% install --disable-pip-version-check --user --upgrade pip"
-  - "%PIP% install wheel twine pytest"
-
-build_script:
-  - "%SETUPPY% build"
-  - "%SETUPPY% develop --user"
-
-test_script:
-  - "%PYEXE% -m pytest"
-
-after_test:
-  - "%SETUPPY% bdist_wheel"
-
-on_success:
-  - "IF %APPVEYOR_REPO_BRANCH%==master %TWINE% upload dist\\* -u %PYPI_USERNAME% -p %PYPI_PASSWORD%"
-
-artifacts:
-  - path: dist\*
-
-deploy: off
diff --git a/docs/Makefile b/docs/Makefile
deleted file mode 100644
index c1ec497..0000000
--- a/docs/Makefile
+++ /dev/null
@@ -1,153 +0,0 @@
-# Makefile for Sphinx documentation
-#
-
-# You can set these variables from the command line.
-SPHINXOPTS    =
-SPHINXBUILD   = sphinx-build
-PAPER         =
-BUILDDIR      = _build
-
-# Internal variables.
-PAPEROPT_a4     = -D latex_paper_size=a4
-PAPEROPT_letter = -D latex_paper_size=letter
-ALLSPHINXOPTS   = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-# the i18n builder cannot share the environment and doctrees with the others
-I18NSPHINXOPTS  = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
-
-.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
-
-help:
-	@echo "Please use \`make <target>' where <target> is one of"
-	@echo "  html       to make standalone HTML files"
-	@echo "  dirhtml    to make HTML files named index.html in directories"
-	@echo "  singlehtml to make a single large HTML file"
-	@echo "  pickle     to make pickle files"
-	@echo "  json       to make JSON files"
-	@echo "  htmlhelp   to make HTML files and a HTML help project"
-	@echo "  qthelp     to make HTML files and a qthelp project"
-	@echo "  devhelp    to make HTML files and a Devhelp project"
-	@echo "  epub       to make an epub"
-	@echo "  latex      to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
-	@echo "  latexpdf   to make LaTeX files and run them through pdflatex"
-	@echo "  text       to make text files"
-	@echo "  man        to make manual pages"
-	@echo "  texinfo    to make Texinfo files"
-	@echo "  info       to make Texinfo files and run them through makeinfo"
-	@echo "  gettext    to make PO message catalogs"
-	@echo "  changes    to make an overview of all changed/added/deprecated items"
-	@echo "  linkcheck  to check all external links for integrity"
-	@echo "  doctest    to run all doctests embedded in the documentation (if enabled)"
-
-clean:
-	-rm -rf $(BUILDDIR)/*
-
-html:
-	$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
-	@echo
-	@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
-
-dirhtml:
-	$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
-	@echo
-	@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
-
-singlehtml:
-	$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
-	@echo
-	@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
-
-pickle:
-	$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
-	@echo
-	@echo "Build finished; now you can process the pickle files."
-
-json:
-	$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
-	@echo
-	@echo "Build finished; now you can process the JSON files."
-
-htmlhelp:
-	$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
-	@echo
-	@echo "Build finished; now you can run HTML Help Workshop with the" \
-	      ".hhp project file in $(BUILDDIR)/htmlhelp."
-
-qthelp:
-	$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
-	@echo
-	@echo "Build finished; now you can run "qcollectiongenerator" with the" \
-	      ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
-	@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/mwparserfromhell.qhcp"
-	@echo "To view the help file:"
-	@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/mwparserfromhell.qhc"
-
-devhelp:
-	$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
-	@echo
-	@echo "Build finished."
-	@echo "To view the help file:"
-	@echo "# mkdir -p $$HOME/.local/share/devhelp/mwparserfromhell"
-	@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/mwparserfromhell"
-	@echo "# devhelp"
-
-epub:
-	$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
-	@echo
-	@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
-
-latex:
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-	@echo
-	@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
-	@echo "Run \`make' in that directory to run these through (pdf)latex" \
-	      "(use \`make latexpdf' here to do that automatically)."
-
-latexpdf:
-	$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
-	@echo "Running LaTeX files through pdflatex..."
-	$(MAKE) -C $(BUILDDIR)/latex all-pdf
-	@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
-
-text:
-	$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
-	@echo
-	@echo "Build finished. The text files are in $(BUILDDIR)/text."
-
-man:
-	$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
-	@echo
-	@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
-
-texinfo:
-	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-	@echo
-	@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
-	@echo "Run \`make' in that directory to run these through makeinfo" \
-	      "(use \`make info' here to do that automatically)."
-
-info:
-	$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
-	@echo "Running Texinfo files through makeinfo..."
-	make -C $(BUILDDIR)/texinfo info
-	@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
-
-gettext:
-	$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
-	@echo
-	@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
-
-changes:
-	$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
-	@echo
-	@echo "The overview file is in $(BUILDDIR)/changes."
-
-linkcheck:
-	$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
-	@echo
-	@echo "Link check complete; look for any errors in the above output " \
-	      "or in $(BUILDDIR)/linkcheck/output.txt."
-
-doctest:
-	$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
-	@echo "Testing of doctests in the sources finished, look at the " \
-	      "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/api/modules.rst b/docs/api/modules.rst
deleted file mode 100644
index 05d6516..0000000
--- a/docs/api/modules.rst
+++ /dev/null
@@ -1,7 +0,0 @@
-mwparserfromhell
-================
-
-.. toctree::
-   :maxdepth: 6
-
-   mwparserfromhell
diff --git a/docs/api/mwparserfromhell.nodes.extras.rst b/docs/api/mwparserfromhell.nodes.extras.rst
deleted file mode 100644
index 44f940e..0000000
--- a/docs/api/mwparserfromhell.nodes.extras.rst
+++ /dev/null
@@ -1,25 +0,0 @@
-extras Package
-==============
-
-:mod:`extras` Package
----------------------
-
-.. automodule:: mwparserfromhell.nodes.extras
-    :members:
-    :undoc-members:
-
-:mod:`attribute` Module
------------------------
-
-.. automodule:: mwparserfromhell.nodes.extras.attribute
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`parameter` Module
------------------------
-
-.. automodule:: mwparserfromhell.nodes.extras.parameter
-    :members:
-    :undoc-members:
-    :show-inheritance:
diff --git a/docs/api/mwparserfromhell.nodes.rst b/docs/api/mwparserfromhell.nodes.rst
deleted file mode 100644
index 38058f2..0000000
--- a/docs/api/mwparserfromhell.nodes.rst
+++ /dev/null
@@ -1,97 +0,0 @@
-nodes Package
-=============
-
-:mod:`nodes` Package
---------------------
-
-.. automodule:: mwparserfromhell.nodes
-
-.. autoclass:: mwparserfromhell.nodes.Node
-    :special-members:
-
-:mod:`_base` Module
-----------------------
-
-.. automodule:: mwparserfromhell.nodes._base
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`argument` Module
-----------------------
-
-.. automodule:: mwparserfromhell.nodes.argument
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`comment` Module
----------------------
-
-.. automodule:: mwparserfromhell.nodes.comment
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`external_link` Module
----------------------------
-
-.. automodule:: mwparserfromhell.nodes.external_link
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`heading` Module
----------------------
-
-.. automodule:: mwparserfromhell.nodes.heading
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`html_entity` Module
--------------------------
-
-.. automodule:: mwparserfromhell.nodes.html_entity
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`tag` Module
------------------
-
-.. automodule:: mwparserfromhell.nodes.tag
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`template` Module
-----------------------
-
-.. automodule:: mwparserfromhell.nodes.template
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`text` Module
-------------------
-
-.. automodule:: mwparserfromhell.nodes.text
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-:mod:`wikilink` Module
-----------------------
-
-.. automodule:: mwparserfromhell.nodes.wikilink
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-Subpackages
------------
-
-.. toctree::
-
-    mwparserfromhell.nodes.extras
diff --git a/docs/api/mwparserfromhell.parser.rst b/docs/api/mwparserfromhell.parser.rst
deleted file mode 100644
index 72ee9eb..0000000
--- a/docs/api/mwparserfromhell.parser.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-parser Package
-==============
-
-:mod:`parser` Package
----------------------
-
-.. automodule:: mwparserfromhell.parser
-    :members:
-    :undoc-members:
-
-:mod:`builder` Module
----------------------
-
-.. automodule:: mwparserfromhell.parser.builder
-    :members:
-    :undoc-members:
-    :private-members:
-
-:mod:`contexts` Module
-----------------------
-
-.. automodule:: mwparserfromhell.parser.contexts
-    :members:
-    :undoc-members:
-
-:mod:`errors` Module
---------------------
-
-.. automodule:: mwparserfromhell.parser.errors
-    :members:
-    :undoc-members:
-
-:mod:`tokenizer` Module
------------------------
-
-.. automodule:: mwparserfromhell.parser.tokenizer
-    :members:
-    :undoc-members:
-    :private-members:
-
-.. autoexception:: mwparserfromhell.parser.tokenizer.BadRoute
-
-:mod:`tokens` Module
---------------------
-
-.. automodule:: mwparserfromhell.parser.tokens
-    :members:
-    :undoc-members:
diff --git a/docs/api/mwparserfromhell.rst b/docs/api/mwparserfromhell.rst
deleted file mode 100644
index c0bdc88..0000000
--- a/docs/api/mwparserfromhell.rst
+++ /dev/null
@@ -1,46 +0,0 @@
-mwparserfromhell Package
-========================
-
-:mod:`mwparserfromhell` Package
--------------------------------
-
-.. automodule:: mwparserfromhell.__init__
-    :members:
-    :undoc-members:
-
-:mod:`definitions` Module
--------------------------
-
-.. automodule:: mwparserfromhell.definitions
-    :members:
-
-:mod:`string_mixin` Module
---------------------------
-
-.. automodule:: mwparserfromhell.string_mixin
-    :members:
-    :undoc-members:
-
-:mod:`utils` Module
--------------------
-
-.. automodule:: mwparserfromhell.utils
-    :members:
-    :undoc-members:
-
-:mod:`wikicode` Module
-----------------------
-
-.. automodule:: mwparserfromhell.wikicode
-    :members:
-    :undoc-members:
-    :show-inheritance:
-
-Subpackages
------------
-
-.. toctree::
-
-    mwparserfromhell.nodes
-    mwparserfromhell.parser
-    mwparserfromhell.smart_list
diff --git a/docs/api/mwparserfromhell.smart_list.rst b/docs/api/mwparserfromhell.smart_list.rst
deleted file mode 100644
index 9312374..0000000
--- a/docs/api/mwparserfromhell.smart_list.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-smart_list Package
-==================
-
-:mod:`smart_list` Package
--------------------------
-
-.. automodule:: mwparserfromhell.smart_list
-    :members:
-    :undoc-members:
-
-:mod:`list_proxy` Module
----------------------
-
-.. automodule:: mwparserfromhell.smart_list.list_proxy
-    :members:
-    :undoc-members:
-
-:mod:`smart_list` Module
----------------------
-
-.. automodule:: mwparserfromhell.smart_list.smart_list
-    :members:
-    :undoc-members:
-
-:mod:`utils` Module
----------------------
-
-.. automodule:: mwparserfromhell.smart_list.utils
-    :members:
-    :undoc-members:
diff --git a/docs/changelog.rst b/docs/changelog.rst
deleted file mode 100644
index 1c303ad..0000000
--- a/docs/changelog.rst
+++ /dev/null
@@ -1,393 +0,0 @@
-Changelog
-=========
-
-v0.6.4
-------
-
-`Released February 14, 2022 <https://github.com/earwig/mwparserfromhell/tree/v0.6.4>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.6.3...v0.6.4>`__):
-
-- Dropped support for end-of-life Python 3.5.
-- Added support for Python 3.10.
-  (`#278 <https://github.com/earwig/mwparserfromhell/issues/278>`_)
-- Fixed a regression in v0.6.2 that broke parsing of nested wikilinks in file
-  captions. For now, the parser will handle interpret wikilinks in normal links
-  as well, even though this differs from MediaWiki.
-  (`#270 <https://github.com/earwig/mwparserfromhell/issues/270>`_)
-
-v0.6.3
-------
-
-`Released September 2, 2021 <https://github.com/earwig/mwparserfromhell/tree/v0.6.3>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.6.2...v0.6.3>`__):
-
-- Added Linux AArch64 wheels.
-  (`#276 <https://github.com/earwig/mwparserfromhell/issues/276>`_)
-- Fixed C integer conversion, manifesting as parsing errors on big-endian
-  platforms.
-  (`#277 <https://github.com/earwig/mwparserfromhell/issues/277>`_)
-
-v0.6.2
-------
-
-`Released May 16, 2021 <https://github.com/earwig/mwparserfromhell/tree/v0.6.2>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.6...v0.6.2>`__):
-
-- Improved parsing of external links.
-  (`#232 <https://github.com/earwig/mwparserfromhell/issues/232>`_)
-- Fixed parsing of nested wikilinks.
-- Ported tests to pytest.
-  (`#237 <https://github.com/earwig/mwparserfromhell/issues/237>`_)
-- Moved mwparserfromhell package to src/ dir.
-- There was no 0.6.1 release due to a packaging error.
-
-v0.6
-----
-
-`Released December 21, 2020 <https://github.com/earwig/mwparserfromhell/tree/v0.6>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.5.4...v0.6>`__):
-
-Thanks to everyone for their patience with this release!
-
-- Breaking change: dropped support for end-of-life Python 2.7 and 3.4.
-- Added support for Python 3.8 and 3.9.
-- Added binary wheels for Linux and macOS.
-- Updated :meth:`.Wikicode.matches` to recognize underscores as being
-  equivalent to spaces.
-  (`#216 <https://github.com/earwig/mwparserfromhell/issues/216>`_)
-- Added a `default` parameter to :meth:`.Template.get`, and implement dict-style
-  item access for template parameters.
-  (`#252 <https://github.com/earwig/mwparserfromhell/issues/252>`_)
-- Fixed a rare parsing bug involving deeply nested style tags.
-  (`#224 <https://github.com/earwig/mwparserfromhell/issues/224>`_)
-- Fixed parsing of section headings inside templates.
-  (`#233 <https://github.com/earwig/mwparserfromhell/issues/233>`_)
-- Updated HTML tag definitions.
-- Internal refactoring and cleanup.
-
-v0.5.4
-------
-
-`Released May 15, 2019 <https://github.com/earwig/mwparserfromhell/tree/v0.5.4>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.5.3...v0.5.4>`__):
-
-- Fixed an unlikely crash in the C tokenizer when interrupted while parsing
-  a heading.
-
-v0.5.3
-------
-
-`Released March 30, 2019 <https://github.com/earwig/mwparserfromhell/tree/v0.5.3>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.5.2...v0.5.3>`__):
-
-- Fixed manual construction of Node objects, previously unsupported.
-  (`#214 <https://github.com/earwig/mwparserfromhell/issues/214>`_)
-- Fixed :class:`.Wikicode` transformation methods (:meth:`.Wikicode.replace`,
-  :meth:`.Wikicode.remove`, etc.) when passed an empty section as an argument.
-  (`#212 <https://github.com/earwig/mwparserfromhell/issues/212>`_)
-- Fixed the parser getting stuck inside malformed tables.
-  (`#206 <https://github.com/earwig/mwparserfromhell/issues/206>`_)
-
-v0.5.2
-------
-
-`Released November 1, 2018 <https://github.com/earwig/mwparserfromhell/tree/v0.5.2>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.5.1...v0.5.2>`__):
-
-- Dropped support for end-of-life Python versions 2.6, 3.2, 3.3.
-  (`#199 <https://github.com/earwig/mwparserfromhell/issues/199>`_,
-  `#204 <https://github.com/earwig/mwparserfromhell/pull/204>`_)
-- Fixed signals getting stuck inside the C tokenizer until parsing finishes,
-  in pathological cases.
-  (`#206 <https://github.com/earwig/mwparserfromhell/issues/206>`_)
-- Fixed `<wbr>` not being considered a single-only tag.
-  (`#200 <https://github.com/earwig/mwparserfromhell/pull/200>`_)
-- Fixed a C tokenizer crash on Python 3.7 when compiled with assertions.
-  (`#208 <https://github.com/earwig/mwparserfromhell/issues/208>`_)
-- Cleaned up some minor documentation issues.
-  (`#207 <https://github.com/earwig/mwparserfromhell/pull/207>`_)
-
-v0.5.1
-------
-
-`Released March 3, 2018 <https://github.com/earwig/mwparserfromhell/tree/v0.5.1>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.5...v0.5.1>`__):
-
-- Improved behavior when adding parameters to templates (via
-  :meth:`.Template.add`) with poorly formatted whitespace conventions.
-  (`#185 <https://github.com/earwig/mwparserfromhell/issues/185>`_)
-- Fixed the parser getting stuck in deeply nested HTML tags with unclosed,
-  quoted attributes.
-  (`#190 <https://github.com/earwig/mwparserfromhell/issues/190>`_)
-
-v0.5
-----
-
-`Released June 23, 2017 <https://github.com/earwig/mwparserfromhell/tree/v0.5>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.4.4...v0.5>`__):
-
-- Added :meth:`.Wikicode.contains` to determine whether a :class:`.Node` or
-  :class:`.Wikicode` object is contained within another :class:`.Wikicode`
-  object.
-- Added :meth:`.Wikicode.get_ancestors` and :meth:`.Wikicode.get_parent` to
-  find all ancestors and the direct parent of a :class:`.Node`, respectively.
-- Fixed a long-standing performance issue with deeply nested, invalid syntax
-  (`issue #42 <https://github.com/earwig/mwparserfromhell/issues/42>`_). The
-  parser should be much faster on certain complex pages. The "max cycle"
-  restriction has also been removed, so some situations where templates at the
-  end of a page were being skipped are now resolved.
-- Made :meth:`Template.remove(keep_field=True) <.Template.remove>` behave more
-  reasonably when the parameter is already empty.
-- Added the *keep_template_params* argument to :meth:`.Wikicode.strip_code`.
-  If *True*, then template parameters will be preserved in the output.
-- :class:`.Wikicode` objects can now be pickled properly (fixed infinite
-  recursion error on incompletely-constructed :class:`.StringMixIn`
-  subclasses).
-- Fixed :meth:`.Wikicode.matches`\ 's behavior on iterables besides lists and
-  tuples.
-- Fixed ``len()`` sometimes raising ``ValueError`` on empty node lists.
-- Fixed a rare parsing bug involving self-closing tags inside the attributes of
-  unpaired tags.
-- Fixed release script after changes to PyPI.
-
-v0.4.4
-------
-
-`Released December 30, 2016 <https://github.com/earwig/mwparserfromhell/tree/v0.4.4>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.4.3...v0.4.4>`__):
-
-- Added support for Python 3.6.
-- Fixed parsing bugs involving:
-
-  - wikitables nested in templates;
-  - wikitable error recovery when unable to recurse;
-  - templates nested in template parameters before other parameters.
-
-- Fixed parsing file-like objects.
-- Made builds deterministic.
-- Documented caveats.
-
-v0.4.3
-------
-
-`Released October 29, 2015 <https://github.com/earwig/mwparserfromhell/tree/v0.4.3>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.4.2...v0.4.3>`__):
-
-- Added Windows binaries for Python 3.5.
-- Fixed edge cases involving wikilinks inside of external links and vice versa.
-- Fixed a C tokenizer crash when a keyboard interrupt happens while parsing.
-
-v0.4.2
-------
-
-`Released July 30, 2015 <https://github.com/earwig/mwparserfromhell/tree/v0.4.2>`__
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.4.1...v0.4.2>`__):
-
-- Fixed setup script not including header files in releases.
-- Fixed Windows binary uploads.
-
-v0.4.1
-------
-
-`Released July 30, 2015 <https://github.com/earwig/mwparserfromhell/tree/v0.4.1>`__
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.4...v0.4.1>`__):
-
-- The process for building Windows binaries has been fixed, and these should be
-  distributed along with new releases. Windows users can now take advantage of
-  C speedups without having a compiler of their own.
-- Added support for Python 3.5.
-- ``<`` and ``>`` are now disallowed in wikilink titles and template names.
-  This includes when denoting tags, but not comments.
-- Fixed the behavior of *preserve_spacing* in :meth:`.Template.add` and
-  *keep_field* in :meth:`.Template.remove` on parameters with hidden keys.
-- Removed :meth:`._ListProxy.detach`. :class:`.SmartList`\ s now use weak
-  references and their children are garbage-collected properly.
-- Fixed parser bugs involving:
-
-  - templates with completely blank names;
-  - templates with newlines and comments.
-
-- Heavy refactoring and fixes to the C tokenizer, including:
-
-  - corrected a design flaw in text handling, allowing for substantial speed
-    improvements when parsing long strings of plain text;
-  - implemented new Python 3.3
-    `PEP 393 <https://www.python.org/dev/peps/pep-0393/>`_ Unicode APIs.
-
-- Fixed various bugs in :class:`.SmartList`, including one that was causing
-  memory issues on 64-bit builds of Python 2 on Windows.
-- Fixed some bugs in the release scripts.
-
-v0.4
-----
-
-`Released May 23, 2015 <https://github.com/earwig/mwparserfromhell/tree/v0.4>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.3.3...v0.4>`__):
-
-- The parser now falls back on pure Python mode if C extensions cannot be
-  built. This fixes an issue that prevented some Windows users from installing
-  the parser.
-- Added support for parsing wikicode tables (patches by David Winegar).
-- Added a script to test for memory leaks in :file:`scripts/memtest.py`.
-- Added a script to do releases in :file:`scripts/release.sh`.
-- *skip_style_tags* can now be passed to :func:`mwparserfromhell.parse()
-  <.parse_anything>` (previously, only :meth:`.Parser.parse` allowed it).
-- The *recursive* argument to :class:`Wikicode's <.Wikicode>` :meth:`.filter`
-  methods now accepts a third option, ``RECURSE_OTHERS``, which recurses over
-  all children except instances of *forcetype* (for example,
-  ``code.filter_templates(code.RECURSE_OTHERS)`` returns all un-nested
-  templates).
-- The parser now understands HTML tag attributes quoted with single quotes.
-  When setting a tag attribute's value, quotes will be added if necessary. As
-  part of this, :class:`.Attribute`\ 's :attr:`~.Attribute.quoted` attribute
-  has been changed to :attr:`~.Attribute.quotes`, and is now either a string or
-  ``None``.
-- Calling :meth:`.Template.remove` with a :class:`.Parameter` object that is
-  not part of the template now raises :exc:`ValueError` instead of doing
-  nothing.
-- :class:`.Parameter`\ s with non-integer keys can no longer be created with
-  *showkey=False*, nor have the value of this attribute be set to *False*
-  later.
-- :meth:`._ListProxy.destroy` has been changed to :meth:`._ListProxy.detach`,
-  and now works in a more useful way.
-- If something goes wrong while parsing, :exc:`.ParserError` will now be
-  raised. Previously, the parser would produce an unclear :exc:`.BadRoute`
-  exception or allow an incorrect node tree to be build.
-- Fixed parser bugs involving:
-
-  - nested tags;
-  - comments in template names;
-  - tags inside of ``<nowiki>`` tags.
-
-- Added tests to ensure that parsed trees convert back to wikicode without
-  unintentional modifications.
-- Added support for a :envvar:`NOWEB` environment variable, which disables a
-  unit test that makes a web call.
-- Test coverage has been improved, and some minor related bugs have been fixed.
-- Updated and fixed some documentation.
-
-v0.3.3
-------
-
-`Released April 22, 2014 <https://github.com/earwig/mwparserfromhell/tree/v0.3.3>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.3.2...v0.3.3>`__):
-
-- Added support for Python 2.6 and 3.4.
-- :meth:`.Template.has` is now passed *ignore_empty=False* by default
-  instead of *True*. This fixes a bug when adding parameters to templates with
-  empty fields, **and is a breaking change if you rely on the default
-  behavior.**
-- The *matches* argument of :class:`Wikicode's <.Wikicode>` :meth:`.filter`
-  methods now accepts a function (taking one argument, a :class:`.Node`, and
-  returning a bool) in addition to a regex.
-- Re-added *flat* argument to :meth:`.Wikicode.get_sections`, fixed the order
-  in which it returns sections, and made it faster.
-- :meth:`.Wikicode.matches` now accepts a tuple or list of
-  strings/:class:`.Wikicode` objects instead of just a single string or
-  :class:`.Wikicode`.
-- Given the frequency of issues with the (admittedly insufficient) tag parser,
-  there's a temporary *skip_style_tags* argument to :meth:`~.Parser.parse` that
-  ignores ``''`` and ``'''`` until these issues are corrected.
-- Fixed a parser bug involving nested wikilinks and external links.
-- C code cleanup and speed improvements.
-
-v0.3.2
-------
-
-`Released September 1, 2013 <https://github.com/earwig/mwparserfromhell/tree/v0.3.2>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.3.1...v0.3.2>`__):
-
-- Added support for Python 3.2 (along with current support for 3.3 and 2.7).
-- Renamed :meth:`.Template.remove`\ 's first argument from *name* to *param*,
-  which now accepts :class:`.Parameter` objects in addition to parameter name
-  strings.
-
-v0.3.1
-------
-
-`Released August 29, 2013 <https://github.com/earwig/mwparserfromhell/tree/v0.3.1>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.3...v0.3.1>`__):
-
-- Fixed a parser bug involving URLs nested inside other markup.
-- Fixed some typos.
-
-v0.3
-----
-
-`Released August 24, 2013 <https://github.com/earwig/mwparserfromhell/tree/v0.3>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.2...v0.3>`__):
-
-- Added complete support for HTML :class:`Tags <.Tag>`, including forms like
-  ``<ref>foo</ref>``, ``<ref name="bar"/>``, and wiki-markup tags like bold
-  (``'''``), italics (``''``), and lists (``*``, ``#``, ``;`` and ``:``).
-- Added support for :class:`.ExternalLink`\ s (``http://example.com/`` and
-  ``[http://example.com/ Example]``).
-- :class:`Wikicode's <.Wikicode>` :meth:`.filter` methods are now passed
-  *recursive=True* by default instead of *False*. **This is a breaking change
-  if you rely on any filter() methods being non-recursive by default.**
-- Added a :meth:`.matches` method to :class:`.Wikicode` for page/template name
-  comparisons.
-- The *obj* param of :meth:`.Wikicode.insert_before`, :meth:`.insert_after`,
-  :meth:`~.Wikicode.replace`, and :meth:`~.Wikicode.remove` now accepts
-  :class:`.Wikicode` objects and strings representing parts of wikitext,
-  instead of just nodes. These methods also make all possible substitutions
-  instead of just one.
-- Renamed :meth:`.Template.has_param` to :meth:`~.Template.has` for consistency
-  with :class:`.Template`\ 's other methods; :meth:`.has_param` is now an
-  alias.
-- The C tokenizer extension now works on Python 3 in addition to Python 2.7.
-- Various bugfixes, internal changes, and cleanup.
-
-v0.2
-----
-
-`Released June 20, 2013 <https://github.com/earwig/mwparserfromhell/tree/v0.2>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.1.1...v0.2>`__):
-
-- The parser now fully supports Python 3 in addition to Python 2.7.
-- Added a C tokenizer extension that is significantly faster than its Python
-  equivalent. It is enabled by default (if available) and can be toggled by
-  setting :attr:`mwparserfromhell.parser.use_c` to a boolean value.
-- Added a complete set of unit tests covering parsing and wikicode
-  manipulation.
-- Renamed :meth:`.filter_links` to :meth:`.filter_wikilinks` (applies to
-  :meth:`.ifilter` as well).
-- Added filter methods for :class:`Arguments <.Argument>`,
-  :class:`Comments <.Comment>`, :class:`Headings <.Heading>`, and
-  :class:`HTMLEntities <.HTMLEntity>`.
-- Added *before* param to :meth:`.Template.add`; renamed *force_nonconformity*
-  to *preserve_spacing*.
-- Added *include_lead* param to :meth:`.Wikicode.get_sections`.
-- Removed *flat* param from :meth:`.get_sections`.
-- Removed *force_no_field* param from :meth:`.Template.remove`.
-- Added support for Travis CI.
-- Added note about Windows build issue in the README.
-- The tokenizer will limit itself to a realistic recursion depth to prevent
-  errors and unreasonably long parse times.
-- Fixed how some nodes' attribute setters handle input.
-- Fixed multiple bugs in the tokenizer's handling of invalid markup.
-- Fixed bugs in the implementation of :class:`.SmartList` and
-  :class:`.StringMixIn`.
-- Fixed some broken example code in the README; other copyedits.
-- Other bugfixes and code cleanup.
-
-v0.1.1
-------
-
-`Released September 21, 2012 <https://github.com/earwig/mwparserfromhell/tree/v0.1.1>`_
-(`changes <https://github.com/earwig/mwparserfromhell/compare/v0.1...v0.1.1>`__):
-
-- Added support for :class:`Comments <.Comment>` (``<!-- foo -->``) and
-  :class:`Wikilinks <.Wikilink>` (``[[foo]]``).
-- Added corresponding :meth:`.ifilter_links` and :meth:`.filter_links` methods
-  to :class:`.Wikicode`.
-- Fixed a bug when parsing incomplete templates.
-- Fixed :meth:`.strip_code` to affect the contents of headings.
-- Various copyedits in documentation and comments.
-
-v0.1
-----
-
-`Released August 23, 2012 <https://github.com/earwig/mwparserfromhell/tree/v0.1>`_:
-
-- Initial release.
diff --git a/docs/conf.py b/docs/conf.py
deleted file mode 100644
index 61d5b20..0000000
--- a/docs/conf.py
+++ /dev/null
@@ -1,261 +0,0 @@
-# -*- coding: utf-8 -*-
-#
-# mwparserfromhell documentation build configuration file, created by
-# sphinx-quickstart on Tue Aug 21 20:47:26 2012.
-#
-# This file is execfile()d with the current directory set to its containing dir.
-#
-# Note that not all possible configuration values are present in this
-# autogenerated file.
-#
-# All configuration values have a default; values that are commented out
-# serve to show the default.
-
-import sys, os
-
-# If extensions (or modules to document with autodoc) are in another directory,
-# add these directories to sys.path here. If the directory is relative to the
-# documentation root, use os.path.abspath to make it absolute, like shown here.
-sys.path.insert(0, os.path.abspath(".."))
-import mwparserfromhell
-
-# -- General configuration -----------------------------------------------------
-
-# If your documentation needs a minimal Sphinx version, state it here.
-# needs_sphinx = '1.0'
-
-# Add any Sphinx extension module names here, as strings. They can be extensions
-# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
-extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx", "sphinx.ext.viewcode"]
-
-# Add any paths that contain templates here, relative to this directory.
-templates_path = ["_templates"]
-
-# The suffix of source filenames.
-source_suffix = ".rst"
-
-# The encoding of source files.
-# source_encoding = 'utf-8-sig'
-
-# The master toctree document.
-master_doc = "index"
-
-# General information about the project.
-project = "mwparserfromhell"
-copyright = "2012–2021 Ben Kurtovic"
-
-# The version info for the project you're documenting, acts as replacement for
-# |version| and |release|, also used in various other places throughout the
-# built documents.
-#
-# The short X.Y version.
-version = ".".join(mwparserfromhell.__version__.split(".", 2)[:2])
-# The full version, including alpha/beta/rc tags.
-release = mwparserfromhell.__version__
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-# language = None
-
-# There are two options for replacing |today|: either, you set today to some
-# non-false value, then it is used:
-# today = ''
-# Else, today_fmt is used as the format for a strftime call.
-# today_fmt = '%B %d, %Y'
-
-# List of patterns, relative to source directory, that match files and
-# directories to ignore when looking for source files.
-exclude_patterns = ["_build"]
-
-# The reST default role (used for this markup: `text`) to use for all documents.
-# default_role = None
-
-# If true, '()' will be appended to :func: etc. cross-reference text.
-# add_function_parentheses = True
-
-# If true, the current module name will be prepended to all description
-# unit titles (such as .. function::).
-# add_module_names = True
-
-# If true, sectionauthor and moduleauthor directives will be shown in the
-# output. They are ignored by default.
-# show_authors = False
-
-# The name of the Pygments (syntax highlighting) style to use.
-pygments_style = "sphinx"
-
-# A list of ignored prefixes for module index sorting.
-# modindex_common_prefix = []
-
-
-# -- Options for HTML output ---------------------------------------------------
-
-# The theme to use for HTML and HTML Help pages.  See the documentation for
-# a list of builtin themes.
-html_theme = "nature"
-
-# Theme options are theme-specific and customize the look and feel of a theme
-# further.  For a list of options available for each theme, see the
-# documentation.
-# html_theme_options = {}
-
-# Add any paths that contain custom themes here, relative to this directory.
-# html_theme_path = []
-
-# The name for this set of Sphinx documents.  If None, it defaults to
-# "<project> v<release> documentation".
-# html_title = None
-
-# A shorter title for the navigation bar.  Default is the same as html_title.
-# html_short_title = None
-
-# The name of an image file (relative to this directory) to place at the top
-# of the sidebar.
-# html_logo = None
-
-# The name of an image file (within the static path) to use as favicon of the
-# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32
-# pixels large.
-# html_favicon = None
-
-# Add any paths that contain custom static files (such as style sheets) here,
-# relative to this directory. They are copied after the builtin static files,
-# so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ["_static"]
-
-# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
-# using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
-
-# If true, SmartyPants will be used to convert quotes and dashes to
-# typographically correct entities.
-# html_use_smartypants = True
-
-# Custom sidebar templates, maps document names to template names.
-# html_sidebars = {}
-
-# Additional templates that should be rendered to pages, maps page names to
-# template names.
-# html_additional_pages = {}
-
-# If false, no module index is generated.
-# html_domain_indices = True
-
-# If false, no index is generated.
-# html_use_index = True
-
-# If true, the index is split into individual pages for each letter.
-# html_split_index = False
-
-# If true, links to the reST sources are added to the pages.
-# html_show_sourcelink = True
-
-# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
-# html_show_sphinx = True
-
-# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
-# html_show_copyright = True
-
-# If true, an OpenSearch description file will be output, and all pages will
-# contain a <link> tag referring to it.  The value of this option must be the
-# base URL from which the finished HTML is served.
-# html_use_opensearch = ''
-
-# This is the file name suffix for HTML files (e.g. ".xhtml").
-# html_file_suffix = None
-
-# Output file base name for HTML help builder.
-htmlhelp_basename = "mwparserfromhelldoc"
-
-
-# -- Options for LaTeX output --------------------------------------------------
-
-latex_elements = {
-    # The paper size ('letterpaper' or 'a4paper').
-    #'papersize': 'letterpaper',
-    # The font size ('10pt', '11pt' or '12pt').
-    #'pointsize': '10pt',
-    # Additional stuff for the LaTeX preamble.
-    #'preamble': '',
-}
-
-# Grouping the document tree into LaTeX files. List of tuples
-# (source start file, target name, title, author, documentclass [howto/manual]).
-latex_documents = [
-    (
-        "index",
-        "mwparserfromhell.tex",
-        "mwparserfromhell Documentation",
-        "Ben Kurtovic",
-        "manual",
-    )
-]
-
-# The name of an image file (relative to this directory) to place at the top of
-# the title page.
-# latex_logo = None
-
-# For "manual" documents, if this is true, then toplevel headings are parts,
-# not chapters.
-# latex_use_parts = False
-
-# If true, show page references after internal links.
-# latex_show_pagerefs = False
-
-# If true, show URL addresses after external links.
-# latex_show_urls = False
-
-# Documents to append as an appendix to all manuals.
-# latex_appendices = []
-
-# If false, no module index is generated.
-# latex_domain_indices = True
-
-
-# -- Options for manual page output --------------------------------------------
-
-# One entry per manual page. List of tuples
-# (source start file, name, description, authors, manual section).
-man_pages = [
-    (
-        "index",
-        "mwparserfromhell",
-        "mwparserfromhell Documentation",
-        ["Ben Kurtovic"],
-        1,
-    )
-]
-
-# If true, show URL addresses after external links.
-# man_show_urls = False
-
-
-# -- Options for Texinfo output ------------------------------------------------
-
-# Grouping the document tree into Texinfo files. List of tuples
-# (source start file, target name, title, author,
-#  dir menu entry, description, category)
-texinfo_documents = [
-    (
-        "index",
-        "mwparserfromhell",
-        "mwparserfromhell Documentation",
-        "Ben Kurtovic",
-        "mwparserfromhell",
-        "One line description of project.",
-        "Miscellaneous",
-    )
-]
-
-# Documents to append as an appendix to all manuals.
-# texinfo_appendices = []
-
-# If false, no module index is generated.
-# texinfo_domain_indices = True
-
-# How to display URL addresses: 'footnote', 'no', or 'inline'.
-# texinfo_show_urls = 'footnote'
-
-
-# Example configuration for intersphinx: refer to the Python standard library.
-intersphinx_mapping = {"http://docs.python.org/": None}
diff --git a/docs/index.rst b/docs/index.rst
deleted file mode 100644
index 0ce3489..0000000
--- a/docs/index.rst
+++ /dev/null
@@ -1,55 +0,0 @@
-MWParserFromHell v\ |version| Documentation
-===========================================
-
-:mod:`mwparserfromhell` (the *MediaWiki Parser from Hell*) is a Python package
-that provides an easy-to-use and outrageously powerful parser for MediaWiki_
-wikicode. It supports Python 3.5+.
-
-Developed by Earwig_ with contributions from `Σ`_, Legoktm_, and others.
-Development occurs on GitHub_.
-
-.. _MediaWiki:            https://www.mediawiki.org
-.. _Earwig:               https://en.wikipedia.org/wiki/User:The_Earwig
-.. _Σ:                    https://en.wikipedia.org/wiki/User:%CE%A3
-.. _Legoktm:              https://en.wikipedia.org/wiki/User:Legoktm
-.. _GitHub:               https://github.com/earwig/mwparserfromhell
-
-Installation
-------------
-
-The easiest way to install the parser is through the `Python Package Index`_;
-you can install the latest release with ``pip install mwparserfromhell``
-(`get pip`_). Make sure your pip is up-to-date first, especially on Windows.
-
-Alternatively, get the latest development version::
-
-    git clone https://github.com/earwig/mwparserfromhell.git
-    cd mwparserfromhell
-    python setup.py install
-
-The comprehensive unit testing suite requires `pytest`_ (``pip install pytest``)
-and can be run with ``python -m pytest``.
-
-.. _Python Package Index:   https://pypi.org/
-.. _get pip:                https://pypi.org/project/pip/
-.. _pytest:                 https://docs.pytest.org/
-
-Contents
---------
-
-.. toctree::
-   :maxdepth: 2
-
-   usage
-   limitations
-   integration
-   changelog
-   API Reference <api/modules>
-
-
-Indices and tables
-------------------
-
-* :ref:`genindex`
-* :ref:`modindex`
-* :ref:`search`
diff --git a/docs/integration.rst b/docs/integration.rst
deleted file mode 100644
index 8054d9f..0000000
--- a/docs/integration.rst
+++ /dev/null
@@ -1,50 +0,0 @@
-Integration
-===========
-
-:mod:`mwparserfromhell` is used by and originally developed for EarwigBot_;
-:class:`~earwigbot.wiki.page.Page` objects have a
-:meth:`~earwigbot.wiki.page.Page.parse` method that essentially calls
-:func:`mwparserfromhell.parse() <mwparserfromhell.__init__.parse>` on
-:meth:`~earwigbot.wiki.page.Page.get`.
-
-If you're using Pywikibot_, your code might look like this:
-
-    import mwparserfromhell
-    import pywikibot
-
-    def parse(title):
-        site = pywikibot.Site()
-        page = pywikibot.Page(site, title)
-        text = page.get()
-        return mwparserfromhell.parse(text)
-
-If you're not using a library, you can parse any page with the following
-Python 3 code (using the API_ and the requests_ library):
-
-    import mwparserfromhell
-    import requests
-
-    API_URL = "https://en.wikipedia.org/w/api.php"
-
-    def parse(title):
-        params = {
-            "action": "query",
-            "prop": "revisions",
-            "rvprop": "content",
-            "rvslots": "main",
-            "rvlimit": 1,
-            "titles": title,
-            "format": "json",
-            "formatversion": "2",
-        }
-        headers = {"User-Agent": "My-Bot-Name/1.0"}
-        req = requests.get(API_URL, headers=headers, params=params)
-        res = req.json()
-        revision = res["query"]["pages"][0]["revisions"][0]
-        text = revision["slots"]["main"]["content"]
-        return mwparserfromhell.parse(text)
-
-.. _EarwigBot:            https://github.com/earwig/earwigbot
-.. _Pywikibot:            https://www.mediawiki.org/wiki/Manual:Pywikibot
-.. _API:                  https://www.mediawiki.org/wiki/API:Main_page
-.. _requests:             https://2.python-requests.org
diff --git a/docs/limitations.rst b/docs/limitations.rst
deleted file mode 100644
index 294f4c5..0000000
--- a/docs/limitations.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-Limitations
-===========
-
-While the MediaWiki parser generates HTML and has access to the contents of
-templates, among other things, mwparserfromhell acts as a direct interface to
-the source code only. This has several implications:
-
-* Syntax elements produced by a template transclusion cannot be detected. For
-  example, imagine a hypothetical page ``"Template:End-bold"`` that contained
-  the text ``</b>``. While MediaWiki would correctly understand that
-  ``<b>foobar{{end-bold}}`` translates to ``<b>foobar</b>``, mwparserfromhell
-  has no way of examining the contents of ``{{end-bold}}``. Instead, it would
-  treat the bold tag as unfinished, possibly extending further down the page.
-
-* Templates adjacent to external links, as in ``http://example.com{{foo}}``,
-  are considered part of the link. In reality, this would depend on the
-  contents of the template.
-
-* When different syntax elements cross over each other, as in
-  ``{{echo|''Hello}}, world!''``, the parser gets confused because this cannot
-  be represented by an ordinary syntax tree. Instead, the parser will treat the
-  first syntax construct as plain text. In this case, only the italic tag would
-  be properly parsed.
-
-  **Workaround:** Since this commonly occurs with text formatting and text
-  formatting is often not of interest to users, you may pass
-  *skip_style_tags=True* to ``mwparserfromhell.parse()``. This treats ``''``
-  and ``'''`` as plain text.
-
-  A future version of mwparserfromhell may include multiple parsing modes to
-  get around this restriction more sensibly.
-
-Additionally, the parser lacks awareness of certain wiki-specific settings:
-
-* `Word-ending links`_ are not supported, since the linktrail rules are
-  language-specific.
-
-* Localized namespace names aren't recognized, so file links (such as
-  ``[[File:...]]``) are treated as regular wikilinks.
-
-* Anything that looks like an XML tag is treated as a tag, even if it is not a
-  recognized tag name, since the list of valid tags depends on loaded MediaWiki
-  extensions.
-
-.. _Word-ending links:      https://www.mediawiki.org/wiki/Help:Links#linktrail
diff --git a/docs/usage.rst b/docs/usage.rst
deleted file mode 100644
index 2cdc690..0000000
--- a/docs/usage.rst
+++ /dev/null
@@ -1,82 +0,0 @@
-Usage
-=====
-
-Normal usage is rather straightforward (where ``text`` is page text)::
-
-    >>> import mwparserfromhell
-    >>> wikicode = mwparserfromhell.parse(text)
-
-``wikicode`` is a :class:`mwparserfromhell.Wikicode <.Wikicode>` object, which
-acts like an ordinary ``str`` object with some extra methods. For example::
-
-    >>> text = "I has a template! {{foo|bar|baz|eggs=spam}} See it?"
-    >>> wikicode = mwparserfromhell.parse(text)
-    >>> print(wikicode)
-    I has a template! {{foo|bar|baz|eggs=spam}} See it?
-    >>> templates = wikicode.filter_templates()
-    >>> print(templates)
-    ['{{foo|bar|baz|eggs=spam}}']
-    >>> template = templates[0]
-    >>> print(template.name)
-    foo
-    >>> print(template.params)
-    ['bar', 'baz', 'eggs=spam']
-    >>> print(template.get(1).value)
-    bar
-    >>> print(template.get("eggs").value)
-    spam
-
-Since nodes can contain other nodes, getting nested templates is trivial::
-
-    >>> text = "{{foo|{{bar}}={{baz|{{spam}}}}}}"
-    >>> mwparserfromhell.parse(text).filter_templates()
-    ['{{foo|{{bar}}={{baz|{{spam}}}}}}', '{{bar}}', '{{baz|{{spam}}}}', '{{spam}}']
-
-You can also pass *recursive=False* to :meth:`.filter_templates` and explore
-templates manually. This is possible because nodes can contain additional
-:class:`.Wikicode` objects::
-
-    >>> code = mwparserfromhell.parse("{{foo|this {{includes a|template}}}}")
-    >>> print(code.filter_templates(recursive=False))
-    ['{{foo|this {{includes a|template}}}}']
-    >>> foo = code.filter_templates(recursive=False)[0]
-    >>> print(foo.get(1).value)
-    this {{includes a|template}}
-    >>> print(foo.get(1).value.filter_templates()[0])
-    {{includes a|template}}
-    >>> print(foo.get(1).value.filter_templates()[0].get(1).value)
-    template
-
-Templates can be easily modified to add, remove, or alter params.
-:class:`.Wikicode` objects can be treated like lists, with
-:meth:`~.Wikicode.append`, :meth:`~.Wikicode.insert`,
-:meth:`~.Wikicode.remove`, :meth:`~.Wikicode.replace`, and more. They also have
-a :meth:`~.Wikicode.matches` method for comparing page or template names, which
-takes care of capitalization and whitespace::
-
-    >>> text = "{{cleanup}} '''Foo''' is a [[bar]]. {{uncategorized}}"
-    >>> code = mwparserfromhell.parse(text)
-    >>> for template in code.filter_templates():
-    ...     if template.name.matches("Cleanup") and not template.has("date"):
-    ...         template.add("date", "July 2012")
-    ...
-    >>> print(code)
-    {{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{uncategorized}}
-    >>> code.replace("{{uncategorized}}", "{{bar-stub}}")
-    >>> print(code)
-    {{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}
-    >>> print(code.filter_templates())
-    ['{{cleanup|date=July 2012}}', '{{bar-stub}}']
-
-You can then convert ``code`` back into a regular :class:`str` object (for
-saving the page!) by calling :func:`str` on it::
-
-    >>> text = str(code)
-    >>> print(text)
-    {{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}
-    >>> text == code
-    True
-
-
-For more tips, check out :class:`Wikicode's full method list <.Wikicode>` and
-the :mod:`list of Nodes <.nodes>`.
diff --git a/scripts/README b/scripts/README
deleted file mode 100644
index eea9627..0000000
--- a/scripts/README
+++ /dev/null
@@ -1,3 +0,0 @@
-This directory contains support files used for *developing* mwparserfromhell,
-not running it. If you are looking for code examples, read the documentation
-or explore the source code.
diff --git a/scripts/memtest.py b/scripts/memtest.py
deleted file mode 100644
index d5e39e5..0000000
--- a/scripts/memtest.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# Copyright (C) 2012-2020 Ben Kurtovic <ben.kurtovic@gmail.com>
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-# SOFTWARE.
-
-"""
-Tests for memory leaks in the CTokenizer.
-
-This appears to work mostly fine under Linux, but gives an absurd number of
-false positives on macOS. I'm not sure why. Running the tests multiple times
-yields different results (tests don't always leak, and the amount they leak by
-varies). Increasing the number of loops results in a smaller bytes/loop value,
-too, indicating the increase in memory usage might be due to something else.
-Actual memory leaks typically leak very large amounts of memory (megabytes)
-and scale with the number of loops.
-"""
-
-from locale import LC_ALL, setlocale
-from multiprocessing import Process, Pipe
-from os import listdir, path
-import sys
-
-import psutil
-
-from mwparserfromhell.parser._tokenizer import CTokenizer
-
-LOOPS = 10000
-
-
-class Color:
-    GRAY = "\x1b[30;1m"
-    GREEN = "\x1b[92m"
-    YELLOW = "\x1b[93m"
-    RESET = "\x1b[0m"
-
-
-class MemoryTest:
-    """Manages a memory test."""
-
-    def __init__(self):
-        self._tests = []
-        self._load()
-
-    def _parse_file(self, name, text):
-        tests = text.split("\n---\n")
-        counter = 1
-        digits = len(str(len(tests)))
-        for test in tests:
-            data = {"name": None, "label": None, "input": None, "output": None}
-            for line in test.strip().splitlines():
-                if line.startswith("name:"):
-                    data["name"] = line[len("name:") :].strip()
-                elif line.startswith("label:"):
-                    data["label"] = line[len("label:") :].strip()
-                elif line.startswith("input:"):
-                    raw = line[len("input:") :].strip()
-                    if raw[0] == '"' and raw[-1] == '"':
-                        raw = raw[1:-1]
-                    raw = raw.encode("raw_unicode_escape")
-                    data["input"] = raw.decode("unicode_escape")
-            number = str(counter).zfill(digits)
-            fname = "test_{}{}_{}".format(name, number, data["name"])
-            self._tests.append((fname, data["input"]))
-            counter += 1
-
-    def _load(self):
-        def load_file(filename):
-            with open(filename, "rU") as fp:
-                text = fp.read()
-                name = path.split(filename)[1][: 0 - len(extension)]
-                self._parse_file(name, text)
-
-        root = path.split(path.dirname(path.abspath(__file__)))[0]
-        directory = path.join(root, "tests", "tokenizer")
-        extension = ".mwtest"
-        if len(sys.argv) > 2 and sys.argv[1] == "--use":
-            for name in sys.argv[2:]:
-                load_file(path.join(directory, name + extension))
-            sys.argv = [sys.argv[0]]  # So unittest doesn't try to load these
-        else:
-            for filename in listdir(directory):
-                if not filename.endswith(extension):
-                    continue
-                load_file(path.join(directory, filename))
-
-    @staticmethod
-    def _print_results(info1, info2):
-        r1, r2 = info1.rss, info2.rss
-        buff = 8192
-        if r2 - buff > r1:
-            d = r2 - r1
-            p = float(d) / r1
-            bpt = d // LOOPS
-            tmpl = "{0}LEAKING{1}: {2:n} bytes, {3:.2%} inc ({4:n} bytes/loop)"
-            sys.stdout.write(tmpl.format(Color.YELLOW, Color.RESET, d, p, bpt))
-        else:
-            sys.stdout.write("{}OK{}".format(Color.GREEN, Color.RESET))
-
-    def run(self):
-        """Run the memory test suite."""
-        width = 1
-        for (name, _) in self._tests:
-            if len(name) > width:
-                width = len(name)
-
-        tmpl = "{0}[{1:03}/{2}]{3} {4}: "
-        for i, (name, text) in enumerate(self._tests, 1):
-            sys.stdout.write(
-                tmpl.format(
-                    Color.GRAY, i, len(self._tests), Color.RESET, name.ljust(width)
-                )
-            )
-            sys.stdout.flush()
-            parent, child = Pipe()
-            p = Process(target=_runner, args=(text, child))
-            p.start()
-            try:
-                proc = psutil.Process(p.pid)
-                parent.recv()
-                parent.send("OK")
-                parent.recv()
-                info1 = proc.get_memory_info()
-                sys.stdout.flush()
-                parent.send("OK")
-                parent.recv()
-                info2 = proc.get_memory_info()
-                self._print_results(info1, info2)
-                sys.stdout.flush()
-                parent.send("OK")
-            finally:
-                proc.kill()
-                print()
-
-
-def _runner(text, child):
-    r1, r2 = range(250), range(LOOPS)
-    for _ in r1:
-        CTokenizer().tokenize(text)
-    child.send("OK")
-    child.recv()
-    child.send("OK")
-    child.recv()
-    for _ in r2:
-        CTokenizer().tokenize(text)
-    child.send("OK")
-    child.recv()
-
-
-if __name__ == "__main__":
-    setlocale(LC_ALL, "")
-    MemoryTest().run()
diff --git a/scripts/release.sh b/scripts/release.sh
deleted file mode 100755
index 257b963..0000000
--- a/scripts/release.sh
+++ /dev/null
@@ -1,169 +0,0 @@
-#! /usr/bin/env bash
-
-if [[ -z "$1" ]]; then
-    echo "usage: $0 1.2.3"
-    exit 1
-fi
-
-set -euo pipefail
-
-VERSION=$1
-SCRIPT_DIR=$(dirname "$0")
-RELEASE_DATE=$(date +"%B %-d, %Y")
-
-check_git() {
-    if [[ -n "$(git status --porcelain --untracked-files=no)" ]]; then
-        echo "Aborting: dirty working directory."
-        exit 1
-    fi
-    if [[ "$(git rev-parse --abbrev-ref HEAD)" != "develop" ]]; then
-        echo "Aborting: not on develop."
-        exit 1
-    fi
-    echo -n "Are you absolutely ready to release? [yN] "
-    read confirm
-    if [[ ${confirm,,} != "y" ]]; then
-        exit 1
-    fi
-}
-
-update_version() {
-    echo -n "Updating mwparserfromhell.__version__..."
-    sed -e 's/__version__ = .*/__version__ = "'$VERSION'"/' -i "" src/mwparserfromhell/__init__.py
-    echo " done."
-}
-
-update_appveyor() {
-    filename="appveyor.yml"
-    echo -n "Updating $filename..."
-    sed -e "s/version: .*/version: $VERSION-b{build}/" -i "" $filename
-    echo " done."
-}
-
-update_changelog() {
-    filename="CHANGELOG"
-    echo -n "Updating $filename..."
-    sed -e "1s/.*/v$VERSION (released $RELEASE_DATE):/" -i "" $filename
-    echo " done."
-}
-
-update_docs_changelog() {
-    filename="docs/changelog.rst"
-    echo -n "Updating $filename..."
-    dashes=$(seq 1 $(expr ${#VERSION} + 1) | sed 's/.*/-/' | tr -d '\n')
-    previous_lineno=$(expr $(grep -n -e "^---" $filename | sed '2q;d' | cut -d ':' -f 1) - 1)
-    previous_version=$(sed $previous_lineno'q;d' $filename)
-    sed \
-        -e "4s/.*/v$VERSION/" \
-        -e "5s/.*/$dashes/" \
-        -e "7s/.*/\`Released $RELEASE_DATE <https:\/\/github.com\/earwig\/mwparserfromhell\/tree\/v$VERSION>\`_/" \
-        -e "8s/.*/(\`changes <https:\/\/github.com\/earwig\/mwparserfromhell\/compare\/$previous_version...v$VERSION>\`__):/" \
-        -i "" $filename
-    echo " done."
-}
-
-do_git_stuff() {
-    echo -n "Git: committing, tagging, and merging release..."
-    git commit -qam "release/$VERSION"
-    git tag v$VERSION -s -m "version $VERSION"
-    git checkout -q master
-    git merge -q --no-ff develop -m "Merge develop into master (release/$VERSION)"
-    echo -n " pushing..."
-    git push -q --tags origin master
-    git checkout -q develop
-    git push -q origin develop
-    echo " done."
-}
-
-upload_to_pypi() {
-    echo -n "PyPI: uploading source tarball..."
-    python setup.py -q sdist
-    twine upload -s dist/mwparserfromhell-$VERSION*
-    echo " done."
-}
-
-post_release() {
-    echo
-    echo "*** Release completed."
-    echo "*** Update: https://github.com/earwig/mwparserfromhell/releases/tag/v$VERSION"
-    echo "*** Verify: https://pypi.org/project/mwparserfromhell"
-    echo "*** Verify: https://ci.appveyor.com/project/earwig/mwparserfromhell"
-    echo "*** Verify: https://mwparserfromhell.readthedocs.io"
-    echo "*** Press enter to sanity-check the release."
-    read
-}
-
-test_release() {
-    echo
-    echo "Checking mwparserfromhell v$VERSION..."
-    echo -n "Creating a virtualenv..."
-    virtdir="mwparser-test-env"
-    python -m venv $virtdir
-    cd $virtdir
-    source bin/activate
-    echo " done."
-    echo -n "Installing mwparserfromhell with pip..."
-    pip -q install --upgrade pip
-    pip -q install mwparserfromhell pytest
-    echo " done."
-    echo -n "Checking version..."
-    reported_version=$(python -c 'print(__import__("mwparserfromhell").__version__)')
-    if [[ "$reported_version" != "$VERSION" ]]; then
-        echo " error."
-        echo "*** ERROR: mwparserfromhell is reporting its version as $reported_version, not $VERSION!"
-        deactivate
-        cd ..
-        rm -rf $virtdir
-        exit 1
-    else
-        echo " done."
-    fi
-    pip -q uninstall -y mwparserfromhell
-    echo -n "Downloading mwparserfromhell source tarball and GPG signature..."
-    curl -sL "https://pypi.io/packages/source/m/mwparserfromhell/mwparserfromhell-$VERSION.tar.gz" -o "mwparserfromhell.tar.gz"
-    curl -sL "https://pypi.io/packages/source/m/mwparserfromhell/mwparserfromhell-$VERSION.tar.gz.asc" -o "mwparserfromhell.tar.gz.asc"
-    echo " done."
-    echo "Verifying tarball..."
-    gpg --verify mwparserfromhell.tar.gz.asc mwparserfromhell.tar.gz
-    if [[ "$?" != "0" ]]; then
-        echo "*** ERROR: GPG signature verification failed!"
-        deactivate
-        cd ..
-        rm -rf $virtdir
-        exit 1
-    fi
-    tar -xf mwparserfromhell.tar.gz
-    rm mwparserfromhell.tar.gz mwparserfromhell.tar.gz.asc
-    cd mwparserfromhell-$VERSION
-    echo "Running unit tests..."
-    python setup.py -q install
-    python -m pytest
-    if [[ "$?" != "0" ]]; then
-        echo "*** ERROR: Unit tests failed!"
-        deactivate
-        cd ../..
-        rm -rf $virtdir
-        exit 1
-    fi
-    echo -n "Everything looks good. Cleaning up..."
-    deactivate
-    cd ../..
-    rm -rf $virtdir
-    echo " done."
-}
-
-echo "Preparing mwparserfromhell v$VERSION..."
-cd "$SCRIPT_DIR/.."
-
-check_git
-update_version
-update_appveyor
-update_changelog
-update_docs_changelog
-do_git_stuff
-upload_to_pypi
-post_release
-test_release
-
-echo "All done."
-exit 0
diff --git a/scripts/win_wrapper.cmd b/scripts/win_wrapper.cmd
deleted file mode 100644
index 3a590df..0000000
--- a/scripts/win_wrapper.cmd
+++ /dev/null
@@ -1,55 +0,0 @@
-:: To build extensions for 64 bit Python 3, we need to configure environment
-:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
-:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1)
-::
-:: To build extensions for 64 bit Python 2, we need to configure environment
-:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of:
-:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0)
-::
-:: 32 bit builds do not require specific environment configurations.
-::
-:: Note: this script needs to be run with the /E:ON and /V:ON flags for the
-:: cmd interpreter, at least for (SDK v7.0)
-::
-:: More details at:
-:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows
-:: http://stackoverflow.com/a/13751649/163740
-::
-:: Author: Olivier Grisel
-:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
-@ECHO OFF
-
-SET COMMAND_TO_RUN=%*
-SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
-SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf
-
-SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1%
-SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2%
-
-IF %MAJOR_PYTHON_VERSION% == 2 (
-    SET WINDOWS_SDK_VERSION="v7.0"
-) ELSE IF %MAJOR_PYTHON_VERSION% == 3 (
-    SET WINDOWS_SDK_VERSION="v7.1"
-    IF %MINOR_PYTHON_VERSION% GEQ 5 (
-        SET NO_SET_SDK_64=Y
-    )
-) ELSE (
-    ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%"
-    EXIT 1
-)
-
-IF "%PYTHON_ARCH%"=="32" (
-    call %COMMAND_TO_RUN% || EXIT 1
-) ELSE IF "%NO_SET_SDK_64%"=="Y" (
-    IF EXIST "%WIN_WDK%" (
-        :: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/
-        REN "%WIN_WDK%" 0wdf
-    )
-   call %COMMAND_TO_RUN% || EXIT 1
-) ELSE (
-    SET DISTUTILS_USE_SDK=1
-    SET MSSdk=1
-    "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
-    "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
-    call %COMMAND_TO_RUN% || EXIT 1
-)
diff --git a/setup.cfg b/setup.cfg
index b7e4789..e4eba0b 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,2 +1,7 @@
 [aliases]
-test=pytest
+test = pytest
+
+[egg_info]
+tag_build = 
+tag_date = 0
+
diff --git a/src/mwparserfromhell.egg-info/PKG-INFO b/src/mwparserfromhell.egg-info/PKG-INFO
new file mode 100644
index 0000000..7769829
--- /dev/null
+++ b/src/mwparserfromhell.egg-info/PKG-INFO
@@ -0,0 +1,246 @@
+Metadata-Version: 2.1
+Name: mwparserfromhell
+Version: 0.7.dev0
+Summary: MWParserFromHell is a parser for MediaWiki wikicode.
+Home-page: https://github.com/earwig/mwparserfromhell
+Author: Ben Kurtovic
+Author-email: ben.kurtovic@gmail.com
+License: MIT License
+Download-URL: https://github.com/earwig/mwparserfromhell/tarball/v0.7.dev0
+Keywords: earwig mwparserfromhell wikipedia wiki mediawiki wikicode template parsing
+Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Environment :: Console
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.6
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Topic :: Text Processing :: Markup
+Requires-Python: >= 3.6
+License-File: LICENSE
+
+mwparserfromhell
+================
+
+.. image:: https://api.travis-ci.com/earwig/mwparserfromhell.svg
+  :alt: Build Status
+  :target: https://travis-ci.org/earwig/mwparserfromhell
+
+.. image:: https://img.shields.io/coveralls/earwig/mwparserfromhell/main.svg
+  :alt: Coverage Status
+  :target: https://coveralls.io/r/earwig/mwparserfromhell
+
+**mwparserfromhell** (the *MediaWiki Parser from Hell*) is a Python package
+that provides an easy-to-use and outrageously powerful parser for MediaWiki_
+wikicode. It supports Python 3.5+.
+
+Developed by Earwig_ with contributions from `Σ`_, Legoktm_, and others.
+Full documentation is available on ReadTheDocs_. Development occurs on GitHub_.
+
+Installation
+------------
+
+The easiest way to install the parser is through the `Python Package Index`_;
+you can install the latest release with ``pip install mwparserfromhell``
+(`get pip`_). Make sure your pip is up-to-date first, especially on Windows.
+
+Alternatively, get the latest development version::
+
+    git clone https://github.com/earwig/mwparserfromhell.git
+    cd mwparserfromhell
+    python setup.py install
+
+The comprehensive unit testing suite requires `pytest`_ (``pip install pytest``)
+and can be run with ``python -m pytest``.
+
+Usage
+-----
+
+Normal usage is rather straightforward (where ``text`` is page text):
+
+>>> import mwparserfromhell
+>>> wikicode = mwparserfromhell.parse(text)
+
+``wikicode`` is a ``mwparserfromhell.Wikicode`` object, which acts like an
+ordinary ``str`` object with some extra methods. For example:
+
+>>> text = "I has a template! {{foo|bar|baz|eggs=spam}} See it?"
+>>> wikicode = mwparserfromhell.parse(text)
+>>> print(wikicode)
+I has a template! {{foo|bar|baz|eggs=spam}} See it?
+>>> templates = wikicode.filter_templates()
+>>> print(templates)
+['{{foo|bar|baz|eggs=spam}}']
+>>> template = templates[0]
+>>> print(template.name)
+foo
+>>> print(template.params)
+['bar', 'baz', 'eggs=spam']
+>>> print(template.get(1).value)
+bar
+>>> print(template.get("eggs").value)
+spam
+
+Since nodes can contain other nodes, getting nested templates is trivial:
+
+>>> text = "{{foo|{{bar}}={{baz|{{spam}}}}}}"
+>>> mwparserfromhell.parse(text).filter_templates()
+['{{foo|{{bar}}={{baz|{{spam}}}}}}', '{{bar}}', '{{baz|{{spam}}}}', '{{spam}}']
+
+You can also pass ``recursive=False`` to ``filter_templates()`` and explore
+templates manually. This is possible because nodes can contain additional
+``Wikicode`` objects:
+
+>>> code = mwparserfromhell.parse("{{foo|this {{includes a|template}}}}")
+>>> print(code.filter_templates(recursive=False))
+['{{foo|this {{includes a|template}}}}']
+>>> foo = code.filter_templates(recursive=False)[0]
+>>> print(foo.get(1).value)
+this {{includes a|template}}
+>>> print(foo.get(1).value.filter_templates()[0])
+{{includes a|template}}
+>>> print(foo.get(1).value.filter_templates()[0].get(1).value)
+template
+
+Templates can be easily modified to add, remove, or alter params. ``Wikicode``
+objects can be treated like lists, with ``append()``, ``insert()``,
+``remove()``, ``replace()``, and more. They also have a ``matches()`` method
+for comparing page or template names, which takes care of capitalization and
+whitespace:
+
+>>> text = "{{cleanup}} '''Foo''' is a [[bar]]. {{uncategorized}}"
+>>> code = mwparserfromhell.parse(text)
+>>> for template in code.filter_templates():
+...     if template.name.matches("Cleanup") and not template.has("date"):
+...         template.add("date", "July 2012")
+...
+>>> print(code)
+{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{uncategorized}}
+>>> code.replace("{{uncategorized}}", "{{bar-stub}}")
+>>> print(code)
+{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}
+>>> print(code.filter_templates())
+['{{cleanup|date=July 2012}}', '{{bar-stub}}']
+
+You can then convert ``code`` back into a regular ``str`` object (for
+saving the page!) by calling ``str()`` on it:
+
+>>> text = str(code)
+>>> print(text)
+{{cleanup|date=July 2012}} '''Foo''' is a [[bar]]. {{bar-stub}}
+>>> text == code
+True
+
+Limitations
+-----------
+
+While the MediaWiki parser generates HTML and has access to the contents of
+templates, among other things, mwparserfromhell acts as a direct interface to
+the source code only. This has several implications:
+
+* Syntax elements produced by a template transclusion cannot be detected. For
+  example, imagine a hypothetical page ``"Template:End-bold"`` that contained
+  the text ``</b>``. While MediaWiki would correctly understand that
+  ``<b>foobar{{end-bold}}`` translates to ``<b>foobar</b>``, mwparserfromhell
+  has no way of examining the contents of ``{{end-bold}}``. Instead, it would
+  treat the bold tag as unfinished, possibly extending further down the page.
+
+* Templates adjacent to external links, as in ``http://example.com{{foo}}``,
+  are considered part of the link. In reality, this would depend on the
+  contents of the template.
+
+* When different syntax elements cross over each other, as in
+  ``{{echo|''Hello}}, world!''``, the parser gets confused because this cannot
+  be represented by an ordinary syntax tree. Instead, the parser will treat the
+  first syntax construct as plain text. In this case, only the italic tag would
+  be properly parsed.
+
+  **Workaround:** Since this commonly occurs with text formatting and text
+  formatting is often not of interest to users, you may pass
+  *skip_style_tags=True* to ``mwparserfromhell.parse()``. This treats ``''``
+  and ``'''`` as plain text.
+
+  A future version of mwparserfromhell may include multiple parsing modes to
+  get around this restriction more sensibly.
+
+Additionally, the parser lacks awareness of certain wiki-specific settings:
+
+* `Word-ending links`_ are not supported, since the linktrail rules are
+  language-specific.
+
+* Localized namespace names aren't recognized, so file links (such as
+  ``[[File:...]]``) are treated as regular wikilinks.
+
+* Anything that looks like an XML tag is treated as a tag, even if it is not a
+  recognized tag name, since the list of valid tags depends on loaded MediaWiki
+  extensions.
+
+Integration
+-----------
+
+``mwparserfromhell`` is used by and originally developed for EarwigBot_;
+``Page`` objects have a ``parse`` method that essentially calls
+``mwparserfromhell.parse()`` on ``page.get()``.
+
+If you're using Pywikibot_, your code might look like this:
+
+.. code-block:: python
+
+    import mwparserfromhell
+    import pywikibot
+
+    def parse(title):
+        site = pywikibot.Site()
+        page = pywikibot.Page(site, title)
+        text = page.get()
+        return mwparserfromhell.parse(text)
+
+If you're not using a library, you can parse any page with the following
+Python 3 code (using the API_ and the requests_ library):
+
+.. code-block:: python
+
+    import mwparserfromhell
+    import requests
+
+    API_URL = "https://en.wikipedia.org/w/api.php"
+
+    def parse(title):
+        params = {
+            "action": "query",
+            "prop": "revisions",
+            "rvprop": "content",
+            "rvslots": "main",
+            "rvlimit": 1,
+            "titles": title,
+            "format": "json",
+            "formatversion": "2",
+        }
+        headers = {"User-Agent": "My-Bot-Name/1.0"}
+        req = requests.get(API_URL, headers=headers, params=params)
+        res = req.json()
+        revision = res["query"]["pages"][0]["revisions"][0]
+        text = revision["slots"]["main"]["content"]
+        return mwparserfromhell.parse(text)
+
+.. _MediaWiki:              https://www.mediawiki.org
+.. _ReadTheDocs:            https://mwparserfromhell.readthedocs.io
+.. _Earwig:                 https://en.wikipedia.org/wiki/User:The_Earwig
+.. _Σ:                      https://en.wikipedia.org/wiki/User:%CE%A3
+.. _Legoktm:                https://en.wikipedia.org/wiki/User:Legoktm
+.. _GitHub:                 https://github.com/earwig/mwparserfromhell
+.. _Python Package Index:   https://pypi.org/
+.. _get pip:                https://pypi.org/project/pip/
+.. _pytest:                 https://docs.pytest.org/
+.. _Word-ending links:      https://www.mediawiki.org/wiki/Help:Links#linktrail
+.. _EarwigBot:              https://github.com/earwig/earwigbot
+.. _Pywikibot:              https://www.mediawiki.org/wiki/Manual:Pywikibot
+.. _API:                    https://www.mediawiki.org/wiki/API:Main_page
+.. _requests:               https://2.python-requests.org
+
+
diff --git a/src/mwparserfromhell.egg-info/SOURCES.txt b/src/mwparserfromhell.egg-info/SOURCES.txt
new file mode 100644
index 0000000..4f2e586
--- /dev/null
+++ b/src/mwparserfromhell.egg-info/SOURCES.txt
@@ -0,0 +1,91 @@
+CHANGELOG
+LICENSE
+MANIFEST.in
+README.rst
+setup.cfg
+setup.py
+src/mwparserfromhell/__init__.py
+src/mwparserfromhell/definitions.py
+src/mwparserfromhell/string_mixin.py
+src/mwparserfromhell/utils.py
+src/mwparserfromhell/wikicode.py
+src/mwparserfromhell.egg-info/PKG-INFO
+src/mwparserfromhell.egg-info/SOURCES.txt
+src/mwparserfromhell.egg-info/dependency_links.txt
+src/mwparserfromhell.egg-info/top_level.txt
+src/mwparserfromhell/nodes/__init__.py
+src/mwparserfromhell/nodes/_base.py
+src/mwparserfromhell/nodes/argument.py
+src/mwparserfromhell/nodes/comment.py
+src/mwparserfromhell/nodes/external_link.py
+src/mwparserfromhell/nodes/heading.py
+src/mwparserfromhell/nodes/html_entity.py
+src/mwparserfromhell/nodes/tag.py
+src/mwparserfromhell/nodes/template.py
+src/mwparserfromhell/nodes/text.py
+src/mwparserfromhell/nodes/wikilink.py
+src/mwparserfromhell/nodes/extras/__init__.py
+src/mwparserfromhell/nodes/extras/attribute.py
+src/mwparserfromhell/nodes/extras/parameter.py
+src/mwparserfromhell/parser/__init__.py
+src/mwparserfromhell/parser/builder.py
+src/mwparserfromhell/parser/contexts.py
+src/mwparserfromhell/parser/errors.py
+src/mwparserfromhell/parser/tokenizer.py
+src/mwparserfromhell/parser/tokens.py
+src/mwparserfromhell/parser/ctokenizer/avl_tree.c
+src/mwparserfromhell/parser/ctokenizer/avl_tree.h
+src/mwparserfromhell/parser/ctokenizer/common.h
+src/mwparserfromhell/parser/ctokenizer/contexts.h
+src/mwparserfromhell/parser/ctokenizer/definitions.c
+src/mwparserfromhell/parser/ctokenizer/definitions.h
+src/mwparserfromhell/parser/ctokenizer/tag_data.c
+src/mwparserfromhell/parser/ctokenizer/tag_data.h
+src/mwparserfromhell/parser/ctokenizer/textbuffer.c
+src/mwparserfromhell/parser/ctokenizer/textbuffer.h
+src/mwparserfromhell/parser/ctokenizer/tok_parse.c
+src/mwparserfromhell/parser/ctokenizer/tok_parse.h
+src/mwparserfromhell/parser/ctokenizer/tok_support.c
+src/mwparserfromhell/parser/ctokenizer/tok_support.h
+src/mwparserfromhell/parser/ctokenizer/tokenizer.c
+src/mwparserfromhell/parser/ctokenizer/tokenizer.h
+src/mwparserfromhell/parser/ctokenizer/tokens.c
+src/mwparserfromhell/parser/ctokenizer/tokens.h
+src/mwparserfromhell/smart_list/__init__.py
+src/mwparserfromhell/smart_list/list_proxy.py
+src/mwparserfromhell/smart_list/smart_list.py
+src/mwparserfromhell/smart_list/utils.py
+tests/__init__.py
+tests/conftest.py
+tests/test_argument.py
+tests/test_attribute.py
+tests/test_builder.py
+tests/test_comment.py
+tests/test_docs.py
+tests/test_external_link.py
+tests/test_heading.py
+tests/test_html_entity.py
+tests/test_parameter.py
+tests/test_parser.py
+tests/test_smart_list.py
+tests/test_string_mixin.py
+tests/test_tag.py
+tests/test_template.py
+tests/test_text.py
+tests/test_tokenizer.py
+tests/test_tokens.py
+tests/test_utils.py
+tests/test_wikicode.py
+tests/test_wikilink.py
+tests/tokenizer/arguments.mwtest
+tests/tokenizer/comments.mwtest
+tests/tokenizer/external_links.mwtest
+tests/tokenizer/headings.mwtest
+tests/tokenizer/html_entities.mwtest
+tests/tokenizer/integration.mwtest
+tests/tokenizer/tables.mwtest
+tests/tokenizer/tags.mwtest
+tests/tokenizer/tags_wikimarkup.mwtest
+tests/tokenizer/templates.mwtest
+tests/tokenizer/text.mwtest
+tests/tokenizer/wikilinks.mwtest
\ No newline at end of file
diff --git a/src/mwparserfromhell.egg-info/dependency_links.txt b/src/mwparserfromhell.egg-info/dependency_links.txt
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/mwparserfromhell.egg-info/dependency_links.txt
@@ -0,0 +1 @@
+
diff --git a/src/mwparserfromhell.egg-info/top_level.txt b/src/mwparserfromhell.egg-info/top_level.txt
new file mode 100644
index 0000000..7b0f32d
--- /dev/null
+++ b/src/mwparserfromhell.egg-info/top_level.txt
@@ -0,0 +1 @@
+mwparserfromhell
diff --git a/src/mwparserfromhell/__init__.py b/src/mwparserfromhell/__init__.py
index 4d9c830..aeb8fad 100644
--- a/src/mwparserfromhell/__init__.py
+++ b/src/mwparserfromhell/__init__.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2012-2021 Ben Kurtovic <ben.kurtovic@gmail.com>
+# Copyright (C) 2012-2022 Ben Kurtovic <ben.kurtovic@gmail.com>
 #
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
@@ -25,9 +25,9 @@ outrageously powerful parser for `MediaWiki <https://www.mediawiki.org>`_ wikico
 """
 
 __author__ = "Ben Kurtovic"
-__copyright__ = "Copyright (C) 2012-2021 Ben Kurtovic"
+__copyright__ = "Copyright (C) 2012-2022 Ben Kurtovic"
 __license__ = "MIT License"
-__version__ = "0.6.4"
+__version__ = "0.7.dev0"
 __email__ = "ben.kurtovic@gmail.com"
 
 from . import definitions, nodes, parser, smart_list, string_mixin, utils, wikicode
diff --git a/tests/MWPFHTestCase.tmlanguage b/tests/MWPFHTestCase.tmlanguage
deleted file mode 100644
index e6ea7f0..0000000
--- a/tests/MWPFHTestCase.tmlanguage
+++ /dev/null
@@ -1,130 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>fileTypes</key>
-	<array>
-		<string>mwtest</string>
-	</array>
-	<key>name</key>
-	<string>MWParserFromHell Test Case</string>
-	<key>patterns</key>
-	<array>
-		<dict>
-			<key>match</key>
-			<string>---</string>
-			<key>name</key>
-			<string>markup.heading.divider.mwpfh</string>
-		</dict>
-		<dict>
-			<key>captures</key>
-			<dict>
-				<key>1</key>
-				<dict>
-					<key>name</key>
-					<string>keyword.other.name.mwpfh</string>
-				</dict>
-				<key>2</key>
-				<dict>
-					<key>name</key>
-					<string>variable.other.name.mwpfh</string>
-				</dict>
-			</dict>
-			<key>match</key>
-			<string>(name:)\s*(\w*)</string>
-			<key>name</key>
-			<string>meta.name.mwpfh</string>
-		</dict>
-		<dict>
-			<key>captures</key>
-			<dict>
-				<key>1</key>
-				<dict>
-					<key>name</key>
-					<string>keyword.other.label.mwpfh</string>
-				</dict>
-				<key>2</key>
-				<dict>
-					<key>name</key>
-					<string>comment.line.other.label.mwpfh</string>
-				</dict>
-			</dict>
-			<key>match</key>
-			<string>(label:)\s*(.*)</string>
-			<key>name</key>
-			<string>meta.label.mwpfh</string>
-		</dict>
-		<dict>
-			<key>captures</key>
-			<dict>
-				<key>1</key>
-				<dict>
-					<key>name</key>
-					<string>keyword.other.input.mwpfh</string>
-				</dict>
-				<key>2</key>
-				<dict>
-					<key>name</key>
-					<string>string.quoted.double.input.mwpfh</string>
-				</dict>
-			</dict>
-			<key>match</key>
-			<string>(input:)\s*(.*)</string>
-			<key>name</key>
-			<string>meta.input.mwpfh</string>
-		</dict>
-		<dict>
-			<key>captures</key>
-			<dict>
-				<key>1</key>
-				<dict>
-					<key>name</key>
-					<string>keyword.other.output.mwpfh</string>
-				</dict>
-			</dict>
-			<key>match</key>
-			<string>(output:)</string>
-			<key>name</key>
-			<string>meta.output.mwpfh</string>
-		</dict>
-		<dict>
-			<key>captures</key>
-			<dict>
-				<key>1</key>
-				<dict>
-					<key>name</key>
-					<string>support.language.token.mwpfh</string>
-				</dict>
-			</dict>
-			<key>match</key>
-			<string>(\w+)\s*\(</string>
-			<key>name</key>
-			<string>meta.name.token.mwpfh</string>
-		</dict>
-		<dict>
-			<key>captures</key>
-			<dict>
-				<key>1</key>
-				<dict>
-					<key>name</key>
-					<string>variable.parameter.token.mwpfh</string>
-				</dict>
-			</dict>
-			<key>match</key>
-			<string>(\w+)\s*(=)</string>
-			<key>name</key>
-			<string>meta.name.parameter.token.mwpfh</string>
-		</dict>
-		<dict>
-			<key>match</key>
-			<string>".*?"</string>
-			<key>name</key>
-			<string>string.quoted.double.mwpfh</string>
-		</dict>
-	</array>
-	<key>scopeName</key>
-	<string>text.mwpfh</string>
-	<key>uuid</key>
-	<string>cd3e2ffa-a57d-4c40-954f-1a2e87ffd638</string>
-</dict>
-</plist>