# Path: wikitextparser/_config.py
# def _plant_trie(strings: _Iterable[str]) -> dict:
# def _pattern(trie: dict) -> str:
# def regex_pattern(words: _Iterable[str]) -> bytes:
# _HTML_TAG_NAME = regex_pattern(_valid_html_tag_names) + br'\b'
# 
# Path: wikitextparser/_spans.py
# BARE_EXTERNAL_LINK = BARE_EXTERNAL_LINK_SCHEMES + EXTERNAL_LINK_URL_TAIL
# 
# END_TAG_PATTERN = rb'(?<end_tag></{name}(?:>|[' + SPACE_CHARS + rb'][^>]*+>))'
# 
# EXTERNAL_LINK_URL_TAIL = (
#     rb'(?>' + LITERAL_IPV6_AND_TAIL + rb'|' + VALID_URL_CHARS + rb')')
# 
# INVALID_URL_CHARS = rb' \t\n"<>\[\]'
# 
# PARSABLE_TAG_EXTENSION_NAME = regex_pattern(
#     _parsable_tag_extensions)
# 
# START_TAG_PATTERN = ( # noqa
#     rb'(?<start_tag>'
#         rb'<{name}' + ATTRS_PATTERN +
#         rb'[' + SPACE_CHARS + rb']*+'
#         rb'(?:(?<self_closing>/[' + SPACE_CHARS + b']*+>)|>)'
#     rb')')
# 
# def parse_to_spans(byte_array: bytearray) -> Dict[str, list]:
#     """Calculate and set self._type_to_spans.
# 
#     Extracted spans will be removed from byte_array.
#     The result is a dictionary containing lists of spans:
#     {
#         'Comment': comment_spans,
#         'ExtTag': extension_tag_spans,
#         'Parameter': parameter_spans,
#         'ParserFunction': parser_function_spans,
#         'Template': template_spans,
#         'WikiLink': wikilink_spans,
#     }
#     """
#     comment_spans = []
#     cms_append = comment_spans.append
#     extension_tag_spans = []
#     ets_append = extension_tag_spans.append
#     wikilink_spans = []
#     wls_append = wikilink_spans.append
#     parameter_spans = []
#     pms_append = parameter_spans.append
#     parser_function_spans = []
#     pfs_append = parser_function_spans.append
#     template_spans = []
#     tls_append = template_spans.append
#     # <extension tags>
#     extract_tag_extensions(
#         byte_array, ets_append, cms_append, None, None,
#         pms_append, pfs_append, tls_append, wls_append)
#     _parse_sub_spans(
#         byte_array, 0, None, pms_append, pfs_append, tls_append, wls_append)
#     return {
#         'Comment': comment_spans,
#         'ExtensionTag': sorted(extension_tag_spans),
#         'Parameter': sorted(parameter_spans),
#         'ParserFunction': sorted(parser_function_spans),
#         'Template': sorted(template_spans),
#         'WikiLink': sorted(wikilink_spans)}


from bisect import bisect_left, bisect_right, insort_right
from copy import deepcopy
from html import unescape
from itertools import islice
from operator import attrgetter
from typing import (
    Dict, Generator, Iterable, List, MutableSequence, Optional, Tuple, Union)
from warnings import warn
from regex import DOTALL, IGNORECASE, MULTILINE, VERBOSE, \
    compile as regex_compile, finditer, search, match
from wcwidth import wcswidth
from ._config import (
    _HTML_TAG_NAME, _bare_external_link_schemes, _tag_extensions,
    regex_pattern, _parsable_tag_extensions)
from ._spans import (
    BARE_EXTERNAL_LINK, END_TAG_PATTERN, EXTERNAL_LINK_URL_TAIL,
    INVALID_URL_CHARS, PARSABLE_TAG_EXTENSION_NAME, START_TAG_PATTERN,
    parse_to_spans)
    from ._tag import Tag
    from ._parser_function import ParserFunction
    from ._template import Template
    from ._wikilink import WikiLink
    from ._comment_bold_italic import Comment, Bold, Italic
    from ._externallink import ExternalLink
    from ._section import Section
    from ._wikilist import WikiList, LIST_PATTERN_FORMAT
    from ._table import Table
    from ._parameter import Parameter
        if name:
            # There is a name but it is not in TAG_EXTENSIONS.
            reversed_start_matches = reversed([m for m in regex_compile(
                START_TAG_PATTERN.replace(
                    rb'{name}', rb'(?P<name>' + name.encode() + rb')')
            ).finditer(shadow)])
            end_search = regex_compile(END_TAG_PATTERN.replace(
                b'{name}', name.encode())).search
        else:
            reversed_start_matches = reversed(
                [m for m in NAME_CAPTURING_HTML_START_TAG_FINDITER(shadow)])
        shadow_copy = shadow[:]
        spans = type_to_spans.setdefault('Tag', [])
        span_tuple_to_span_get = {(s[0], s[1]): s for s in spans}.get
        spans_append = spans.append
        for start_match in reversed_start_matches:
            if start_match['self_closing']:
                # Don't look for the end tag
                ms, me = start_match.span()
                span = [ss + ms, ss + me, None, shadow_copy[ms:me]]
            else:
                # look for the end-tag
                sms, sme = start_match.span()
                if name:
                    # the end_search is already available
                    # noinspection PyUnboundLocalVariable
                    end_match = end_search(shadow_copy, sme)
                else:
                    # build end_search according to start tag name
                    end_match = search(

# Path: wikitextparser/_config.py
# def _plant_trie(strings: _Iterable[str]) -> dict:
# def _pattern(trie: dict) -> str:
# def regex_pattern(words: _Iterable[str]) -> bytes:
# _HTML_TAG_NAME = regex_pattern(_valid_html_tag_names) + br'\b'
# 
# Path: wikitextparser/_spans.py
# BARE_EXTERNAL_LINK = BARE_EXTERNAL_LINK_SCHEMES + EXTERNAL_LINK_URL_TAIL
# 
# END_TAG_PATTERN = rb'(?<end_tag></{name}(?:>|[' + SPACE_CHARS + rb'][^>]*+>))'
# 
# EXTERNAL_LINK_URL_TAIL = (
#     rb'(?>' + LITERAL_IPV6_AND_TAIL + rb'|' + VALID_URL_CHARS + rb')')
# 
# INVALID_URL_CHARS = rb' \t\n"<>\[\]'
# 
# PARSABLE_TAG_EXTENSION_NAME = regex_pattern(
#     _parsable_tag_extensions)
# 
# START_TAG_PATTERN = ( # noqa
#     rb'(?<start_tag>'
#         rb'<{name}' + ATTRS_PATTERN +
#         rb'[' + SPACE_CHARS + rb']*+'
#         rb'(?:(?<self_closing>/[' + SPACE_CHARS + b']*+>)|>)'
#     rb')')
# 
# def parse_to_spans(byte_array: bytearray) -> Dict[str, list]:
#     """Calculate and set self._type_to_spans.
# 
#     Extracted spans will be removed from byte_array.
#     The result is a dictionary containing lists of spans:
#     {
#         'Comment': comment_spans,
#         'ExtTag': extension_tag_spans,
#         'Parameter': parameter_spans,
#         'ParserFunction': parser_function_spans,
#         'Template': template_spans,
#         'WikiLink': wikilink_spans,
#     }
#     """
#     comment_spans = []
#     cms_append = comment_spans.append
#     extension_tag_spans = []
#     ets_append = extension_tag_spans.append
#     wikilink_spans = []
#     wls_append = wikilink_spans.append
#     parameter_spans = []
#     pms_append = parameter_spans.append
#     parser_function_spans = []
#     pfs_append = parser_function_spans.append
#     template_spans = []
#     tls_append = template_spans.append
#     # <extension tags>
#     extract_tag_extensions(
#         byte_array, ets_append, cms_append, None, None,
#         pms_append, pfs_append, tls_append, wls_append)
#     _parse_sub_spans(
#         byte_array, 0, None, pms_append, pfs_append, tls_append, wls_append)
#     return {
#         'Comment': comment_spans,
#         'ExtensionTag': sorted(extension_tag_spans),
#         'Parameter': sorted(parameter_spans),
#         'ParserFunction': sorted(parser_function_spans),
#         'Template': sorted(template_spans),
#         'WikiLink': sorted(wikilink_spans)}


# Path: wikitextparser/_wikitext.py
from bisect import bisect_left, bisect_right, insort_right
from copy import deepcopy
from html import unescape
from itertools import islice
from operator import attrgetter
from typing import (
    Dict, Generator, Iterable, List, MutableSequence, Optional, Tuple, Union)
from warnings import warn
from regex import DOTALL, IGNORECASE, MULTILINE, VERBOSE, \
    compile as regex_compile, finditer, search, match
from wcwidth import wcswidth
from ._config import (
    _HTML_TAG_NAME, _bare_external_link_schemes, _tag_extensions,
    regex_pattern, _parsable_tag_extensions)
from ._spans import (
    BARE_EXTERNAL_LINK, END_TAG_PATTERN, EXTERNAL_LINK_URL_TAIL,
    INVALID_URL_CHARS, PARSABLE_TAG_EXTENSION_NAME, START_TAG_PATTERN,
    parse_to_spans)
    from ._tag import Tag
    from ._parser_function import ParserFunction
    from ._template import Template
    from ._wikilink import WikiLink
    from ._comment_bold_italic import Comment, Bold, Italic
    from ._externallink import ExternalLink
    from ._section import Section
    from ._wikilist import WikiList, LIST_PATTERN_FORMAT
    from ._table import Table
    from ._parameter import Parameter

        if name:
            # There is a name but it is not in TAG_EXTENSIONS.
            reversed_start_matches = reversed([m for m in regex_compile(
                START_TAG_PATTERN.replace(
                    rb'{name}', rb'(?P<name>' + name.encode() + rb')')
            ).finditer(shadow)])
            end_search = regex_compile(END_TAG_PATTERN.replace(
                b'{name}', name.encode())).search
        else:
            reversed_start_matches = reversed(
                [m for m in NAME_CAPTURING_HTML_START_TAG_FINDITER(shadow)])
        shadow_copy = shadow[:]
        spans = type_to_spans.setdefault('Tag', [])
        span_tuple_to_span_get = {(s[0], s[1]): s for s in spans}.get
        spans_append = spans.append
        for start_match in reversed_start_matches:
            if start_match['self_closing']:
                # Don't look for the end tag
                ms, me = start_match.span()
                span = [ss + ms, ss + me, None, shadow_copy[ms:me]]
            else:
                # look for the end-tag
                sms, sme = start_match.span()
                if name:
                    # the end_search is already available
                    # noinspection PyUnboundLocalVariable
                    end_match = end_search(shadow_copy, sme)
                else:
                    # build end_search according to start tag name
                    end_match = search(

                        END_TAG_PATTERN.replace(