# -*- coding: utf-8 -*- vim: fileencoding=utf-8 :

import collections.abc
import contextlib
import sys
import textwrap
import weakref
from abc import ABC
from types import TracebackType
from weakref import ReferenceType

from debian._deb822_repro._util import (combine_into_replacement, BufferingIterator,
                                        len_check_iterator,
                                        )
from debian._deb822_repro.formatter import (
    FormatterContentToken, one_value_per_line_trailing_separator, format_field,
)
from debian._deb822_repro.tokens import (
    Deb822Token, Deb822ValueToken, Deb822SemanticallySignificantWhiteSpace,
    Deb822SpaceSeparatorToken, Deb822CommentToken, Deb822WhitespaceToken,
    Deb822ValueContinuationToken, Deb822NewlineAfterValueToken, Deb822CommaToken,
    Deb822FieldNameToken, Deb822FieldSeparatorToken, Deb822ErrorToken,
    tokenize_deb822_file, comma_split_tokenizer, whitespace_split_tokenizer,
)
from debian._deb822_repro.types import AmbiguousDeb822FieldKeyError, SyntaxOrParseError
from debian._util import (
    resolve_ref, LinkedList, LinkedListNode, OrderedSet, _strI, default_field_sort_key,
)

try:
    from typing import (
        Iterable, Iterator, List, Union, Dict, Optional, Callable, Any, Generic, Type, Tuple, IO,
        cast, overload, Mapping, TYPE_CHECKING,
)
    from debian._util import T
    # for some reason, pylint does not see that Commentish is used in typing
    from debian._deb822_repro.types import (  # pylint: disable=unused-import
        ST, VE, TE,
        ParagraphKey, TokenOrElement, Commentish, ParagraphKeyBase,
        FormatterCallback,
    )
    if TYPE_CHECKING:
        StreamingValueParser = Callable[[Deb822Token, BufferingIterator[Deb822Token]], VE]
        StrToValueParser = Callable[[str], Iterable[Union['Deb822Token', VE]]]
        KVPNode = LinkedListNode['Deb822KeyValuePairElement']
    else:
        StreamingValueParser = None
        StrToValueParser = None
        KVPNode = None
except ImportError:
    if not TYPE_CHECKING:
        # pylint: disable=unnecessary-lambda-assignment
        cast = lambda t, v: v
        overload = lambda f: None


class ValueReference(Generic[TE]):

    """Reference to a value inside a Deb822 paragraph

    This is useful for cases where want to modify values "in-place" or maybe
    conditionally remove a value after looking at it.

    ValueReferences can be invalidated by various changes or actions performed
    to the underlying provider of the value reference.  As an example, sorting
    a list of values will generally invalidate all ValueReferences related to
    that list.

    The ValueReference will raise validity issues where it detects them but most
    of the time it will not notice.  As a means to this end,  the ValueReference
    will *not* keep a strong reference to the underlying value.  This enables it
    to detect when the container goes out of scope.  However, keep in mind that
    the timeliness of garbage collection is implementation defined (e.g., pypy
    does not use ref-counting).
    """

    __slots__ = ('_node', '_render', '_value_factory', '_removal_handler', '_mutation_notifier')

    def __init__(self,
                 node,  # type: LinkedListNode[TE]
                 render,  # type: Callable[[TE], str]
                 value_factory,  # type: Callable[[str], TE]
                 removal_handler,  # type: Callable[[LinkedListNode[TokenOrElement]], None]
                 mutation_notifier,  # type: Optional[Callable[[], None]]
                 ):
        self._node = weakref.ref(node)  # type: Optional[ReferenceType[LinkedListNode[TE]]]
        self._render = render
        self._value_factory = value_factory
        self._removal_handler = removal_handler
        self._mutation_notifier = mutation_notifier

    def _resolve_node(self):
        # type: () -> LinkedListNode[TE]
        # NB: We check whether the "ref" itself is None (instead of the ref resolving to None)
        # This enables us to tell the difference between "known removal" vs. "garbage collected"
        if self._node is None:
            raise RuntimeError("Cannot use ValueReference after remove()")
        node = self._node()
        if node is None:
            raise RuntimeError("ValueReference is invalid (garbage collected)")
        return node

    @property
    def value(self):
        # type: () -> str
        """Resolve the reference into a str"""
        return self._render(self._resolve_node().value)

    @value.setter
    def value(self, new_value):
        # type: (str) -> None
        """Update the reference value

        Updating the value via this method will *not* invalidate the reference (or other
        references to the same container).

        This can raise an exception of the new value does not follow the requirements
        for the referenced values.  As an example, values in whitespace separated
        lists cannot contain spaces and would trigger an exception.
        """
        self._resolve_node().value = self._value_factory(new_value)
        if self._mutation_notifier is not None:
            self._mutation_notifier()

    def remove(self):
        # type: () -> None
        """Remove the underlying value

        This will invalidate the ValueReference (and any other ValueReferences pointing
        to that exact value).  The validity of other ValueReferences to that container
        remains unaffected.
        """
        self._removal_handler(cast('LinkedListNode[TokenOrElement]', self._resolve_node()))
        self._node = None


if sys.version_info >= (3, 9) or TYPE_CHECKING:
    _Deb822ParsedTokenList_ContextManager = contextlib.AbstractContextManager[T]
else:
    # Python 3.5 - 3.8 compat - we are not allowed to subscript the abc.Iterator
    # - use this little hack to work around it
    # Note that Python 3.5 is so old that it does not have AbstractContextManager,
    # so we re-implement it here.
    class _Deb822ParsedTokenList_ContextManager(Generic[T]):

        def __enter__(self):
            return self

        def __exit__(self, exc_type, exc_val, exc_tb):
            return None


class Deb822ParsedTokenList(Generic[VE, ST],
                            _Deb822ParsedTokenList_ContextManager['Deb822ParsedTokenList[VE, ST]']
                            ):

    def __init__(self,
                 kvpair_element,  # type: 'Deb822KeyValuePairElement'
                 interpreted_value_element,  # type: 'List[TokenOrElement]'
                 vtype,  # type: Type[VE]
                 stype,  # type: Type[ST]
                 str2value_parser,  # type: StrToValueParser[VE]
                 default_separator_factory,  # type: Callable[[], ST]
                 render,  # type: Callable[[VE], str]
                 ):
        # type: (...) -> None
        self._kvpair_element = kvpair_element
        self._token_list = LinkedList(interpreted_value_element)
        self._vtype = vtype
        self._stype = stype
        self._str2value_parser = str2value_parser
        self._default_separator_factory = default_separator_factory
        self._value_factory = _parser_to_value_factory(str2value_parser, vtype)
        self._render = render
        self._format_preserve_original_formatting = True
        self._formatter = one_value_per_line_trailing_separator  # type: FormatterCallback
        self._changed = False
        self.__continuation_line_char = None  # type: Optional[str]
        assert self._token_list
        last_token = self._token_list.tail

        if last_token is not None and isinstance(last_token, Deb822NewlineAfterValueToken):
            # We always remove the last newline (if present), because then
            # adding values will happen after the last value rather than on
            # a new line by default.
            #
            # On write, we always ensure the value ends on a newline (even
            # if it did not before).  This is simpler and should be a
            # non-issue in practise.
            self._token_list.pop()

    def __iter__(self):
        # type: () -> Iterator[str]
        yield from (self._render(v) for v in self.value_parts)

    def __bool__(self):
        # type: () -> bool
        return next(iter(self), None) is not None

    def __exit__(self,
                 exc_type,  # type: Optional[Type[BaseException]]
                 exc_val,  # type: Optional[BaseException]
                 exc_tb,  # type: Optional[TracebackType]
                 ):
        # type: (...) -> Optional[bool]
        if exc_type is None and self._changed:
            self._update_field()
        return super().__exit__(exc_type, exc_val, exc_tb)

    @property
    def value_parts(self):
        # type: () -> Iterator[VE]
        yield from (v for v in self._token_list if isinstance(v, self._vtype))

    def _mark_changed(self):
        # type: () -> None
        self._changed = True

    def iter_value_references(self):
        # type: () -> Iterator[ValueReference[VE]]
        """Iterate over all values in the list (as ValueReferences)

        This is useful for doing inplace modification of the values or even
        streaming removal of field values.  It is in general also more
        efficient when more than one value is updated or removed.
        """
        yield from (ValueReference(
            cast('LinkedListNode[VE]', n),
            self._render,
            self._value_factory,
            self._remove_node,
            self._mark_changed,
        ) for n in self._token_list.iter_nodes()
            if isinstance(n.value, self._vtype)
        )

    def append_separator(self, space_after_separator=True):
        # type: (bool) -> None

        separator_token = self._default_separator_factory()
        if separator_token.is_whitespace:
            space_after_separator = False

        self._changed = True
        self._append_continuation_line_token_if_necessary()
        self._token_list.append(separator_token)

        if space_after_separator and not separator_token.is_whitespace:
            self._token_list.append(Deb822WhitespaceToken(' '))

    def replace(self, orig_value, new_value):
        # type: (str, str) -> None
        """Replace the first instance of a value with another

        This method will *not* affect the validity of ValueReferences.
        """
        vtype = self._vtype
        for node in self._token_list.iter_nodes():
            if isinstance(node.value, vtype) and self._render(node.value) == orig_value:
                node.value = self._value_factory(new_value)
                self._changed = True
                break
        else:
            raise ValueError("list.replace(x, y): x not in list")

    def remove(self, value):
        # type: (str) -> None
        """Remove the first instance of a value

        Removal will invalidate ValueReferences to the value being removed.
        ValueReferences to other values will be unaffected.
        """
        vtype = self._vtype
        for node in self._token_list.iter_nodes():
            if isinstance(node.value, vtype) and self._render(node.value) == value:
                node_to_remove = node
                break
        else:
            raise ValueError("list.remove(x): x not in list")

        return self._remove_node(node_to_remove)

    def _remove_node(self, node_to_remove):
        # type: (LinkedListNode[TokenOrElement]) -> None
        vtype = self._vtype
        self._changed = True

        # We naively want to remove the node and every thing to the left of it
        # until the previous value.  That is the basic idea for now (ignoring
        # special-cases for now).
        #
        # Example:
        #
        # """
        # Multiline-Keywords: bar[
        # # Comment about foo
        #                     foo]
        #                     baz
        # Keywords: bar[ foo] baz
        # Comma-List: bar[, foo], baz,
        # Multiline-Comma-List: bar[,
        # # Comment about foo
        #                       foo],
        #                       baz,
        # """
        #
        # Assuming we want to remove "foo" for the lists, the []-markers
        # show what we aim to remove.  This has the nice side-effect of
        # preserving whether nor not the value has a trailing separator.
        # Note that we do *not* attempt to repair missing separators but
        # it may fix duplicated separators by "accident".
        #
        # Now, there are two special cases to be aware of, where this approach
        # has short comings:
        #
        # 1) If foo is the only value (in which case, "delete everything"
        #    is the only option).
        # 2) If foo is the first value
        # 3) If foo is not the only value on the line and we see a comment
        #    inside the deletion range.
        #
        # For 2) + 3), we attempt to flip and range to delete and every
        # thing after it (up to but exclusion "baz") instead.  This
        # definitely fixes 3), but 2) has yet another corner case, namely:
        #
        # """
        # Multiline-Comma-List: foo,
        # # Remark about bar
        #                       bar,
        # Another-Case: foo
        # # Remark, also we use leading separator
        #             , bar
        # """
        #
        # The options include:
        #
        #  A) Discard the comment - brain-dead simple
        #  B) Hoist the comment up to a field comment, but then what if the
        #     field already has a comment?
        #  C) Clear the first value line leaving just the newline and
        #     replace the separator before "bar" (if present) with a space.
        #     (leaving you with the value of the form "\n# ...\n      bar")
        #

        first_value_on_lhs = None  # type: Optional[LinkedListNode[TokenOrElement]]
        first_value_on_rhs = None  # type: Optional[LinkedListNode[TokenOrElement]]
        comment_before_previous_value = False
        comment_before_next_value = False
        for past_node in node_to_remove.iter_previous(skip_current=True):
            past_token = past_node.value
            if isinstance(past_token, Deb822Token) and past_token.is_comment:
                comment_before_previous_value = True
                continue
            if isinstance(past_token, vtype):
                first_value_on_lhs = past_node
                break

        for future_node in node_to_remove.iter_next(skip_current=True):
            future_token = future_node.value
            if isinstance(future_token, Deb822Token) and future_token.is_comment:
                comment_before_next_value = True
                continue
            if isinstance(future_token, vtype):
                first_value_on_rhs = future_node
                break

        if first_value_on_rhs is None and first_value_on_lhs is None:
            # This was the last value, just remove everything.
            self._token_list.clear()
            return

        if first_value_on_lhs is not None and not comment_before_previous_value:
            # Delete left
            delete_lhs_of_node = True
        elif first_value_on_rhs is not None and not comment_before_next_value:
            # Delete right
            delete_lhs_of_node = False
        else:
            # There is a comment on either side (or no value on one and a
            # comment and the other). Keep it simple, we just delete to
            # one side (preferring deleting to left if possible).
            delete_lhs_of_node = first_value_on_lhs is not None

        if delete_lhs_of_node:
            first_remain_lhs = first_value_on_lhs
            first_remain_rhs = node_to_remove.next_node
        else:
            first_remain_lhs = node_to_remove.previous_node
            first_remain_rhs = first_value_on_rhs

        # Actual deletion - with some manual labour to update HEAD/TAIL of
        # the list in case we do a "delete everything left/right this node".
        if first_remain_lhs is None:
            self._token_list.head_node = first_remain_rhs
        if first_remain_rhs is None:
            self._token_list.tail_node = first_remain_lhs
        LinkedListNode.link_nodes(first_remain_lhs, first_remain_rhs)

    def append(self, value):
        # type: (str) -> None
        vt = self._value_factory(value)
        self.append_value(vt)

    def append_value(self, vt):
        # type: (VE) -> None
        value_parts = self._token_list
        if value_parts:
            needs_separator = False
            stype = self._stype
            vtype = self._vtype
            for t in reversed(value_parts):
                if isinstance(t, vtype):
                    needs_separator = True
                    break
                if isinstance(t, stype):
                    break

            if needs_separator:
                self.append_separator()
        else:
            # Looks nicer if there is a space before the very first value
            self._token_list.append(Deb822WhitespaceToken(' '))
        self._append_continuation_line_token_if_necessary()
        self._changed = True
        value_parts.append(vt)

    def _previous_is_newline(self):
        # type: () -> bool
        tail = self._token_list.tail
        return tail is not None and tail.convert_to_text().endswith("\n")

    def append_newline(self):
        # type: () -> None
        if self._previous_is_newline():
            raise ValueError("Cannot add a newline after a token that ends on a newline")
        self._token_list.append(Deb822NewlineAfterValueToken())

    def append_comment(self, comment_text):
        # type: (str) -> None
        tail = self._token_list.tail
        if tail is None or not tail.convert_to_text().endswith('\n'):
            self.append_newline()
        comment_token = Deb822CommentToken(_format_comment(comment_text))
        self._token_list.append(comment_token)

    @property
    def _continuation_line_char(self):
        # type: () -> str
        char = self.__continuation_line_char
        if char is None:
            # Use ' ' by default but match the existing field if possible.
            char = ' '
            for token in self._token_list:
                if isinstance(token, Deb822ValueContinuationToken):
                    char = token.text
                    break
            self.__continuation_line_char = char
        return char

    def _append_continuation_line_token_if_necessary(self):
        # type: () -> None
        tail = self._token_list.tail
        if tail is not None and tail.convert_to_text().endswith("\n"):
            self._token_list.append(Deb822ValueContinuationToken(self._continuation_line_char))

    def reformat_when_finished(self):
        # type: () -> None
        self._enable_reformatting()
        self._changed = True

    def _enable_reformatting(self):
        # type: () -> None
        self._format_preserve_original_formatting = False

    def no_reformatting_when_finished(self):
        # type: () -> None
        self._format_preserve_original_formatting = True

    def value_formatter(self,
                        formatter,  # type: FormatterCallback
                        force_reformat=False,  # type: bool
                        ):
        # type: (...) -> None
        """Use a custom formatter when formatting the value

        :param formatter: A formatter (see debian._deb822_repro.formatter.format_field
          for details)
        :param force_reformat: If True, always reformat the field even if there are
          no (other) changes performed.  By default, fields are only reformatted if
          they are changed.
        """
        self._formatter = formatter
        self._format_preserve_original_formatting = False
        if force_reformat:
            self._changed = True

    def clear(self):
        # type: () -> None
        """Like list.clear() - removes all content (including comments and spaces)"""
        if self._token_list:
            self._changed = True
        self._token_list.clear()

    def _iter_content_as_tokens(self):
        # type: () -> Iterable[Deb822Token]
        for te in self._token_list:
            if isinstance(te, Deb822Element):
                yield from te.iter_tokens()
            else:
                yield te

    def _generate_reformatted_field_content(self):
        # type: () -> str
        separator_token = self._default_separator_factory()
        vtype = self._vtype
        stype = self._stype
        token_list = self._token_list

        def _token_iter():
            # type: () -> Iterator[FormatterContentToken]
            text = ""  # type: str
            for te in token_list:
                if isinstance(te, Deb822Token):
                    if te.is_comment:
                        yield FormatterContentToken.comment_token(te.text)
                    elif isinstance(te, stype):
                        text = te.text
                        yield FormatterContentToken.separator_token(text)
                else:
                    assert isinstance(te, vtype)
                    text = te.convert_to_text()
                    yield FormatterContentToken.value_token(text)

        return format_field(self._formatter,
                            self._kvpair_element.field_name,
                            FormatterContentToken.separator_token(separator_token.text),
                            _token_iter()
                            )

    def _generate_field_content(self):
        # type: () -> str
        return "".join(t.text for t in self._iter_content_as_tokens())

    def _update_field(self):
        # type: () -> None
        kvpair_element = self._kvpair_element
        field_name = kvpair_element.field_name
        token_list = self._token_list
        tail = token_list.tail
        had_tokens = False

        for t in self._iter_content_as_tokens():
            had_tokens = True
            if not t.is_comment and not t.is_whitespace:
                break
        else:
            if had_tokens:
                raise ValueError("Field must be completely empty or have content "
                                 "(i.e. non-whitespace and non-comments)")
        if tail is not None:
            if isinstance(tail, Deb822Token) and tail.is_comment:
                raise ValueError("Fields must not end on a comment")
            if not tail.convert_to_text().endswith("\n"):
                # Always end on a newline
                self.append_newline()

            if self._format_preserve_original_formatting:
                value_text = self._generate_field_content()
                text = ':'.join((field_name, value_text))
            else:
                text = self._generate_reformatted_field_content()

            new_content = text.splitlines(keepends=True)
        else:
            # Special-case for the empty list which will be mapped to
            # an empty field.  Always end on a newline (avoids errors
            # if there is a field after this)
            new_content = [field_name + ":\n"]

        # As absurd as it might seem, it is easier to just use the parser to
        # construct the AST correctly
        deb822_file = parse_deb822_file(iter(new_content))
        error_token = deb822_file.find_first_error_element()
        if error_token:
            # _print_ast(deb822_file)
            raise ValueError("Syntax error in new field value for " + field_name)
        paragraph = next(iter(deb822_file))
        assert isinstance(paragraph, Deb822NoDuplicateFieldsParagraphElement)
        new_kvpair_element = paragraph.get_kvpair_element(field_name)
        assert new_kvpair_element is not None
        kvpair_element.value_element = new_kvpair_element.value_element
        self._changed = False

    def sort_elements(self, *,
                      key=None,  # type: Optional[Callable[[VE], Any]]
                      reverse=False  # type: bool
                      ):
        # type: (...) -> None
        """Sort the elements (abstract values) in this list.

        This method will sort the logical values of the list. It will
        attempt to preserve comments associated with a given value where
        possible.  Whether space and separators are preserved depends on
        the contents of the field as well as the formatting settings.

        Sorting (without reformatting) is likely to leave you with "awkward"
        whitespace. Therefore, you almost always want to apply reformatting
        such as the reformat_when_finished() method.

        Sorting will invalidate all ValueReferences.
        """
        comment_start_node = None
        vtype = self._vtype
        stype = self._stype

        def key_func(x):
            # type: (Tuple[VE, List[TokenOrElement]]) -> Any
            if key:
                return key(x[0])
            return x[0].convert_to_text()

        parts = []

        for node in self._token_list.iter_nodes():
            value = node.value
            if isinstance(value, Deb822Token) and value.is_comment:
                if comment_start_node is None:
                    comment_start_node = node
                continue

            if isinstance(value, vtype):
                comments = []
                if comment_start_node is not None:
                    for keep_node in comment_start_node.iter_next(skip_current=False):
                        if keep_node is node:
                            break
                        comments.append(keep_node.value)
                parts.append((value, comments))
                comment_start_node = None

        parts.sort(key=key_func, reverse=reverse)

        self._changed = True
        self._token_list.clear()
        first_value = True

        separator_is_space = self._default_separator_factory().is_whitespace

        for value, comments in parts:
            if first_value:
                first_value = False
                if comments:
                    # While unlikely, there could be a separator between the comments.
                    # It would be in the way and we remove it.
                    comments = [x for x in comments if not isinstance(x, stype)]
                    # Comments cannot start the field, so inject a newline to
                    # work around that
                    self.append_newline()
            else:
                if not separator_is_space and not any(isinstance(x, stype) for x in comments):
                    # While unlikely, you can hide a comma between two comments and expect
                    # us to preserve it.  However, the more common case is that the separator
                    # appeared before the comments and was thus omitted (leaving us to re-add
                    # it here).
                    self.append_separator(space_after_separator=False)
                if comments:
                    self.append_newline()
                else:
                    self._token_list.append(Deb822WhitespaceToken(' '))

            self._token_list.extend(comments)
            self.append_value(value)

    def sort(self,
             *,
             key=None,  # type: Optional[Callable[[str], Any]]
             **kwargs  # type: Any
             ):
        # type: (...) -> None
        """Sort the values (rendered as str) in this list.

        This method will sort the logical values of the list. It will
        attempt to preserve comments associated with a given value where
        possible.  Whether space and separators are preserved depends on
        the contents of the field as well as the formatting settings.

        Sorting (without reformatting) is likely to leave you with "awkward"
        whitespace. Therefore, you almost always want to apply reformatting
        such as the reformat_when_finished() method.

        Sorting will invalidate all ValueReferences.
        """
        if key is not None:
            render = self._render
            kwargs['key'] = lambda vt: key(render(vt))
        self.sort_elements(**kwargs)


class Interpretation(Generic[T]):

    def interpret(self,
                  kvpair_element,  # type: Deb822KeyValuePairElement
                  discard_comments_on_read=True  # type: bool
                  ):
        # type: (...) -> T
        raise NotImplementedError  # pragma: no cover


class GenericContentBasedInterpretation(Interpretation[T], Generic[T, VE]):

    def __init__(self,
                 tokenizer,  # type: Callable[[str], Iterable['Deb822Token']]
                 value_parser  # type: StreamingValueParser[VE]
                 ):
        # type: (...) -> None
        super().__init__()
        self._tokenizer = tokenizer
        self._value_parser = value_parser

    def _high_level_interpretation(self,
                                   kvpair_element,  # type: Deb822KeyValuePairElement
                                   token_list,  # type: List['TokenOrElement']
                                   discard_comments_on_read=True  # type: bool
                                   ):
        # type: (...) -> T
        raise NotImplementedError  # pragma: no cover

    def _parse_stream(self,
                      buffered_iterator  # type: BufferingIterator[Deb822Token]
                      ):
        # type: (...) -> Iterable[Union[Deb822Token, VE]]

        value_parser = self._value_parser
        for token in buffered_iterator:
            if isinstance(token, Deb822ValueToken):
                yield value_parser(token, buffered_iterator)
            else:
                yield token

    def _parse_kvpair(
            self,
            kvpair  # type: Deb822KeyValuePairElement
    ):
        # type: (...) -> Iterable[Union[Deb822Token, VE]]
        content = kvpair.value_element.convert_to_text()
        yield from self._parse_str(content)

    def _parse_str(self, content):
        # type: (str) -> Iterable[Union[Deb822Token, VE]]
        content_len = len(content)
        biter = BufferingIterator(len_check_iterator(content,
                                                     self._tokenizer(content),
                                                     content_len=content_len,))
        yield from len_check_iterator(content,
                                      self._parse_stream(biter),
                                      content_len=content_len,
                                      )

    def interpret(self,
                  kvpair_element,  # type: Deb822KeyValuePairElement
                  discard_comments_on_read=True  # type: bool
                  ):
        # type: (...) -> T
        token_list = []  # type: List['TokenOrElement']
        token_list.extend(self._parse_kvpair(kvpair_element))
        return self._high_level_interpretation(kvpair_element,
                                               token_list,
                                               discard_comments_on_read=discard_comments_on_read,
                                               )


def _parser_to_value_factory(parser,  # type: StrToValueParser[VE]
                             vtype,  # type: Type[VE]
                             ):
    # type: (...) -> Callable[[str], VE]
    def _value_factory(v):
        # type: (str) -> VE
        if v == '':
            raise ValueError("The empty string is not a value")
        token_iter = iter(parser(v))
        t1 = next(token_iter, None)  # type: Optional[Union[TokenOrElement]]
        t2 = next(token_iter, None)
        assert t1 is not None, 'Bad parser - it returned None (or no TE) for "' + v + '"'
        if t2 is not None:
            msg = textwrap.dedent("""\
            The input "{v}" should have been exactly one element, but the parser provided at
             least two.  This can happen with unnecessary leading/trailing whitespace
             or including commas the value for a comma list.
            """).format(v=v)
            raise ValueError(msg)
        if not isinstance(t1, vtype):
            if isinstance(t1, Deb822Token) and (t1.is_comment or t1.is_whitespace):
                raise ValueError('The input "{v}" is whitespace or a comment: Expected a value')
            msg = 'The input "{v}" should have produced a element of type {vtype_name}, but' \
                  ' instead it produced {t1}'
            raise ValueError(msg.format(v=v, vtype_name=vtype.__name__, t1=t1))

        assert len(t1.convert_to_text()) == len(v), \
            "Bad tokenizer - the token did not cover the input text" \
            " exactly ({t1_len} != {v_len}".format(
                t1_len=len(t1.convert_to_text()), v_len=len(v)
            )
        return t1

    return _value_factory


class ListInterpretation(GenericContentBasedInterpretation[Deb822ParsedTokenList[VE, ST], VE]):

    def __init__(self,
                 tokenizer,  # type: Callable[[str], Iterable['Deb822Token']]
                 value_parser,  # type: StreamingValueParser[VE]
                 vtype,  # type: Type[VE]
                 stype,  # type: Type[ST]
                 default_separator_factory,  # type: Callable[[], ST]
                 render_factory  # type: Callable[[bool], Callable[[VE], str]]
                 ):
        # type: (...) -> None
        super().__init__(tokenizer, value_parser)
        self._vtype = vtype
        self._stype = stype
        self._default_separator_factory = default_separator_factory
        self._render_factory = render_factory

    def _high_level_interpretation(self,
                                   kvpair_element,  # type: Deb822KeyValuePairElement
                                   token_list,  # type: List['TokenOrElement']
                                   discard_comments_on_read=True  # type: bool
                                   ):
        # type: (...) -> Deb822ParsedTokenList[VE, ST]
        return Deb822ParsedTokenList(
            kvpair_element,
            token_list,
            self._vtype,
            self._stype,
            self._parse_str,
            self._default_separator_factory,
            self._render_factory(discard_comments_on_read)
        )


def _parse_whitespace_list_value(token, _):
    # type: (Deb822Token, BufferingIterator[Deb822Token]) -> Deb822ParsedValueElement
    return Deb822ParsedValueElement([token])


def _is_comma_token(v):
    # type: (TokenOrElement) -> bool
    # Consume tokens until the next comma
    return isinstance(v, Deb822CommaToken)


def _parse_comma_list_value(token, buffered_iterator):
    # type: (Deb822Token, BufferingIterator[Deb822Token]) -> Deb822ParsedValueElement
    comma_offset = buffered_iterator.peek_find(_is_comma_token)
    value_parts = [token]
    if comma_offset is not None:
        # The value is followed by a comma and now we know where it ends
        value_parts.extend(buffered_iterator.peek_many(comma_offset - 1))
    else:
        # The value is the last value there is.  Consume all remaining tokens
        # and then trim from the right.
        value_parts.extend(buffered_iterator.peek_buffer())
    while value_parts and not isinstance(value_parts[-1], Deb822ValueToken):
        value_parts.pop()

    buffered_iterator.consume_many(len(value_parts) - 1)
    return Deb822ParsedValueElement(value_parts)


def _parse_uploaders_list_value(token, buffered_iterator):
    # type: (Deb822Token, BufferingIterator[Deb822Token]) -> Deb822ParsedValueElement

    # This is similar to _parse_comma_list_value *except* that there is an extra special
    # case.  Namely comma only counts as a true separator if it follows ">"
    value_parts = [token]
    comma_offset = -1  # type: Optional[int]
    while comma_offset is not None:
        comma_offset = buffered_iterator.peek_find(_is_comma_token)
        if comma_offset is not None:
            # The value is followed by a comma.  Verify that this is a terminating
            # comma (comma may appear in the name or email)
            #
            # We include value_parts[-1] to easily cope with the common case of
            # "foo <a@b.com>," where we will have 0 peeked element to examine.
            peeked_elements = [value_parts[-1]]
            peeked_elements.extend(buffered_iterator.peek_many(comma_offset - 1))
            comma_was_separator = False
            i = len(peeked_elements) - 1
            while i >= 0:
                token = peeked_elements[i]
                if isinstance(token, Deb822ValueToken):
                    if token.text.endswith(">"):
                        # The comma terminates the value
                        value_parts.extend(buffered_iterator.consume_many(i))
                        assert isinstance(value_parts[-1], Deb822ValueToken) and \
                               value_parts[-1].text.endswith('>'), "Got: " + str(value_parts)
                        comma_was_separator = True
                    break
                i -= 1
            if comma_was_separator:
                break
            value_parts.extend(buffered_iterator.consume_many(comma_offset))
            assert isinstance(value_parts[-1], Deb822CommaToken)
        else:
            # The value is the last value there is.  Consume all remaining tokens
            # and then trim from the right.
            remaining_part = buffered_iterator.peek_buffer()
            consume_elements = len(remaining_part)
            value_parts.extend(remaining_part)
            while value_parts and not isinstance(value_parts[-1], Deb822ValueToken):
                value_parts.pop()
                consume_elements -= 1
            buffered_iterator.consume_many(consume_elements)

    return Deb822ParsedValueElement(value_parts)


class Deb822Element:
    """Composite elements (consists of 1 or more tokens)"""

    __slots__ = ('_parent_element', '__weakref__')

    def __init__(self):
        # type: () -> None
        self._parent_element = None  # type: Optional[ReferenceType['Deb822Element']]

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        raise NotImplementedError  # pragma: no cover

    def iter_parts_of_type(self, only_element_or_token_type):
        # type: (Type[TE]) -> Iterable[TE]
        for part in self.iter_parts():
            if isinstance(part, only_element_or_token_type):
                yield part

    def iter_tokens(self):
        # type: () -> Iterable[Deb822Token]
        for part in self.iter_parts():
            # Control check to catch bugs early
            assert part._parent_element is not None
            if isinstance(part, Deb822Element):
                yield from part.iter_tokens()
            else:
                yield part

    def iter_recurse(self, *,
                     only_element_or_token_type=None  # type: Optional[Type[TE]]
                     ):
        # type: (...) -> Iterable[TE]
        for part in self.iter_parts():
            if only_element_or_token_type is None or isinstance(part, only_element_or_token_type):
                yield cast('TE', part)
            if isinstance(part, Deb822Element):
                yield from part.iter_recurse(only_element_or_token_type=only_element_or_token_type)

    @property
    def parent_element(self):
        # type: () -> Optional[Deb822Element]
        return resolve_ref(self._parent_element)

    @parent_element.setter
    def parent_element(self, new_parent):
        # type: (Optional[Deb822Element]) -> None
        self._parent_element = weakref.ref(new_parent) if new_parent is not None else None

    def _init_parent_of_parts(self):
        # type: () -> None
        for part in self.iter_parts():
            part.parent_element = self

    # Deliberately not a "text" property, to signal that it is not necessary cheap.
    def convert_to_text(self):
        # type: () -> str
        return "".join(t.text for t in self.iter_tokens())

    def clear_parent_if_parent(self, parent):
        # type: (Deb822Element) -> None
        if parent is self.parent_element:
            self._parent_element = None


class Deb822ErrorElement(Deb822Element):
    """Element representing elements or tokens that are out of place

    Commonly, it will just be instances of Deb822ErrorToken, but it can be other
    things.  As an example if a parser discovers out of order elements/tokens,
    it can bundle them in a Deb822ErrorElement to signal that the sequence of
    elements/tokens are invalid (even if the tokens themselves are valid).
    """

    __slots__ = ('_parts',)

    def __init__(self, parts):
        # type: (List[TokenOrElement]) -> None
        super().__init__()
        self._parts = parts
        self._init_parent_of_parts()

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from self._parts


class Deb822ValueLineElement(Deb822Element):
    """Consists of one "line" of a value"""

    __slots__ = ('_comment_element', '_continuation_line_token', '_leading_whitespace_token',
                 '_value_tokens', '_trailing_whitespace_token', '_newline_token')

    def __init__(self,
                 comment_element,  # type: Optional[Deb822CommentElement]
                 continuation_line_token,  # type: Optional[Deb822ValueContinuationToken]
                 leading_whitespace_token,  # type: Optional[Deb822WhitespaceToken]
                 value_parts,  # type: List[TokenOrElement]
                 trailing_whitespace_token,  # type: Optional[Deb822WhitespaceToken]
                 # only optional if it is the last line of the file and the file does not
                 # end with a newline.
                 newline_token  # type: Optional[Deb822WhitespaceToken]
                 ):
        # type: (...) -> None
        super().__init__()
        if comment_element is not None and continuation_line_token is None:
            raise ValueError("Only continuation lines can have comments")
        self._comment_element = comment_element  # type: Optional[Deb822CommentElement]
        self._continuation_line_token = continuation_line_token
        self._leading_whitespace_token = \
            leading_whitespace_token  # type: Optional[Deb822WhitespaceToken]
        self._value_tokens = value_parts  # type: List[TokenOrElement]
        self._trailing_whitespace_token = trailing_whitespace_token
        self._newline_token = newline_token  # type: Optional[Deb822WhitespaceToken]
        self._init_parent_of_parts()

    @property
    def comment_element(self):
        # type: () -> Optional[Deb822CommentElement]
        return self._comment_element

    @property
    def continuation_line_token(self):
        # type: () -> Optional[Deb822ValueContinuationToken]
        return self._continuation_line_token

    @property
    def newline_token(self):
        # type: () -> Optional[Deb822WhitespaceToken]
        return self._newline_token

    def add_newline_if_missing(self):
        # type: () -> None
        if self._newline_token is None:
            self._newline_token = Deb822NewlineAfterValueToken()
            self._newline_token.parent_element = self

    def _iter_content_parts(self):
        # type: () -> Iterable[TokenOrElement]
        if self._leading_whitespace_token:
            yield self._leading_whitespace_token
        yield from self._value_tokens
        if self._trailing_whitespace_token:
            yield self._trailing_whitespace_token

    def _iter_content_tokens(self):
        # type: () -> Iterable[Deb822Token]
        for part in self._iter_content_parts():
            if isinstance(part, Deb822Element):
                yield from part.iter_tokens()
            else:
                yield part

    def convert_content_to_text(self):
        # type: () -> str
        if len(self._value_tokens) == 1 \
                and not self._leading_whitespace_token \
                and not self._trailing_whitespace_token \
                and isinstance(self._value_tokens[0], Deb822Token):
            # By default, we get a single value spanning the entire line
            # (minus continuation line and newline but we are supposed to
            # exclude those)
            return self._value_tokens[0].text

        return "".join(t.text for t in self._iter_content_tokens())

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        if self._comment_element:
            yield self._comment_element
        if self._continuation_line_token:
            yield self._continuation_line_token
        yield from self._iter_content_parts()
        if self._newline_token:
            yield self._newline_token


class Deb822ValueElement(Deb822Element):
    __slots__ = ('_value_entry_elements',)

    def __init__(self, value_entry_elements):
        # type: (List[Deb822ValueLineElement]) -> None
        super().__init__()
        self._value_entry_elements = value_entry_elements  # type: List[Deb822ValueLineElement]
        self._init_parent_of_parts()

    @property
    def value_lines(self):
        # type: () -> List[Deb822ValueLineElement]
        """Read-only list of value entries"""
        return self._value_entry_elements

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from self._value_entry_elements

    def add_final_newline_if_missing(self):
        # type: () -> None
        if self._value_entry_elements:
            self._value_entry_elements[-1].add_newline_if_missing()


class Deb822ParsedValueElement(Deb822Element):

    __slots__ = ('_text_cached', '_text_no_comments_cached', '_token_list')

    def __init__(self, tokens):
        # type: (List[Deb822Token]) -> None
        super().__init__()
        self._token_list = tokens
        self._init_parent_of_parts()
        if not isinstance(tokens[0], Deb822ValueToken) or \
                not isinstance(tokens[-1], Deb822ValueToken):
            raise ValueError(self.__class__.__name__ + " MUST start and end on a Deb822ValueToken")
        if len(tokens) == 1:
            token = tokens[0]
            self._text_cached = token.text  # type: Optional[str]
            self._text_no_comments_cached = token.text  # type: Optional[str]
        else:
            self._text_cached = None
            self._text_no_comments_cached = None

    def convert_to_text(self):
        # type: () -> str
        if self._text_no_comments_cached is None:
            self._text_no_comments_cached = super().convert_to_text()
        return self._text_no_comments_cached

    def convert_to_text_without_comments(self):
        # type: () -> str
        if self._text_no_comments_cached is None:
            self._text_no_comments_cached = "".join(t.text
                                                    for t in self.iter_tokens()
                                                    if not t.is_comment)
        return self._text_no_comments_cached

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from self._token_list


class Deb822CommentElement(Deb822Element):
    __slots__ = ('_comment_tokens',)

    def __init__(self, comment_tokens):
        # type: (List[Deb822CommentToken]) -> None
        super().__init__()
        self._comment_tokens = comment_tokens  # type: List[Deb822CommentToken]
        if not comment_tokens:  # pragma: no cover
            raise ValueError("Comment elements must have at least one comment token")
        self._init_parent_of_parts()

    def __len__(self):
        # type: () -> int
        return len(self._comment_tokens)

    def __getitem__(self, item):
        # type: (int) -> Deb822CommentToken
        return self._comment_tokens[item]

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from self._comment_tokens


class Deb822KeyValuePairElement(Deb822Element):
    __slots__ = ('_comment_element', '_field_token', '_separator_token', '_value_element')

    def __init__(self,
                 comment_element,  # type: Optional[Deb822CommentElement]
                 field_token,  # type: Deb822FieldNameToken
                 separator_token,  # type: Deb822FieldSeparatorToken
                 value_element  # type: Deb822ValueElement
                 ):
        # type: (...) -> None
        super().__init__()
        self._comment_element = comment_element  # type: Optional[Deb822CommentElement]
        self._field_token = field_token  # type: Deb822FieldNameToken
        self._separator_token = separator_token  # type: Deb822FieldSeparatorToken
        self._value_element = value_element  # type: Deb822ValueElement
        self._init_parent_of_parts()

    @property
    def field_name(self):
        # type: () -> _strI
        return self.field_token.text

    @property
    def field_token(self):
        # type: () -> Deb822FieldNameToken
        return self._field_token

    @property
    def value_element(self):
        # type: () -> Deb822ValueElement
        return self._value_element

    @value_element.setter
    def value_element(self, new_value):
        # type: (Deb822ValueElement) -> None
        self._value_element.clear_parent_if_parent(self)
        self._value_element = new_value
        new_value.parent_element = self

    def interpret_as(self,
                     interpreter,  # type: Interpretation[T]
                     discard_comments_on_read=True  # type: bool
                     ):
        # type: (...) -> T
        return interpreter.interpret(self, discard_comments_on_read=discard_comments_on_read)

    @property
    def comment_element(self):
        # type: () -> Optional[Deb822CommentElement]
        return self._comment_element

    @comment_element.setter
    def comment_element(self, value):
        # type: (Optional[Deb822CommentElement]) -> None
        if value is not None:
            if not value[-1].text.endswith("\n"):
                raise ValueError("Field comments must end with a newline")
        if self._comment_element:
            self._comment_element.clear_parent_if_parent(self)
        if value is not None:
            value.parent_element = self
        self._comment_element = value

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        if self._comment_element:
            yield self._comment_element
        yield self._field_token
        yield self._separator_token
        yield self._value_element


def _format_comment(c):
    # type: (str) -> str
    if c == '':
        # Special-case: Empty strings are mapped to an empty comment line
        return "#\n"
    if '\n' in c[:-1]:
        raise ValueError("Comment lines must not have embedded newlines")
    if not c.endswith('\n'):
        c = c.rstrip() + "\n"
    if not c.startswith("#"):
        c = "# " + c.lstrip()
    return c


def _unpack_key(item,  # type: ParagraphKey
                raise_if_indexed=False  # type: bool
                ):
    # type: (...) -> Tuple[_strI, Optional[int], Optional[Deb822FieldNameToken]]
    index = None  # type: Optional[int]
    name_token = None  # type: Optional[Deb822FieldNameToken]
    if isinstance(item, tuple):
        key, index = item
        if raise_if_indexed:
            # Fudge "(key, 0)" into a "key" callers to defensively support
            # both paragraph styles with the same key.
            if index != 0:
                msg = 'Cannot resolve key "{key}" with index {index}. The key is not indexed'
                raise KeyError(msg.format(key=key, index=index))
            index = None
        key = _strI(key)
    else:
        index = None
        if isinstance(item, Deb822FieldNameToken):
            name_token = item
            key = name_token.text
        else:
            key = _strI(item)

    return key, index, name_token


def _convert_value_lines_to_lines(value_lines,  # type: Iterable[Deb822ValueLineElement]
                                  strip_comments  # type: bool
                                  ):
    # type: (...) -> Iterable[str]
    if not strip_comments:
        yield from (v.convert_to_text() for v in value_lines)
    else:
        for element in value_lines:
            yield ''.join(x.text for x in element.iter_tokens()
                          if not x.is_comment)


if sys.version_info >= (3, 9) or TYPE_CHECKING:
    _ParagraphMapping_Base = collections.abc.Mapping[ParagraphKey, T]
else:
    # Python 3.5 - 3.8 compat - we are not allowed to subscript the abc.Iterator
    # - use this little hack to work around it
    class _ParagraphMapping_Base(collections.abc.Mapping, Generic[T], ABC):
        pass


# Deb822ParagraphElement uses this Mixin (by having `_paragraph` return self).
# Therefore the Mixin needs to call the "proper" methods on the paragraph to
# avoid doing infinite recursion.
class AutoResolvingMixin(Generic[T], _ParagraphMapping_Base[T]):

    @property
    def _auto_resolve_ambiguous_fields(self):
        # type: () -> bool
        return True

    @property
    def _paragraph(self):
        # type: () -> Deb822ParagraphElement
        raise NotImplementedError  # pragma: no cover

    def __len__(self):
        # type: () -> int
        return self._paragraph.kvpair_count

    def __contains__(self, item):
        # type: (object) -> bool
        return self._paragraph.contains_kvpair_element(item)

    def __iter__(self):
        # type: () -> Iterator[ParagraphKey]
        return iter(self._paragraph.iter_keys())

    def __getitem__(self, item):
        # type: (ParagraphKey) -> T
        if self._auto_resolve_ambiguous_fields and isinstance(item, str):
            v = self._paragraph.get_kvpair_element((item, 0))
        else:
            v = self._paragraph.get_kvpair_element(item)
        assert v is not None
        return self._interpret_value(item, v)

    def __delitem__(self, item):
        # type: (ParagraphKey) -> None
        self._paragraph.remove_kvpair_element(item)

    def _interpret_value(self, key, value):
        # type: (ParagraphKey, Deb822KeyValuePairElement) -> T
        raise NotImplementedError  # pragma: no cover


# Deb822ParagraphElement uses this Mixin (by having `_paragraph` return self).
# Therefore the Mixin needs to call the "proper" methods on the paragraph to
# avoid doing infinite recursion.
class Deb822ParagraphToStrWrapperMixin(AutoResolvingMixin[str],
                                       ABC):

    @property
    def _auto_map_initial_line_whitespace(self):
        # type: () -> bool
        return True

    @property
    def _discard_comments_on_read(self):
        # type: () -> bool
        return True

    @property
    def _auto_map_final_newline_in_multiline_values(self):
        # type: () -> bool
        return True

    @property
    def _preserve_field_comments_on_field_updates(self):
        # type: () -> bool
        return True

    def _convert_value_to_str(self, kvpair_element):
        # type: (Deb822KeyValuePairElement) -> str
        value_element = kvpair_element.value_element
        value_entries = value_element.value_lines
        if len(value_entries) == 1:
            # Special case single line entry (e.g. "Package: foo") as they never
            # have comments and we can do some parts more efficient.
            value_entry = value_entries[0]
            t = value_entry.convert_to_text()
            if self._auto_map_initial_line_whitespace:
                t = t.strip()
            return t

        if self._auto_map_initial_line_whitespace or self._discard_comments_on_read:
            converter = _convert_value_lines_to_lines(value_entries,
                                                      self._discard_comments_on_read,
                                                      )

            auto_map_space = self._auto_map_initial_line_whitespace

            # Because we know there are more than one line, we can unconditionally inject
            # the newline after the first line
            as_text = ''.join(line.strip() + "\n" if auto_map_space and i == 1 else line
                              for i, line in enumerate(converter, start=1)
                              )
        else:
            # No rewrite necessary.
            as_text = value_element.convert_to_text()

        if self._auto_map_final_newline_in_multiline_values and as_text[-1] == "\n":
            as_text = as_text[:-1]
        return as_text

    def __setitem__(self, item, value):
        # type: (ParagraphKey, str) -> None
        keep_comments = self._preserve_field_comments_on_field_updates  # type: Optional[bool]
        comment = None
        if keep_comments and self._auto_resolve_ambiguous_fields:
            # For ambiguous fields, we have to resolve the original field as
            # the set_field_* methods do not cope with ambiguous fields.  This
            # means we might as well clear the keep_comments flag as we have
            # resolved the comment.
            keep_comments = None
            key_lookup = item
            if isinstance(item, str):
                key_lookup = (item, 0)
            orig_kvpair = self._paragraph.get_kvpair_element(key_lookup, use_get=True)
            if orig_kvpair is not None:
                comment = orig_kvpair.comment_element

        if self._auto_map_initial_line_whitespace:
            try:
                idx = value.index("\n")
            except ValueError:
                idx = -1
            if idx == -1 or idx == len(value):
                self._paragraph.set_field_to_simple_value(
                    item,
                    value.strip(),
                    preserve_original_field_comment=keep_comments,
                    field_comment=comment,
                )
                return
            # Regenerate the first line with normalized whitespace if necessary
            first_line, rest = value.split("\n", 1)
            if first_line and first_line[:1] not in ('\t', ' '):
                value = "".join((" ", first_line.strip(), "\n", rest))
            else:
                value = "".join((first_line, "\n", rest))
        if not value.endswith("\n"):
            if not self._auto_map_final_newline_in_multiline_values:
                raise ValueError("Values must end with a newline (or be single line"
                                 " values and use the auto whitespace mapping feature)")
            value += "\n"
        self._paragraph.set_field_from_raw_string(
            item,
            value,
            preserve_original_field_comment=keep_comments,
            field_comment=comment,
        )

    def _interpret_value(self, key, value):
        # type: (ParagraphKey, Deb822KeyValuePairElement) -> str
        # mypy is a bit dense and cannot see that T == str
        return self._convert_value_to_str(value)


class AbstractDeb822ParagraphWrapper(AutoResolvingMixin[T], ABC):

    def __init__(self,
                 paragraph,  # type: Deb822ParagraphElement
                 *,
                 auto_resolve_ambiguous_fields=False,  # type: bool
                 discard_comments_on_read=True  # type: bool
                 ):
        # type: (...) -> None
        self.__paragraph = paragraph
        self.__auto_resolve_ambiguous_fields = auto_resolve_ambiguous_fields
        self.__discard_comments_on_read = discard_comments_on_read

    @property
    def _paragraph(self):
        # type: () -> Deb822ParagraphElement
        return self.__paragraph

    @property
    def _discard_comments_on_read(self):
        # type: () -> bool
        return self.__discard_comments_on_read

    @property
    def _auto_resolve_ambiguous_fields(self):
        # type: () -> bool
        return self.__auto_resolve_ambiguous_fields


class Deb822InterpretingParagraphWrapper(AbstractDeb822ParagraphWrapper[T]):

    def __init__(self,
                 paragraph,  # type: Deb822ParagraphElement
                 interpretation,  # type: Interpretation[T]
                 *,
                 auto_resolve_ambiguous_fields=False,  # type: bool
                 discard_comments_on_read=True  # type: bool
                 ):
        # type: (...) -> None
        super().__init__(paragraph,
                         auto_resolve_ambiguous_fields=auto_resolve_ambiguous_fields,
                         discard_comments_on_read=discard_comments_on_read,
                         )
        self._interpretation = interpretation

    def _interpret_value(self, key, value):
        # type: (ParagraphKey, Deb822KeyValuePairElement) -> T
        return self._interpretation.interpret(value)


class Deb822DictishParagraphWrapper(AbstractDeb822ParagraphWrapper[str],
                                    Deb822ParagraphToStrWrapperMixin):

    def __init__(self,
                 paragraph,  # type: Deb822ParagraphElement
                 *,
                 discard_comments_on_read=True,  # type: bool
                 auto_map_initial_line_whitespace=True,  # type: bool
                 auto_resolve_ambiguous_fields=False,  # type: bool
                 preserve_field_comments_on_field_updates=True,  # type: bool
                 auto_map_final_newline_in_multiline_values=True  # type: bool
                 ):
        # type: (...) -> None
        super().__init__(paragraph,
                         auto_resolve_ambiguous_fields=auto_resolve_ambiguous_fields,
                         discard_comments_on_read=discard_comments_on_read,
                         )
        self.__auto_map_initial_line_whitespace = auto_map_initial_line_whitespace
        self.__preserve_field_comments_on_field_updates = preserve_field_comments_on_field_updates
        self.__auto_map_final_newline_in_multiline_values = \
            auto_map_final_newline_in_multiline_values

    @property
    def _auto_map_initial_line_whitespace(self):
        # type: () -> bool
        return self.__auto_map_initial_line_whitespace

    @property
    def _preserve_field_comments_on_field_updates(self):
        # type: () -> bool
        return self.__preserve_field_comments_on_field_updates

    @property
    def _auto_map_final_newline_in_multiline_values(self):
        # type: () -> bool
        return self.__auto_map_final_newline_in_multiline_values


class Deb822ParagraphElement(Deb822Element, Deb822ParagraphToStrWrapperMixin, ABC):

    @classmethod
    def new_empty_paragraph(cls):
        # type: () -> Deb822ParagraphElement
        return Deb822NoDuplicateFieldsParagraphElement([], OrderedSet())

    @classmethod
    def from_dict(cls, mapping):
        # type: (Mapping[str, str]) -> Deb822ParagraphElement
        paragraph = cls.new_empty_paragraph()
        for k, v in mapping.items():
            paragraph[k] = v
        return paragraph

    @classmethod
    def from_kvpairs(cls, kvpair_elements):
        # type: (List[Deb822KeyValuePairElement]) -> Deb822ParagraphElement
        if not kvpair_elements:
            raise ValueError("A paragraph must consist of at least one field/value pair")
        kvpair_order = OrderedSet(kv.field_name for kv in kvpair_elements)
        if len(kvpair_order) == len(kvpair_elements):
            # Each field occurs at most once, which is good because that
            # means it is a valid paragraph and we can use the optimized
            # implementation.
            return Deb822NoDuplicateFieldsParagraphElement(kvpair_elements, kvpair_order)
        # Fallback implementation, that can cope with the repeated field names
        # at the cost of complexity.
        return Deb822DuplicateFieldsParagraphElement(kvpair_elements)

    @property
    def has_duplicate_fields(self):
        # type: () -> bool
        """Tell whether this paragraph has duplicate fields"""
        return False

    def as_interpreted_dict_view(self,
                                 interpretation,  # type: Interpretation[T]
                                 *,
                                 auto_resolve_ambiguous_fields=True  # type: bool
                                 ):
        # type: (...) -> Deb822InterpretingParagraphWrapper[T]
        r"""Provide a Dict-like view of the paragraph

        This method returns a dict-like object representing this paragraph and
        is useful for accessing fields in a given interpretation. It is possible
        to use multiple versions of this dict-like view with different interpretations
        on the same paragraph at the same time (for different fields).

            >>> example_deb822_paragraph = '''
            ... Package: foo
            ... # Field comment (because it becomes just before a field)
            ... Architecture: amd64
            ... # Inline comment (associated with the next line)
            ...               i386
            ... # We also support arm
            ...               arm64
            ...               armel
            ... '''
            >>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
            >>> paragraph = next(iter(dfile))
            >>> list_view = paragraph.as_interpreted_dict_view(LIST_SPACE_SEPARATED_INTERPRETATION)
            >>> # With the defaults, you only deal with the semantic values
            >>> # - no leading or trailing whitespace on the first part of the value
            >>> list(list_view["Package"])
            ['foo']
            >>> with list_view["Architecture"] as arch_list:
            ...     orig_arch_list = list(arch_list)
            ...     arch_list.replace('i386', 'kfreebsd-amd64')
            >>> orig_arch_list
            ['amd64', 'i386', 'arm64', 'armel']
            >>> list(list_view["Architecture"])
            ['amd64', 'kfreebsd-amd64', 'arm64', 'armel']
            >>> print(paragraph.dump(), end='')
            Package: foo
            # Field comment (because it becomes just before a field)
            Architecture: amd64
            # Inline comment (associated with the next line)
                          kfreebsd-amd64
            # We also support arm
                          arm64
                          armel
            >>> # Format preserved and architecture replaced
            >>> with list_view["Architecture"] as arch_list:
            ...     # Prettify the result as sorting will cause awkward whitespace
            ...     arch_list.reformat_when_finished()
            ...     arch_list.sort()
            >>> print(paragraph.dump(), end='')
            Package: foo
            # Field comment (because it becomes just before a field)
            Architecture: amd64
            # We also support arm
                          arm64
                          armel
            # Inline comment (associated with the next line)
                          kfreebsd-amd64
            >>> list(list_view["Architecture"])
            ['amd64', 'arm64', 'armel', 'kfreebsd-amd64']
            >>> # Format preserved and architecture values sorted

        :param interpretation: Decides how the field values are interpreted.  As an example,
          use LIST_SPACE_SEPARATED_INTERPRETATION for fields such as Architecture in the
          debian/control file.
        :param auto_resolve_ambiguous_fields: This parameter is only relevant for paragraphs
          that contain the same field multiple times (these are generally invalid).  If the
          caller requests an ambiguous field from an invalid paragraph via a plain field name,
          the return dict-like object will refuse to resolve the field (not knowing which
          version to pick).  This parameter (if set to True) instead changes the error into
          assuming the caller wants the *first* variant.
        """
        return Deb822InterpretingParagraphWrapper(
            self,
            interpretation,
            auto_resolve_ambiguous_fields=auto_resolve_ambiguous_fields,
        )

    def configured_view(self,
                        *,
                        discard_comments_on_read=True,  # type: bool
                        auto_map_initial_line_whitespace=True,  # type: bool
                        auto_resolve_ambiguous_fields=True,  # type: bool
                        preserve_field_comments_on_field_updates=True,  # type: bool
                        auto_map_final_newline_in_multiline_values=True  # type: bool
                        ):
        # type: (...) -> Deb822DictishParagraphWrapper
        r"""Provide a Dict[str, str]-like view of this paragraph with non-standard parameters

        This method returns a dict-like object representing this paragraph that is
        optionally configured differently from the default view.

            >>> example_deb822_paragraph = '''
            ... Package: foo
            ... # Field comment (because it becomes just before a field)
            ... Depends: libfoo,
            ... # Inline comment (associated with the next line)
            ...          libbar,
            ... '''
            >>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
            >>> paragraph = next(iter(dfile))
            >>> # With the defaults, you only deal with the semantic values
            >>> # - no leading or trailing whitespace on the first part of the value
            >>> paragraph["Package"]
            'foo'
            >>> # - no inline comments in multiline values (but whitespace will be present
            >>> #   subsequent lines.)
            >>> print(paragraph["Depends"])
            libfoo,
                     libbar,
            >>> paragraph['Foo'] = 'bar'
            >>> paragraph.get('Foo')
            'bar'
            >>> paragraph.get('Unknown-Field') is None
            True
            >>> # But you get asymmetric behaviour with set vs. get
            >>> paragraph['Foo'] = ' bar\n'
            >>> paragraph['Foo']
            'bar'
            >>> paragraph['Bar'] = '     bar\n#Comment\n another value\n'
            >>> # Note that the whitespace on the first line has been normalized.
            >>> print("Bar: " + paragraph['Bar'])
            Bar: bar
             another value
            >>> # The comment is present (in case you where wondering)
            >>> print(paragraph.get_kvpair_element('Bar').convert_to_text(), end='')
            Bar:     bar
            #Comment
             another value
            >>> # On the other hand, you can choose to see the values as they are
            >>> # - We will just reset the paragraph as a "nothing up my sleeve"
            >>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
            >>> paragraph = next(iter(dfile))
            >>> nonstd_dictview = paragraph.configured_view(
            ...     discard_comments_on_read=False,
            ...     auto_map_initial_line_whitespace=False,
            ...     # For paragraphs with duplicate fields, you can choose to get an error
            ...     # rather than the dict picking the first value available.
            ...     auto_resolve_ambiguous_fields=False,
            ...     auto_map_final_newline_in_multiline_values=False,
            ... )
            >>> # Because we have reset the state, Foo and Bar are no longer there.
            >>> 'Bar' not in paragraph and 'Foo' not in paragraph
            True
            >>> # We can now see the comments (discard_comments_on_read=False)
            >>> # (The leading whitespace in front of "libfoo" is due to
            >>> #  auto_map_initial_line_whitespace=False)
            >>> print(nonstd_dictview["Depends"], end='')
             libfoo,
            # Inline comment (associated with the next line)
                     libbar,
            >>> # And all the optional whitespace on the first value line
            >>> # (auto_map_initial_line_whitespace=False)
            >>> nonstd_dictview["Package"] == ' foo\n'
            True
            >>> # ... which will give you symmetric behaviour with set vs. get
            >>> nonstd_dictview['Foo'] = '  bar \n'
            >>> nonstd_dictview['Foo']
            '  bar \n'
            >>> nonstd_dictview['Bar'] = '  bar \n#Comment\n another value\n'
            >>> nonstd_dictview['Bar']
            '  bar \n#Comment\n another value\n'
            >>> # But then you get no help either.
            >>> try:
            ...     nonstd_dictview["Baz"] = "foo"
            ... except ValueError:
            ...     print("Rejected")
            Rejected
            >>> # With auto_map_initial_line_whitespace=False, you have to include minimum a newline
            >>> nonstd_dictview["Baz"] = "foo\n"
            >>> # The absence of leading whitespace gives you the terse variant at the expensive
            >>> # readability
            >>> paragraph.get_kvpair_element('Baz').convert_to_text()
            'Baz:foo\n'
            >>> # But because they are views, changes performed via one view is visible in the other
            >>> paragraph['Foo']
            'bar'
            >>> # The views show the values according to their own rules. Therefore, there is an
            >>> # asymmetric between paragraph['Foo'] and nonstd_dictview['Foo']
            >>> # Nevertheless, you can read or write the fields via either - enabling you to use
            >>> # the view that best suit your use-case for the given field.
            >>> 'Baz' in paragraph and nonstd_dictview.get('Baz') is not None
            True
            >>> # Deletion via the view also works
            >>> del nonstd_dictview['Baz']
            >>> 'Baz' not in paragraph and nonstd_dictview.get('Baz') is None
            True


        :param discard_comments_on_read: When getting a field value from the dict,
          this parameter decides how in-line comments are handled.  When setting
          the value, inline comments are still allowed and will be retained.
          However, keep in mind that this option makes getter and setter assymetric
          as a "get" following a "set" with inline comments will omit the comments
          even if they are there (see the code example).
        :param auto_map_initial_line_whitespace: Special-case the first value line
          by trimming unnecessary whitespace leaving only the value. For single-line
          values, all space including newline is pruned. For multi-line values, the
          newline is preserved / needed to distinguish the first line from the
          following lines.  When setting a value, this option normalizes the
          whitespace of the initial line of the value field.
          When this option is set to True makes the dictionary behave more like the
          original Deb822 module.
        :param preserve_field_comments_on_field_updates: Whether to preserve the field
          comments when mutating the field.
        :param auto_resolve_ambiguous_fields: This parameter is only relevant for paragraphs
          that contain the same field multiple times (these are generally invalid).  If the
          caller requests an ambiguous field from an invalid paragraph via a plain field name,
          the return dict-like object will refuse to resolve the field (not knowing which
          version to pick).  This parameter (if set to True) instead changes the error into
          assuming the caller wants the *first* variant.
        :param auto_map_final_newline_in_multiline_values: This parameter controls whether
          a multiline field with have / need a trailing newline. If True, the trailing
          newline is hidden on get and automatically added in set (if missing).
          When this option is set to True makes the dictionary behave more like the
          original Deb822 module.
        """
        return Deb822DictishParagraphWrapper(
            self,
            discard_comments_on_read=discard_comments_on_read,
            auto_map_initial_line_whitespace=auto_map_initial_line_whitespace,
            auto_resolve_ambiguous_fields=auto_resolve_ambiguous_fields,
            preserve_field_comments_on_field_updates=preserve_field_comments_on_field_updates,
            auto_map_final_newline_in_multiline_values=auto_map_final_newline_in_multiline_values,
        )

    @property
    def _paragraph(self):
        # type: () -> Deb822ParagraphElement
        return self

    def order_last(self, field):
        # type: (ParagraphKey) -> None
        """Re-order the given field so it is "last" in the paragraph"""
        raise NotImplementedError  # pragma: no cover

    def order_first(self, field):
        # type: (ParagraphKey) -> None
        """Re-order the given field so it is "first" in the paragraph"""
        raise NotImplementedError  # pragma: no cover

    def order_before(self, field, reference_field):
        # type: (ParagraphKey, ParagraphKey) -> None
        """Re-order the given field so appears directly after the reference field in the paragraph

        The reference field must be present."""
        raise NotImplementedError  # pragma: no cover

    def order_after(self, field, reference_field):
        # type: (ParagraphKey, ParagraphKey) -> None
        """Re-order the given field so appears directly before the reference field in the paragraph

        The reference field must be present.
        """
        raise NotImplementedError  # pragma: no cover

    @property
    def kvpair_count(self):
        # type: () -> int
        raise NotImplementedError  # pragma: no cover

    def iter_keys(self):
        # type: () -> Iterable[ParagraphKey]
        raise NotImplementedError  # pragma: no cover

    def contains_kvpair_element(self, item):
        # type: (object) -> bool
        raise NotImplementedError  # pragma: no cover

    def get_kvpair_element(self,
                           item,  # type: ParagraphKey
                           use_get=False  # type: bool
                           ):
        # type: (...) -> Optional[Deb822KeyValuePairElement]
        raise NotImplementedError  # pragma: no cover

    def set_kvpair_element(self, key, value):
        # type: (ParagraphKey, Deb822KeyValuePairElement) -> None
        raise NotImplementedError  # pragma: no cover

    def remove_kvpair_element(self, key):
        # type: (ParagraphKey) -> None
        raise NotImplementedError  # pragma: no cover

    def sort_fields(self,
                    key=None  # type: Optional[Callable[[str], Any]]
                    ):
        # type: (...) -> None
        """Re-order all fields

        :param key: Provide a key function (same semantics as for sorted).  Keep in mind that
          the module preserve the cases for field names - in generally, callers are recommended
          to use "lower()" to normalize the case.
        """
        raise NotImplementedError  # pragma: no cover

    def set_field_to_simple_value(self,
                                  item,  # type: ParagraphKey
                                  simple_value,  # type: str
                                  *,
                                  preserve_original_field_comment=None,  # type: Optional[bool]
                                  field_comment=None  # type: Optional[Commentish]
                                  ):
        # type: (...) -> None
        r"""Sets a field in this paragraph to a simple "word" or "phrase"

        In many cases, it is better for callers to just use the paragraph as
        if it was a dictionary.  However, this method does enable to you choose
        the field comment (if any), which can be a reason for using it.

        This is suitable for "simple" fields like "Package".  Example:

            >>> example_deb822_paragraph = '''
            ... Package: foo
            ... '''
            >>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
            >>> p = next(iter(dfile))
            >>> p.set_field_to_simple_value("Package", "mscgen")
            >>> p.set_field_to_simple_value("Architecture", "linux-any kfreebsd-any",
            ...                             field_comment=['Only ported to linux and kfreebsd'])
            >>> p.set_field_to_simple_value("Priority", "optional")
            >>> print(p.dump(), end='')
            Package: mscgen
            # Only ported to linux and kfreebsd
            Architecture: linux-any kfreebsd-any
            Priority: optional
            >>> # Values are formatted nicely by default, but it does not work with
            >>> # multi-line values
            >>> p.set_field_to_simple_value("Foo", "bar\nbin\n")
            Traceback (most recent call last):
                ...
            ValueError: Cannot use set_field_to_simple_value for values with newlines

        :param item: Name of the field to set.  If the paragraph already
          contains the field, then it will be replaced.  If the field exists,
          then it will preserve its order in the paragraph.  Otherwise, it is
          added to the end of the paragraph.
          Note this can be a "paragraph key", which enables you to control
          *which* instance of a field is being replaced (in case of duplicate
          fields).
        :param simple_value: The text to use as the value.  The value must not
          contain newlines.  Leading and trailing will be stripped but space
          within the value is preserved.  The value cannot contain comments
          (i.e. if the "#" token appears in the value, then it is considered
          a value rather than "start of a comment)
        :param preserve_original_field_comment: See the description for the
          parameter with the same name in the set_field_from_raw_string method.
        :param field_comment: See the description for the parameter with the same
          name in the set_field_from_raw_string method.
        """
        if '\n' in simple_value:
            raise ValueError("Cannot use set_field_to_simple_value for values with newlines")

        # Reformat it with a leading space and trailing newline. The latter because it is
        # necessary if there are any fields after it and the former because it looks nicer so
        # have single space after the field separator
        stripped = simple_value.strip()
        if stripped:
            raw_value = ' ' + stripped + "\n"
        else:
            # Special-case for empty values
            raw_value = "\n"
        self.set_field_from_raw_string(
            item,
            raw_value,
            preserve_original_field_comment=preserve_original_field_comment,
            field_comment=field_comment,
        )

    def set_field_from_raw_string(self,
                                  item,  # type: ParagraphKey
                                  raw_string_value,  # type: str
                                  *,
                                  preserve_original_field_comment=None,  # type: Optional[bool]
                                  field_comment=None  # type: Optional[Commentish]
                                  ):
        # type: (...) -> None
        """Sets a field in this paragraph to a given text value

        In many cases, it is better for callers to just use the paragraph as
        if it was a dictionary.  However, this method does enable to you choose
        the field comment (if any) and lets to have a higher degree of control
        over whitespace (on the first line), which can be a reason for using it.

        Example usage:

            >>> example_deb822_paragraph = '''
            ... Package: foo
            ... '''
            >>> dfile = parse_deb822_file(example_deb822_paragraph.splitlines())
            >>> p = next(iter(dfile))
            >>> raw_value = '''
            ... Build-Depends: debhelper-compat (= 12),
            ...                some-other-bd,
            ... # Comment
            ...                another-bd,
            ... '''.lstrip()  # Remove leading newline, but *not* the trailing newline
            >>> fname, new_value = raw_value.split(':', 1)
            >>> p.set_field_from_raw_string(fname, new_value)
            >>> print(p.dump(), end='')
            Package: foo
            Build-Depends: debhelper-compat (= 12),
                           some-other-bd,
            # Comment
                           another-bd,
            >>> # Format preserved

        :param item: Name of the field to set.  If the paragraph already
          contains the field, then it will be replaced.  Otherwise, it is
          added to the end of the paragraph.
          Note this can be a "paragraph key", which enables you to control
          *which* instance of a field is being replaced (in case of duplicate
          fields).
        :param raw_string_value: The text to use as the value.  The text must
          be valid deb822 syntax and is used *exactly* as it is given.
          Accordingly, multi-line values must include mandatory leading space
          on continuation lines, newlines after the value, etc. On the
          flip-side, any optional space or comments will be included.

          Note that the first line will *never* be read as a comment (if the
          first line of the value starts with a "#" then it will result
          in "Field-Name:#..." which is parsed as a value starting with "#"
          rather than a comment).
        :param preserve_original_field_comment: If True, then if there is an
          existing field and that has a comment, then the comment will remain
          after this operation.  This is the default is the `field_comment`
          parameter is omitted.
          Note that if the parameter is True and the item is ambiguous, this
          will raise an AmbiguousDeb822FieldKeyError.  When the parameter is
          omitted, the ambiguity is resolved automatically and if the resolved
          field has a comment then that will be preserved (assuming
          field_comment is None).
        :param field_comment: If not None, add or replace the comment for
          the field.  Each string in the list will become one comment
          line (inserted directly before the field name). Will appear in the
          same order as they do in the list.

          If you want complete control over the formatting of the comments,
          then ensure that each line start with "#" and end with "\\n" before
          the call.  Otherwise, leading/trailing whitespace is normalized
          and the missing "#"/"\\n" character is inserted.
        """

        new_content = []  # type: List[str]
        if preserve_original_field_comment is not None:
            if field_comment is not None:
                raise ValueError('The "preserve_original_field_comment" conflicts with'
                                 ' "field_comment" parameter')
        elif field_comment is not None:
            if not isinstance(field_comment, Deb822CommentElement):
                new_content.extend(_format_comment(x) for x in field_comment)
                field_comment = None
            preserve_original_field_comment = False

        field_name, _, _ = _unpack_key(item)

        cased_field_name = field_name
        try:
            original = self.get_kvpair_element(item, use_get=True)
        except AmbiguousDeb822FieldKeyError:
            if preserve_original_field_comment:
                # If we were asked to preserve the original comment, then we
                # require a strict lookup
                raise
            original = self.get_kvpair_element((field_name, 0), use_get=True)

        if preserve_original_field_comment is None:
            # We simplify preserve_original_field_comment after the lookup of the field.
            # Otherwise, we can get ambiguous key errors when updating an ambiguous field
            # when the caller did not explicitly ask for that behaviour.
            preserve_original_field_comment = True

        if original:
            # If we already have the field, then preserve the original case
            cased_field_name = original.field_name
        raw = ":".join((cased_field_name, raw_string_value))
        raw_lines = raw.splitlines(keepends=True)
        for i, line in enumerate(raw_lines, start=1):
            if not line.endswith("\n"):
                raise ValueError("Line {i} in new value was missing trailing newline".format(i=i))
            if i != 1 and line[0] not in (' ', '\t', '#'):
                msg = 'Line {i} in new value was invalid.  It must either start' \
                      ' with " " space (continuation line) or "#" (comment line).' \
                      ' The line started with "{line}"'
                raise ValueError(msg.format(i=i, line=line[0]))
        if len(raw_lines) > 1 and raw_lines[-1].startswith('#'):
            raise ValueError('The last line in a value field cannot be a comment')
        new_content.extend(raw_lines)
        # As absurd as it might seem, it is easier to just use the parser to
        # construct the AST correctly
        deb822_file = parse_deb822_file(iter(new_content))
        error_token = deb822_file.find_first_error_element()
        if error_token:
            raise ValueError("Syntax error in new field value for " + field_name)
        paragraph = next(iter(deb822_file))
        assert isinstance(paragraph, Deb822NoDuplicateFieldsParagraphElement)
        value = paragraph.get_kvpair_element(field_name)
        assert value is not None
        if preserve_original_field_comment:
            if original:
                value.comment_element = original.comment_element
                original.comment_element = None
        elif field_comment is not None:
            value.comment_element = field_comment
        self.set_kvpair_element(item, value)

    @overload
    def dump(self,
             fd  # type: IO[bytes]
             ):
        # type: (...) -> None
        pass

    @overload
    def dump(self):
        # type: () -> str
        pass

    def dump(self,
             fd=None  # type: Optional[IO[bytes]]
             ):
        # type: (...) -> Optional[str]
        if fd is None:
            return "".join(t.text for t in self.iter_tokens())
        for token in self.iter_tokens():
            fd.write(token.text.encode('utf-8'))
        return None


class Deb822NoDuplicateFieldsParagraphElement(Deb822ParagraphElement):
    """Paragraph implementation optimized for valid deb822 files

    When there are no duplicated fields, we can use simpler and faster
    datastructures for common operations.
    """

    def __init__(self,
                 kvpair_elements,  # type: List[Deb822KeyValuePairElement]
                 kvpair_order  # type: OrderedSet
                 ):
        # type: (...) -> None
        super().__init__()
        self._kvpair_elements = {kv.field_name: kv for kv in kvpair_elements}
        self._kvpair_order = kvpair_order
        self._init_parent_of_parts()

    @property
    def kvpair_count(self):
        # type: () -> int
        return len(self._kvpair_elements)

    def order_last(self, field):
        # type: (ParagraphKey) -> None
        """Re-order the given field so it is "last" in the paragraph"""
        unpacked_field, _, _ = _unpack_key(field, raise_if_indexed=True)
        self._kvpair_order.order_last(unpacked_field)

    def order_first(self, field):
        # type: (ParagraphKey) -> None
        """Re-order the given field so it is "first" in the paragraph"""
        unpacked_field, _, _ = _unpack_key(field, raise_if_indexed=True)
        self._kvpair_order.order_first(unpacked_field)

    def order_before(self, field, reference_field):
        # type: (ParagraphKey, ParagraphKey) -> None
        """Re-order the given field so appears directly after the reference field in the paragraph

        The reference field must be present."""
        unpacked_field, _, _ = _unpack_key(field, raise_if_indexed=True)
        unpacked_ref_field, _, _ = _unpack_key(reference_field, raise_if_indexed=True)
        self._kvpair_order.order_before(unpacked_field, unpacked_ref_field)

    def order_after(self, field, reference_field):
        # type: (ParagraphKey, ParagraphKey) -> None
        """Re-order the given field so appears directly before the reference field in the paragraph

        The reference field must be present.
        """
        unpacked_field, _, _ = _unpack_key(field, raise_if_indexed=True)
        unpacked_ref_field, _, _ = _unpack_key(reference_field, raise_if_indexed=True)
        self._kvpair_order.order_after(unpacked_field, unpacked_ref_field)

    # Overload to narrow the type to just str.
    def __iter__(self):
        # type: () -> Iterator[str]
        return iter(str(k) for k in self._kvpair_order)

    def iter_keys(self):
        # type: () -> Iterable[str]
        yield from (str(k) for k in self._kvpair_order)

    def remove_kvpair_element(self, key):
        # type: (ParagraphKey) -> None
        key, _, _ = _unpack_key(key, raise_if_indexed=True)
        del self._kvpair_elements[key]
        self._kvpair_order.remove(key)

    def contains_kvpair_element(self, item):
        # type: (object) -> bool
        if not isinstance(item, (str, tuple, Deb822FieldNameToken)):
            return False
        item = cast('ParagraphKey', item)
        key, _, _ = _unpack_key(item, raise_if_indexed=True)
        return key in self._kvpair_elements

    def get_kvpair_element(self,
                           item,  # type: ParagraphKey
                           use_get=False  # type: bool
                           ):
        # type: (...) -> Optional[Deb822KeyValuePairElement]
        item, _, _ = _unpack_key(item, raise_if_indexed=True)
        if use_get:
            return self._kvpair_elements.get(item)
        return self._kvpair_elements[item]

    def set_kvpair_element(self, key, value):
        # type: (ParagraphKey, Deb822KeyValuePairElement) -> None
        key, _, _ = _unpack_key(key, raise_if_indexed=True)
        if isinstance(key, Deb822FieldNameToken):
            if key is not value.field_token:
                raise ValueError("Key is a Deb822FieldNameToken, but not *the* Deb822FieldNameToken"
                                 " for the value")
            key = value.field_name
        else:
            if key != value.field_name:
                raise ValueError("Cannot insert value under a different field value than field name"
                                 " from its Deb822FieldNameToken implies")
            # Use the string from the Deb822FieldNameToken as we need to keep that in memory either
            # way
            key = value.field_name
        original_value = self._kvpair_elements.get(key)
        self._kvpair_elements[key] = value
        self._kvpair_order.append(key)
        if original_value is not None:
            original_value.parent_element = None
        value.parent_element = self

    def sort_fields(self, key=None):
        # type: (Optional[Callable[[str], Any]]) -> None
        """Re-order all fields

        :param key: Provide a key function (same semantics as for sorted).  Keep in mind that
          the module preserve the cases for field names - in generally, callers are recommended
          to use "lower()" to normalize the case.
        """
        for last_field_name in reversed(self._kvpair_order):
            last_kvpair = self._kvpair_elements[cast('_strI', last_field_name)]
            last_kvpair.value_element.add_final_newline_if_missing()
            break

        if key is None:
            key = default_field_sort_key

        self._kvpair_order = OrderedSet(sorted(self._kvpair_order, key=key))

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from (self._kvpair_elements[x]
                    for x in cast('Iterable[_strI]', self._kvpair_order))


class Deb822DuplicateFieldsParagraphElement(Deb822ParagraphElement):

    def __init__(self, kvpair_elements):
        # type: (List[Deb822KeyValuePairElement]) -> None
        super().__init__()
        self._kvpair_order = LinkedList()  # type: LinkedList[Deb822KeyValuePairElement]
        self._kvpair_elements = \
            {}  # type: Dict[_strI, List[KVPNode]]
        self._init_kvpair_fields(kvpair_elements)
        self._init_parent_of_parts()

    @property
    def has_duplicate_fields(self):
        # type: () -> bool
        # Most likely, the answer is "True" but if the caller "fixes" the problem
        # then this can return "False"
        return len(self._kvpair_order) > len(self._kvpair_elements)

    def _init_kvpair_fields(self, kvpairs):
        # type: (Iterable[Deb822KeyValuePairElement]) -> None
        assert not self._kvpair_order
        assert not self._kvpair_elements
        for kv in kvpairs:
            field_name = kv.field_name
            node = self._kvpair_order.append(kv)
            if field_name not in self._kvpair_elements:
                self._kvpair_elements[field_name] = [node]
            else:
                self._kvpair_elements[field_name].append(node)

    def _nodes_being_relocated(self, field):
        # type: (ParagraphKey) -> Tuple[List[KVPNode], List[KVPNode]]
        key, index, name_token = _unpack_key(field)
        nodes = self._kvpair_elements[key]
        nodes_being_relocated = []

        if name_token is not None or index is not None:
            single_node = self._resolve_to_single_node(nodes, key, index, name_token)
            assert single_node is not None
            nodes_being_relocated.append(single_node)
        else:
            nodes_being_relocated = nodes
        return nodes, nodes_being_relocated

    def order_last(self, field):
        # type: (ParagraphKey) -> None
        """Re-order the given field so it is "last" in the paragraph"""
        nodes, nodes_being_relocated = self._nodes_being_relocated(field)
        assert len(nodes_being_relocated) == 1 or len(nodes) == len(nodes_being_relocated)

        kvpair_order = self._kvpair_order
        for node in nodes_being_relocated:
            if kvpair_order.tail_node is node:
                # Special case for relocating a single node that happens to be the last.
                continue
            kvpair_order.remove_node(node)
            # assertion for mypy
            assert kvpair_order.tail_node is not None
            kvpair_order.insert_node_after(node, kvpair_order.tail_node)

        if len(nodes_being_relocated) == 1 and nodes_being_relocated[0] is not nodes[-1]:
            single_node = nodes_being_relocated[0]
            nodes.remove(single_node)
            nodes.append(single_node)

    def order_first(self, field):
        # type: (ParagraphKey) -> None
        """Re-order the given field so it is "first" in the paragraph"""
        nodes, nodes_being_relocated = self._nodes_being_relocated(field)
        assert len(nodes_being_relocated) == 1 or len(nodes) == len(nodes_being_relocated)

        kvpair_order = self._kvpair_order
        for node in nodes_being_relocated:
            if kvpair_order.head_node is node:
                # Special case for relocating a single node that happens to be the first.
                continue
            kvpair_order.remove_node(node)
            # assertion for mypy
            assert kvpair_order.head_node is not None
            kvpair_order.insert_node_before(node, kvpair_order.head_node)

        if len(nodes_being_relocated) == 1 and nodes_being_relocated[0] is not nodes[0]:
            single_node = nodes_being_relocated[0]
            nodes.remove(single_node)
            nodes.insert(0, single_node)

    def order_before(self, field, reference_field):
        # type: (ParagraphKey, ParagraphKey) -> None
        """Re-order the given field so appears directly after the reference field in the paragraph

        The reference field must be present."""
        nodes, nodes_being_relocated = self._nodes_being_relocated(field)
        assert len(nodes_being_relocated) == 1 or len(nodes) == len(nodes_being_relocated)
        # For "before" we always use the "first" variant as reference in case of doubt
        _, reference_nodes = self._nodes_being_relocated(reference_field)
        reference_node = reference_nodes[0]
        if reference_node in nodes_being_relocated:
            raise ValueError("Cannot re-order a field relative to itself")

        kvpair_order = self._kvpair_order
        for node in nodes_being_relocated:
            kvpair_order.remove_node(node)
            kvpair_order.insert_node_before(node, reference_node)

        if len(nodes_being_relocated) == 1 and len(nodes) > 1:
            # Regenerate the (new) relative field order.
            field_name = nodes_being_relocated[0].value.field_name
            self._regenerate_relative_kvapir_order(field_name)

    def order_after(self, field, reference_field):
        # type: (ParagraphKey, ParagraphKey) -> None
        """Re-order the given field so appears directly before the reference field in the paragraph

        The reference field must be present.
        """
        nodes, nodes_being_relocated = self._nodes_being_relocated(field)
        assert len(nodes_being_relocated) == 1 or len(nodes) == len(nodes_being_relocated)
        _, reference_nodes = self._nodes_being_relocated(reference_field)
        # For "after" we always use the "last" variant as reference in case of doubt
        reference_node = reference_nodes[-1]
        if reference_node in nodes_being_relocated:
            raise ValueError("Cannot re-order a field relative to itself")

        kvpair_order = self._kvpair_order
        # Use "reversed" to preserve the relative order of the nodes assuming a bulk reorder
        for node in reversed(nodes_being_relocated):
            kvpair_order.remove_node(node)
            kvpair_order.insert_node_after(node, reference_node)

        if len(nodes_being_relocated) == 1 and len(nodes) > 1:
            # Regenerate the (new) relative field order.
            field_name = nodes_being_relocated[0].value.field_name
            self._regenerate_relative_kvapir_order(field_name)

    def _regenerate_relative_kvapir_order(self, field_name):
        # type: (_strI) -> None
        nodes = []
        for node in self._kvpair_order.iter_nodes():
            if node.value.field_name == field_name:
                nodes.append(node)
        self._kvpair_elements[field_name] = nodes

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from self._kvpair_order

    @property
    def kvpair_count(self):
        # type: () -> int
        return len(self._kvpair_order)

    def iter_keys(self):
        # type: () -> Iterable[ParagraphKey]
        yield from (kv.field_name for kv in self._kvpair_order)

    def _resolve_to_single_node(self,
                                nodes,  # type: List[KVPNode]
                                key,  # type: str
                                index,  # type: Optional[int]
                                name_token,  # type: Optional[Deb822FieldNameToken]
                                use_get=False  # type: bool
                                ):
        # type: (...) -> Optional[KVPNode]
        if index is None:
            if len(nodes) != 1:
                if name_token is not None:
                    node = self._find_node_via_name_token(name_token, nodes)
                    if node is not None:
                        return node
                msg = "Ambiguous key {key} - the field appears {res_len} times. Use" \
                      " ({key}, index) to denote which instance of the field you want.  (Index" \
                      " can be 0..{res_len_1} or e.g. -1 to denote the last field)"
                raise AmbiguousDeb822FieldKeyError(msg.format(key=key,
                                                              res_len=len(nodes),
                                                              res_len_1=len(nodes) - 1))
            index = 0
        try:
            return nodes[index]
        except IndexError:
            if use_get:
                return None
            msg = 'Field "{key}" was present but the index "{index}" was invalid.'
            raise KeyError(msg.format(key=key, index=index))

    def get_kvpair_element(self,
                           item,  # type: ParagraphKey
                           use_get=False  # type: bool
                           ):
        # type: (...) -> Optional[Deb822KeyValuePairElement]
        key, index, name_token = _unpack_key(item)
        if use_get:
            nodes = self._kvpair_elements.get(key)
            if nodes is None:
                return None
        else:
            nodes = self._kvpair_elements[key]
        node = self._resolve_to_single_node(nodes, key, index, name_token, use_get=use_get)
        if node is not None:
            return node.value
        return None

    @staticmethod
    def _find_node_via_name_token(
            name_token,  # type: Deb822FieldNameToken
            elements  # type: Iterable[KVPNode]
    ):
        # type: (...) -> Optional[KVPNode]
        # if we are given a name token, then it is non-ambiguous if we have exactly
        # that name token in our list of nodes.  It will be an O(n) lookup but we
        # probably do not have that many duplicate fields (and even if do, it is not
        # exactly a valid file, so there little reason to optimize for it)
        for node in elements:
            if name_token is node.value.field_token:
                return node
        return None

    def contains_kvpair_element(self, item):
        # type: (object) -> bool
        if not isinstance(item, (str, tuple, Deb822FieldNameToken)):
            return False
        item = cast('ParagraphKey', item)
        try:
            return self.get_kvpair_element(item, use_get=True) is not None
        except AmbiguousDeb822FieldKeyError:
            return True

    def set_kvpair_element(self, key, value):
        # type: (ParagraphKey, Deb822KeyValuePairElement) -> None
        key, index, name_token = _unpack_key(key)
        if name_token:
            if name_token is not value.field_token:
                original_nodes = self._kvpair_elements.get(value.field_name)
                original_node = None
                if original_nodes is not None:
                    original_node = self._find_node_via_name_token(name_token, original_nodes)

                if original_node is None:
                    raise ValueError("Key is a Deb822FieldNameToken, but not *the*"
                                     " Deb822FieldNameToken for the value nor the"
                                     " Deb822FieldNameToken for an existing field in the paragraph")
                # Primarily for mypy's sake
                assert original_nodes is not None
                # Rely on the index-based code below to handle update.
                index = original_nodes.index(original_node)
            key = value.field_name
        else:
            if key != value.field_name:
                raise ValueError("Cannot insert value under a different field value than field name"
                                 " from its Deb822FieldNameToken implies")
            # Use the string from the Deb822FieldNameToken as it is a _strI and has the same value
            # (memory optimization)
            key = value.field_name
        original_nodes = self._kvpair_elements.get(key)
        if original_nodes is None or not original_nodes:
            if index is not None and index != 0:
                msg = "Cannot replace field ({key}, {index}) as the field does not exist" \
                      " in the first place.  Please index-less key or ({key}, 0) if you" \
                      " want to add the field."
                raise KeyError(msg.format(key=key, index=index))
            node = self._kvpair_order.append(value)
            if key not in self._kvpair_elements:
                self._kvpair_elements[key] = [node]
            else:
                self._kvpair_elements[key].append(node)
            return

        replace_all = False
        if index is None:
            replace_all = True
            node = original_nodes[0]
            if len(original_nodes) != 1:
                self._kvpair_elements[key] = [node]
        else:
            # We insist on there being an original node, which as a side effect ensures
            # you cannot add additional copies of the field.  This means that you cannot
            # make the problem worse.
            node = original_nodes[index]

        # Replace the value of the existing node plus do a little dance
        # for the parent element part.
        node.value.parent_element = None
        value.parent_element = self
        node.value = value

        if replace_all and len(original_nodes) != 1:
            # If we were in a replace-all mode, discard any remaining nodes
            for n in original_nodes[1:]:
                n.value.parent_element = None
                self._kvpair_order.remove_node(n)

    def remove_kvpair_element(self, key):
        # type: (ParagraphKey) -> None
        key, idx, name_token = _unpack_key(key)
        field_list = self._kvpair_elements[key]

        if name_token is None and idx is None:
            # Remove all case
            for node in field_list:
                node.value.parent_element = None
                self._kvpair_order.remove_node(node)
            del self._kvpair_elements[key]
            return

        if name_token is not None:
            # Indirection between original_node and node for mypy's sake
            original_node = self._find_node_via_name_token(name_token, field_list)
            if original_node is None:
                msg = 'The field "{key}" is present but key used to access it is not.'
                raise KeyError(msg.format(key=key))
            node = original_node
        else:
            assert idx is not None
            try:
                node = field_list[idx]
            except KeyError:
                msg = 'The field "{key}" is present, but the index "{idx}" was invalid.'
                raise KeyError(msg.format(key=key, idx=idx))

        if len(field_list) == 1:
            del self._kvpair_elements[key]
        else:
            field_list.remove(node)
        node.value.parent_element = None
        self._kvpair_order.remove_node(node)

    def sort_fields(self, key=None):
        # type: (Optional[Callable[[str], Any]]) -> None
        """Re-order all fields

        :param key: Provide a key function (same semantics as for sorted).   Keep in mind that
          the module preserve the cases for field names - in generally, callers are recommended
          to use "lower()" to normalize the case.
        """

        if key is None:
            key = default_field_sort_key

        # Work around mypy that cannot seem to shred the Optional notion
        # without this little indirection
        key_impl = key

        def _actual_key(kvpair):
            # type: (Deb822KeyValuePairElement) -> Any
            return key_impl(kvpair.field_name)

        for last_kvpair in reversed(self._kvpair_order):
            last_kvpair.value_element.add_final_newline_if_missing()
            break

        sorted_kvpair_list = sorted(self._kvpair_order, key=_actual_key)
        self._kvpair_order = LinkedList()
        self._kvpair_elements = {}
        self._init_kvpair_fields(sorted_kvpair_list)


class Deb822FileElement(Deb822Element):
    """Represents the entire deb822 file"""

    def __init__(self, token_and_elements):
        # type: (LinkedList[TokenOrElement]) -> None
        super().__init__()
        self._token_and_elements = token_and_elements
        self._init_parent_of_parts()

    @classmethod
    def new_empty_file(cls):
        # type: () -> Deb822FileElement
        """Creates a new Deb822FileElement with no contents

        Note that a deb822 file must be non-empty to be considered valid
        """
        return cls(LinkedList())

    @property
    def is_valid_file(self):
        # type: () -> bool
        """Returns true if the file is valid

        Invalid elements include error elements (Deb822ErrorElement) but also
        issues such as paragraphs with duplicate fields or "empty" files
        (a valid deb822 file contains at least one paragraph).
        """
        had_paragraph = False
        for paragraph in self:
            had_paragraph = True
            if not paragraph or paragraph.has_duplicate_fields:
                return False

        if not had_paragraph:
            return False

        return self.find_first_error_element() is None

    def find_first_error_element(self):
        # type: () -> Optional[Deb822ErrorElement]
        """Returns the first Deb822ErrorElement (or None) in the file"""
        return next(iter(self.iter_recurse(only_element_or_token_type=Deb822ErrorElement)), None)

    def __iter__(self):
        # type: () -> Iterator[Deb822ParagraphElement]
        return iter(self.iter_parts_of_type(Deb822ParagraphElement))

    def iter_parts(self):
        # type: () -> Iterable[TokenOrElement]
        yield from self._token_and_elements

    def insert(self, idx, para):
        # type: (int, Deb822ParagraphElement) -> None
        """Inserts a paragraph into the file at the given "index" of paragraphs

        Note that if the index is between two paragraphs containing a "free
        floating" comment (e.g. paragrah/start-of-file, empty line, comment,
        empty line, paragraph) then it is unspecified which "side" of the
        comment the new paragraph will appear and this may change between
        versions of python-debian.


        >>> original = '''
        ... Package: libfoo-dev
        ... Depends: libfoo1 (= ${binary:Version}), ${shlib:Depends}, ${misc:Depends}
        ... '''.lstrip()
        >>> deb822_file = parse_deb822_file(original.splitlines())
        >>> para1 = Deb822ParagraphElement.new_empty_paragraph()
        >>> para1["Source"] = "foo"
        >>> para1["Build-Depends"] = "debhelper-compat (= 13)"
        >>> para2 = Deb822ParagraphElement.new_empty_paragraph()
        >>> para2["Package"] = "libfoo1"
        >>> para2["Depends"] = "${shlib:Depends}, ${misc:Depends}"
        >>> deb822_file.insert(0, para1)
        >>> deb822_file.insert(1, para2)
        >>> expected = '''
        ... Source: foo
        ... Build-Depends: debhelper-compat (= 13)
        ...
        ... Package: libfoo1
        ... Depends: ${shlib:Depends}, ${misc:Depends}
        ...
        ... Package: libfoo-dev
        ... Depends: libfoo1 (= ${binary:Version}), ${shlib:Depends}, ${misc:Depends}
        ... '''.lstrip()
        >>> deb822_file.dump() == expected
        True
        """

        anchor_node = None
        needs_newline = True
        if idx == 0:
            # Special-case, if idx is 0, then we insert it before everything else.
            # This is mostly a cosmetic choice for corner cases involving free-floating
            # comments in the file.
            if not self._token_and_elements:
                self.append(para)
                return
            anchor_node = self._token_and_elements.head_node
            needs_newline = bool(self._token_and_elements)
        else:
            i = 0
            for node in self._token_and_elements.iter_nodes():
                entry = node.value
                if isinstance(entry, Deb822ParagraphElement):
                    i += 1
                if idx == i - 1:
                    anchor_node = node
                    break

        if anchor_node is None:
            # Empty list or idx after the last paragraph both degenerate into append
            self.append(para)
        else:
            if needs_newline:
                # Remember to inject the "separating" newline between two paragraphs
                nl_token = self._set_parent(Deb822WhitespaceToken('\n'))
                anchor_node = self._token_and_elements.insert_before(nl_token, anchor_node)
            self._token_and_elements.insert_before(self._set_parent(para), anchor_node)

    def append(self, paragraph):
        # type: (Deb822ParagraphElement) -> None
        """Appends a paragraph to the file

        >>> deb822_file = Deb822FileElement.new_empty_file()
        >>> para1 = Deb822ParagraphElement.new_empty_paragraph()
        >>> para1["Source"] = "foo"
        >>> para1["Build-Depends"] = "debhelper-compat (= 13)"
        >>> para2 = Deb822ParagraphElement.new_empty_paragraph()
        >>> para2["Package"] = "foo"
        >>> para2["Depends"] = "${shlib:Depends}, ${misc:Depends}"
        >>> deb822_file.append(para1)
        >>> deb822_file.append(para2)
        >>> expected = '''
        ... Source: foo
        ... Build-Depends: debhelper-compat (= 13)
        ...
        ... Package: foo
        ... Depends: ${shlib:Depends}, ${misc:Depends}
        ... '''.lstrip()
        >>> deb822_file.dump() == expected
        True
        """
        tail_element = self._token_and_elements.tail
        if paragraph.parent_element is not None:
            if paragraph.parent_element is self:
                raise ValueError("Paragraph is already a part of this file")
            raise ValueError("Paragraph is already part of another Deb822File")

        # We need a separating newline if there is not a whitespace token at the end of the file.
        # Note the special case where the file ends on a comment; here we insert a whitespace too
        # to be sure.  Otherwise, we would have to check that there is an empty line before that
        # comment and that is too much effort.
        if tail_element and not isinstance(tail_element, Deb822WhitespaceToken):
            self._token_and_elements.append(self._set_parent(Deb822WhitespaceToken('\n')))
        self._token_and_elements.append(self._set_parent(paragraph))

    def remove(self, paragraph):
        # type: (Deb822ParagraphElement) -> None
        if paragraph.parent_element is not self:
            raise ValueError("Paragraph is part of a different file")
        node = None
        for node in self._token_and_elements.iter_nodes():
            if node.value is paragraph:
                break
        if node is None:
            raise RuntimeError("unable to find paragraph")
        previous_node = node.previous_node
        next_node = node.next_node
        self._token_and_elements.remove_node(node)
        if next_node is None:
            if previous_node and isinstance(previous_node.value, Deb822WhitespaceToken):
                self._token_and_elements.remove_node(previous_node)
        else:
            if isinstance(next_node.value, Deb822WhitespaceToken):
                self._token_and_elements.remove_node(next_node)
        paragraph.parent_element = None

    def _set_parent(self, t):
        # type: (TE) -> TE
        t.parent_element = self
        return t

    @overload
    def dump(self,
             fd  # type: IO[bytes]
             ):
        # type: (...) -> None
        pass

    @overload
    def dump(self):
        # type: () -> str
        pass

    def dump(self,
             fd=None  # type: Optional[IO[bytes]]
             ):
        # type: (...) -> Optional[str]
        if fd is None:
            return "".join(t.text for t in self.iter_tokens())
        for token in self.iter_tokens():
            fd.write(token.text.encode('utf-8'))
        return None


_combine_error_tokens_into_elements = combine_into_replacement(Deb822ErrorToken, Deb822ErrorElement)
_combine_comment_tokens_into_elements = combine_into_replacement(Deb822CommentToken,
                                                                 Deb822CommentElement)
_combine_vl_elements_into_value_elements = combine_into_replacement(Deb822ValueLineElement,
                                                                    Deb822ValueElement)
_combine_kvp_elements_into_paragraphs = combine_into_replacement(
    Deb822KeyValuePairElement,
    Deb822ParagraphElement,
    constructor=Deb822ParagraphElement.from_kvpairs
    )


def _parsed_value_render_factory(discard_comments):
    # type: (bool) -> Callable[[Deb822ParsedValueElement], str]
    return Deb822ParsedValueElement.convert_to_text_without_comments if discard_comments \
        else Deb822ParsedValueElement.convert_to_text


LIST_SPACE_SEPARATED_INTERPRETATION = ListInterpretation(whitespace_split_tokenizer,
                                                         _parse_whitespace_list_value,
                                                         Deb822ParsedValueElement,
                                                         Deb822SemanticallySignificantWhiteSpace,
                                                         lambda: Deb822SpaceSeparatorToken(' '),
                                                         _parsed_value_render_factory,
                                                         )
LIST_COMMA_SEPARATED_INTERPRETATION = ListInterpretation(comma_split_tokenizer,
                                                         _parse_comma_list_value,
                                                         Deb822ParsedValueElement,
                                                         Deb822CommaToken,
                                                         Deb822CommaToken,
                                                         _parsed_value_render_factory,
                                                         )
LIST_UPLOADERS_INTERPRETATION = ListInterpretation(comma_split_tokenizer,
                                                   _parse_uploaders_list_value,
                                                   Deb822ParsedValueElement,
                                                   Deb822CommaToken,
                                                   Deb822CommaToken,
                                                   _parsed_value_render_factory,
                                                   )


def _non_end_of_line_token(v):
    # type: (TokenOrElement) -> bool
    # Consume tokens until the newline
    return not isinstance(v, Deb822WhitespaceToken) or v.text != '\n'


def _build_value_line(token_stream  # type: Iterable[Union[TokenOrElement, Deb822CommentElement]]
                      ):
    # type: (...) -> Iterable[Union[TokenOrElement, Deb822ValueLineElement]]
    """Parser helper - consumes tokens part of a Deb822ValueEntryElement and turns them into one"""
    buffered_stream = BufferingIterator(token_stream)

    # Deb822ValueLineElement is a bit tricky because of how we handle whitespace
    # and comments.
    #
    # In relation to comments, then only continuation lines can have comments.
    # If there is a comment before a "K: V" line, then the comment is associated
    # with the field rather than the value.
    #
    # On the whitespace front, then we separate syntactical mandatory whitespace
    # from optional whitespace.  As an example:
    #
    # """
    # # some comment associated with the Depends field
    # Depends:_foo_$
    # # some comment associated with the line containing "bar"
    # !________bar_$
    # """
    #
    # Where "$" and "!" represents mandatory whitespace (the newline and the first
    # space are required for the file to be parsed correctly), where as "_" is
    # "optional" whitespace (from a syntactical point of view).
    #
    # This distinction enable us to facilitate APIs for easy removal/normalization
    # of redundant whitespaces without having programmers worry about trashing
    # the file.
    #
    #

    comment_element = None
    continuation_line_token = None
    token = None  # type: Optional[TokenOrElement]

    for token in buffered_stream:
        start_of_value_entry = False
        if isinstance(token, Deb822ValueContinuationToken):
            continuation_line_token = token
            start_of_value_entry = True
            token = None
        elif isinstance(token, Deb822FieldSeparatorToken):
            start_of_value_entry = True
        elif isinstance(token, Deb822CommentElement):
            next_token = buffered_stream.peek()
            # If the next token is a continuation line token, then this comment
            # belong to a value and we might as well just start the value
            # parsing now.
            #
            # Note that we rely on this behaviour to avoid emitting the comment
            # token (failing to do so would cause the comment to appear twice
            # in the file).
            if isinstance(next_token, Deb822ValueContinuationToken):
                start_of_value_entry = True
                comment_element = token
                token = None
                # Use next with None to avoid raising StopIteration inside a generator
                # It won't happen, but pylint cannot see that, so we do this instead.
                continuation_line_token = cast('Deb822ValueContinuationToken',
                                               next(buffered_stream, None)
                                               )
                assert continuation_line_token is not None

        if token is not None:
            yield token
        if start_of_value_entry:
            tokens_in_value = list(buffered_stream.takewhile(_non_end_of_line_token))
            eol_token = cast('Deb822WhitespaceToken', next(buffered_stream, None))
            assert eol_token is None or eol_token.text == '\n'
            leading_whitespace = None
            trailing_whitespace = None
            # "Depends:\n foo" would cause tokens_in_value to be empty for the
            # first "value line" (the empty part between ":" and "\n")
            if tokens_in_value:
                # Another special-case, "Depends: \n foo" (i.e. space after colon)
                # should not introduce an IndexError
                if isinstance(tokens_in_value[-1], Deb822WhitespaceToken):
                    trailing_whitespace = cast('Deb822WhitespaceToken',
                                               tokens_in_value.pop()
                                               )
                if tokens_in_value and isinstance(tokens_in_value[-1], Deb822WhitespaceToken):
                    leading_whitespace = cast('Deb822WhitespaceToken', tokens_in_value[0])
                    tokens_in_value = tokens_in_value[1:]
            yield Deb822ValueLineElement(comment_element,
                                         continuation_line_token,
                                         leading_whitespace,
                                         tokens_in_value,
                                         trailing_whitespace,
                                         eol_token
                                         )
            comment_element = None
            continuation_line_token = None


def _build_field_with_value(
        token_stream  # type: Iterable[Union[TokenOrElement, Deb822ValueElement]]
    ):
    # type: (...) -> Iterable[Union[TokenOrElement, Deb822KeyValuePairElement]]
    buffered_stream = BufferingIterator(token_stream)
    for token_or_element in buffered_stream:
        start_of_field = False
        comment_element = None
        if isinstance(token_or_element, Deb822FieldNameToken):
            start_of_field = True
        elif isinstance(token_or_element, Deb822CommentElement):
            comment_element = token_or_element
            next_token = buffered_stream.peek()
            start_of_field = isinstance(next_token, Deb822FieldNameToken)
            if start_of_field:
                # Remember to consume the field token, the we are aligned
                try:
                    token_or_element = next(buffered_stream)
                except StopIteration:  # pragma: no cover
                    raise AssertionError

        if start_of_field:
            field_name = token_or_element
            separator = next(buffered_stream, None)
            value_element = next(buffered_stream, None)
            if separator is None or value_element is None:
                # Early EOF - should not be possible with how the tokenizer works
                # right now, but now it is future proof.
                if comment_element:
                    yield comment_element
                error_elements = [field_name]
                if separator is not None:
                    error_elements.append(separator)
                yield Deb822ErrorElement(error_elements)
                return

            if isinstance(separator, Deb822FieldSeparatorToken) \
                    and isinstance(value_element, Deb822ValueElement):
                yield Deb822KeyValuePairElement(comment_element,
                                                cast('Deb822FieldNameToken', field_name),
                                                separator,
                                                value_element,
                                                )
            else:
                # We had a parse error, consume until the newline.
                error_tokens = [token_or_element]  # type: List[TokenOrElement]
                error_tokens.extend(buffered_stream.takewhile(_non_end_of_line_token))
                nl = buffered_stream.peek()
                # Take the newline as well if present
                if nl and isinstance(nl, Deb822NewlineAfterValueToken):
                    next(buffered_stream, None)
                    error_tokens.append(nl)
                yield Deb822ErrorElement(error_tokens)
        else:
            # Token is not part of a field, emit it as-is
            yield token_or_element


def _abort_on_error_tokens(sequence):
    # type: (Iterable[TokenOrElement]) -> Iterable[TokenOrElement]
    for token in sequence:
        # We are always called while the sequence consists entirely of tokens
        if isinstance(token, Deb822ErrorToken):
            error_as_text = token.text.replace('\n', '\\n')
            raise SyntaxOrParseError(
                'Syntax or Parse error on the line: "{error_as_text}"'.format(
                    error_as_text=error_as_text))
        yield token


def parse_deb822_file(sequence,  # type: Union[Iterable[Union[str, bytes]], str]
                      *,
                      accept_files_with_error_tokens=False,  # type: bool
                      accept_files_with_duplicated_fields=False,  # type: bool
                      encoding='utf-8'  # type: str
                      ):
    # type: (...) -> Deb822FileElement
    """

    :param sequence: An iterable over lines of str or bytes (an open file for
      reading will do).  If line endings are provided in the input, then they
      must be present on every line (except the last) will be preserved as-is.
      If omitted and the content is at least 2 lines, then parser will assume
      implicit newlines.
    :param accept_files_with_error_tokens: If True, files with critical syntax
      or parse errors will be returned as "successfully" parsed. Usually,
      working on files with this kind of errors are not desirable as it is
      hard to make sense of such files (and they might in fact not be a deb822
      file at all).  When set to False (the default) a ValueError is raised if
      there is a critical syntax or parse error.
      Note that duplicated fields in a paragraph is not considered a critical
      parse error by this parser as the implementation can gracefully cope
      with these. Use accept_files_with_duplicated_fields to determine if
      such files should be accepted.
    :param accept_files_with_duplicated_fields: If True, then
      files containing paragraphs with duplicated fields will be returned as
      "successfully" parsed even though they are invalid according to the
      specification.  The paragraphs will prefer the first appearance of the
      field unless caller explicitly requests otherwise (e.g., via
      Deb822ParagraphElement.configured_view).  If False, then this method
      will raise a ValueError if any duplicated fields are seen inside any
      paragraph.
    :param encoding: The encoding to use (this is here to support Deb822-like
       APIs, new code should not use this parameter).
    """

    if isinstance(sequence, (str, bytes)):
        # Match the deb822 API.
        sequence = sequence.splitlines(True)

    # The order of operations are important here.  As an example,
    # _build_value_line assumes that all comment tokens have been merged
    # into comment elements.  Likewise, _build_field_and_value assumes
    # that value tokens (along with their comments) have been combined
    # into elements.
    tokens = tokenize_deb822_file(sequence, encoding=encoding)  # type: Iterable[TokenOrElement]
    if not accept_files_with_error_tokens:
        tokens = _abort_on_error_tokens(tokens)
    tokens = _combine_comment_tokens_into_elements(tokens)
    tokens = _build_value_line(tokens)
    tokens = _combine_vl_elements_into_value_elements(tokens)
    tokens = _build_field_with_value(tokens)
    tokens = _combine_kvp_elements_into_paragraphs(tokens)
    # Combine any free-floating error tokens into error elements.  We do
    # this last as it enables other parts of the parser to include error
    # tokens in their error elements if they discover something is wrong.
    tokens = _combine_error_tokens_into_elements(tokens)

    deb822_file = Deb822FileElement(LinkedList(tokens))

    if not accept_files_with_duplicated_fields:
        for no, paragraph in enumerate(deb822_file):
            if isinstance(paragraph, Deb822DuplicateFieldsParagraphElement):
                field_names = set()
                dup_field = None
                for field in paragraph.keys():
                    field_name, _, _ = _unpack_key(field)
                    # assert for mypy
                    assert isinstance(field_name, str)
                    if field_name in field_names:
                        dup_field = field_name
                        break
                    field_names.add(field_name)
                if dup_field is not None:
                    msg = 'Duplicate field "{dup_field}" in paragraph number {no}'
                    raise ValueError(msg.format(dup_field=dup_field, no=no))

    return deb822_file


if __name__ == "__main__":  # pragma: no cover
    import doctest
    doctest.testmod()
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     #
# core.py
#
import os
import typing
from typing import (
    NamedTuple,
    Union,
    Callable,
    Any,
    Generator,
    Tuple,
    List,
    TextIO,
    Set,
    Sequence,
)
from abc import ABC, abstractmethod
from enum import Enum
import string
import copy
import warnings
import re
import sys
from collections.abc import Iterable
import traceback
import types
from operator import itemgetter
from functools import wraps
from threading import RLock
from pathlib import Path

from .util import (
    _FifoCache,
    _UnboundedCache,
    __config_flags,
    _collapse_string_to_ranges,
    _escape_regex_range_chars,
    _bslash,
    _flatten,
    LRUMemo as _LRUMemo,
    UnboundedMemo as _UnboundedMemo,
)
from .exceptions import *
from .actions import *
from .results import ParseResults, _ParseResultsWithOffset
from .unicode import pyparsing_unicode

_MAX_INT = sys.maxsize
str_type: Tuple[type, ...] = (str, bytes)

#
# Copyright (c) 2003-2022  Paul T. McGuire
#
# 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.
#


if sys.version_info >= (3, 8):
    from functools import cached_property
else:

    class cached_property:
        def __init__(self, func):
            self._func = func

        def __get__(self, instance, owner=None):
            ret = instance.__dict__[self._func.__name__] = self._func(instance)
            return ret


class __compat__(__config_flags):
    """
    A cross-version compatibility configuration for pyparsing features that will be
    released in a future version. By setting values in this configuration to True,
    those features can be enabled in prior versions for compatibility development
    and testing.

    - ``collect_all_And_tokens`` - flag to enable fix for Issue #63 that fixes erroneous grouping
      of results names when an :class:`And` expression is nested within an :class:`Or` or :class:`MatchFirst`;
      maintained for compatibility, but setting to ``False`` no longer restores pre-2.3.1
      behavior
    """

    _type_desc = "compatibility"

    collect_all_And_tokens = True

    _all_names = [__ for __ in locals() if not __.startswith("_")]
    _fixed_names = """
        collect_all_And_tokens
        """.split()


class __diag__(__config_flags):
    _type_desc = "diagnostic"

    warn_multiple_tokens_in_named_alternation = False
    warn_ungrouped_named_tokens_in_collection = False
    warn_name_set_on_empty_Forward = False
    warn_on_parse_using_empty_Forward = False
    warn_on_assignment_to_Forward = False
    warn_on_multiple_string_args_to_oneof = False
    warn_on_match_first_with_lshift_operator = False
    enable_debug_on_named_expressions = False

    _all_names = [__ for __ in locals() if not __.startswith("_")]
    _warning_names = [name for name in _all_names if name.startswith("warn")]
    _debug_names = [name for name in _all_names if name.startswith("enable_debug")]

    @classmethod
    def enable_all_warnings(cls) -> None:
        for name in cls._warning_names:
            cls.enable(name)


class Diagnostics(Enum):
    """
    Diagnostic configuration (all default to disabled)
    - ``warn_multiple_tokens_in_named_alternation`` - flag to enable warnings when a results
      name is defined on a :class:`MatchFirst` or :class:`Or` expression with one or more :class:`And` subexpressions
    - ``warn_ungrouped_named_tokens_in_collection`` - flag to enable warnings when a results
      name is defined on a containing expression with ungrouped subexpressions that also
      have results names
    - ``warn_name_set_on_empty_Forward`` - flag to enable warnings when a :class:`Forward` is defined
      with a results name, but has no contents defined
    - ``warn_on_parse_using_empty_Forward`` - flag to enable warnings when a :class:`Forward` is
      defined in a grammar but has never had an expression attached to it
    - ``warn_on_assignment_to_Forward`` - flag to enable warnings when a :class:`Forward` is defined
      but is overwritten by assigning using ``'='`` instead of ``'<<='`` or ``'<<'``
    - ``warn_on_multiple_string_args_to_oneof`` - flag to enable warnings when :class:`one_of` is
      incorrectly called with multiple str arguments
    - ``enable_debug_on_named_expressions`` - flag to auto-enable debug on all subsequent
      calls to :class:`ParserElement.set_name`

    Diagnostics are enabled/disabled by calling :class:`enable_diag` and :class:`disable_diag`.
    All warnings can be enabled by calling :class:`enable_all_warnings`.
    """

    warn_multiple_tokens_in_named_alternation = 0
    warn_ungrouped_named_tokens_in_collection = 1
    warn_name_set_on_empty_Forward = 2
    warn_on_parse_using_empty_Forward = 3
    warn_on_assignment_to_Forward = 4
    warn_on_multiple_string_args_to_oneof = 5
    warn_on_match_first_with_lshift_operator = 6
    enable_debug_on_named_expressions = 7


def enable_diag(diag_enum: Diagnostics) -> None:
    """
    Enable a global pyparsing diagnostic flag (see :class:`Diagnostics`).
    """
    __diag__.enable(diag_enum.name)


def disable_diag(diag_enum: Diagnostics) -> None:
    """
    Disable a global pyparsing diagnostic flag (see :class:`Diagnostics`).
    """
    __diag__.disable(diag_enum.name)


def enable_all_warnings() -> None:
    """
    Enable all global pyparsing diagnostic warnings (see :class:`Diagnostics`).
    """
    __diag__.enable_all_warnings()


# hide abstract class
del __config_flags


def _should_enable_warnings(
    cmd_line_warn_options: typing.Iterable[str], warn_env_var: typing.Optional[str]
) -> bool:
    enable = bool(warn_env_var)
    for warn_opt in cmd_line_warn_options:
        w_action, w_message, w_category, w_module, w_line = (warn_opt + "::::").split(
            ":"
        )[:5]
        if not w_action.lower().startswith("i") and (
            not (w_message or w_category or w_module) or w_module == "pyparsing"
        ):
            enable = True
        elif w_action.lower().startswith("i") and w_module in ("pyparsing", ""):
            enable = False
    return enable


if _should_enable_warnings(
    sys.warnoptions, os.environ.get("PYPARSINGENABLEALLWARNINGS")
):
    enable_all_warnings()


# build list of single arg builtins, that can be used as parse actions
_single_arg_builtins = {
    sum,
    len,
    sorted,
    reversed,
    list,
    tuple,
    set,
    any,
    all,
    min,
    max,
}

_generatorType = types.GeneratorType
ParseAction = Union[
    Callable[[], Any],
    Callable[[ParseResults], Any],
    Callable[[int, ParseResults], Any],
    Callable[[str, int, ParseResults], Any],
]
ParseCondition = Union[
    Callable[[], bool],
    Callable[[ParseResults], bool],
    Callable[[int, ParseResults], bool],
    Callable[[str, int, ParseResults], bool],
]
ParseFailAction = Callable[[str, int, "ParserElement", Exception], None]
DebugStartAction = Callable[[str, int, "ParserElement", bool], None]
DebugSuccessAction = Callable[
    [str, int, int, "ParserElement", ParseResults, bool], None
]
DebugExceptionAction = Callable[[str, int, "ParserElement", Exception, bool], None]


alphas = string.ascii_uppercase + string.ascii_lowercase
identchars = pyparsing_unicode.Latin1.identchars
identbodychars = pyparsing_unicode.Latin1.identbodychars
nums = "0123456789"
hexnums = nums + "ABCDEFabcdef"
alphanums = alphas + nums
printables = "".join([c for c in string.printable if c not in string.whitespace])

_trim_arity_call_line: traceback.StackSummary = None


def _trim_arity(func, max_limit=3):
    """decorator to trim function calls to match the arity of the target"""
    global _trim_arity_call_line

    if func in _single_arg_builtins:
        return lambda s, l, t: func(t)

    limit = 0
    found_arity = False

    def extract_tb(tb, limit=0):
        frames = traceback.extract_tb(tb, limit=limit)
        frame_summary = frames[-1]
        return [frame_summary[:2]]

    # synthesize what would be returned by traceback.extract_stack at the call to
    # user's parse action 'func', so that we don't incur call penalty at parse time

    # fmt: off
    LINE_DIFF = 7
    # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND
    # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!
    _trim_arity_call_line = (_trim_arity_call_line or traceback.extract_stack(limit=2)[-1])
    pa_call_line_synth = (_trim_arity_call_line[0], _trim_arity_call_line[1] + LINE_DIFF)

    def wrapper(*args):
        nonlocal found_arity, limit
        while 1:
            try:
                ret = func(*args[limit:])
                found_arity = True
                return ret
            except TypeError as te:
                # re-raise TypeErrors if they did not come from our arity testing
                if found_arity:
                    raise
                else:
                    tb = te.__traceback__
                    trim_arity_type_error = (
                        extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth
                    )
                    del tb

                    if trim_arity_type_error:
                        if limit < max_limit:
                            limit += 1
                            continue

                    raise
    # fmt: on

    # copy func name to wrapper for sensible debug output
    # (can't use functools.wraps, since that messes with function signature)
    func_name = getattr(func, "__name__", getattr(func, "__class__").__name__)
    wrapper.__name__ = func_name
    wrapper.__doc__ = func.__doc__

    return wrapper


def condition_as_parse_action(
    fn: ParseCondition, message: str = None, fatal: bool = False
) -> ParseAction:
    """
    Function to convert a simple predicate function that returns ``True`` or ``False``
    into a parse action. Can be used in places when a parse action is required
    and :class:`ParserElement.add_condition` cannot be used (such as when adding a condition
    to an operator level in :class:`infix_notation`).

    Optional keyword arguments:

    - ``message`` - define a custom message to be used in the raised exception
    - ``fatal`` - if True, will raise :class:`ParseFatalException` to stop parsing immediately;
      otherwise will raise :class:`ParseException`

    """
    msg = message if message is not None else "failed user-defined condition"
    exc_type = ParseFatalException if fatal else ParseException
    fn = _trim_arity(fn)

    @wraps(fn)
    def pa(s, l, t):
        if not bool(fn(s, l, t)):
            raise exc_type(s, l, msg)

    return pa


def _default_start_debug_action(
    instring: str, loc: int, expr: "ParserElement", cache_hit: bool = False
):
    cache_hit_str = "*" if cache_hit else ""
    print(
        (
            "{}Match {} at loc {}({},{})\n  {}\n  {}^".format(
                cache_hit_str,
                expr,
                loc,
                lineno(loc, instring),
                col(loc, instring),
                line(loc, instring),
                " " * (col(loc, instring) - 1),
            )
        )
    )


def _default_success_debug_action(
    instring: str,
    startloc: int,
    endloc: int,
    expr: "ParserElement",
    toks: ParseResults,
    cache_hit: bool = False,
):
    cache_hit_str = "*" if cache_hit else ""
    print("{}Matched {} -> {}".format(cache_hit_str, expr, toks.as_list()))


def _default_exception_debug_action(
    instring: str,
    loc: int,
    expr: "ParserElement",
    exc: Exception,
    cache_hit: bool = False,
):
    cache_hit_str = "*" if cache_hit else ""
    print(
        "{}Match {} failed, {} raised: {}".format(
            cache_hit_str, expr, type(exc).__name__, exc
        )
    )


def null_debug_action(*args):
    """'Do-nothing' debug action, to suppress debugging output during parsing."""


class ParserElement(ABC):
    """Abstract base level parser element class."""

    DEFAULT_WHITE_CHARS: str = " \n\t\r"
    verbose_stacktrace: bool = False
    _literalStringClass: typing.Optional[type] = None

    @staticmethod
    def set_default_whitespace_chars(chars: str) -> None:
        r"""
        Overrides the default whitespace chars

        Example::

            # default whitespace chars are space, <TAB> and newline
            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']

            # change to just treat newline as significant
            ParserElement.set_default_whitespace_chars(" \t")
            Word(alphas)[1, ...].parse_string("abc def\nghi jkl")  # -> ['abc', 'def']
        """
        ParserElement.DEFAULT_WHITE_CHARS = chars

        # update whitespace all parse expressions defined in this module
        for expr in _builtin_exprs:
            if expr.copyDefaultWhiteChars:
                expr.whiteChars = set(chars)

    @staticmethod
    def inline_literals_using(cls: type) -> None:
        """
        Set class to be used for inclusion of string literals into a parser.

        Example::

            # default literal class used is Literal
            integer = Word(nums)
            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")

            date_str.parse_string("1999/12/31")  # -> ['1999', '/', '12', '/', '31']


            # change to Suppress
            ParserElement.inline_literals_using(Suppress)
            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")

            date_str.parse_string("1999/12/31")  # -> ['1999', '12', '31']
        """
        ParserElement._literalStringClass = cls

    class DebugActions(NamedTuple):
        debug_try: typing.Optional[DebugStartAction]
        debug_match: typing.Optional[DebugSuccessAction]
        debug_fail: typing.Optional[DebugExceptionAction]

    def __init__(self, savelist: bool = False):
        self.parseAction: List[ParseAction] = list()
        self.failAction: typing.Optional[ParseFailAction] = None
        self.customName = None
        self._defaultName = None
        self.resultsName = None
        self.saveAsList = savelist
        self.skipWhitespace = True
        self.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS)
        self.copyDefaultWhiteChars = True
        # used when checking for left-recursion
        self.mayReturnEmpty = False
        self.keepTabs = False
        self.ignoreExprs: List["ParserElement"] = list()
        self.debug = False
        self.streamlined = False
        # optimize exception handling for subclasses that don't advance parse index
        self.mayIndexError = True
        self.errmsg = ""
        # mark results names as modal (report only last) or cumulative (list all)
        self.modalResults = True
        # custom debug actions
        self.debugActions = self.DebugActions(None, None, None)
        # avoid redundant calls to preParse
        self.callPreparse = True
        self.callDuringTry = False
        self.suppress_warnings_: List[Diagnostics] = []

    def suppress_warning(self, warning_type: Diagnostics) -> "ParserElement":
        """
        Suppress warnings emitted for a particular diagnostic on this expression.

        Example::

            base = pp.Forward()
            base.suppress_warning(Diagnostics.warn_on_parse_using_empty_Forward)

            # statement would normally raise a warning, but is now suppressed
            print(base.parseString("x"))

        """
        self.suppress_warnings_.append(warning_type)
        return self

    def copy(self) -> "ParserElement":
        """
        Make a copy of this :class:`ParserElement`.  Useful for defining
        different parse actions for the same parsing pattern, using copies of
        the original parse element.

        Example::

            integer = Word(nums).set_parse_action(lambda toks: int(toks[0]))
            integerK = integer.copy().add_parse_action(lambda toks: toks[0] * 1024) + Suppress("K")
            integerM = integer.copy().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")

            print((integerK | integerM | integer)[1, ...].parse_string("5K 100 640K 256M"))

        prints::

            [5120, 100, 655360, 268435456]

        Equivalent form of ``expr.copy()`` is just ``expr()``::

            integerM = integer().add_parse_action(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")
        """
        cpy = copy.copy(self)
        cpy.parseAction = self.parseAction[:]
        cpy.ignoreExprs = self.ignoreExprs[:]
        if self.copyDefaultWhiteChars:
            cpy.whiteChars = set(ParserElement.DEFAULT_WHITE_CHARS)
        return cpy

    def set_results_name(
        self, name: str, list_all_matches: bool = False, *, listAllMatches: bool = False
    ) -> "ParserElement":
        """
        Define name for referencing matching tokens as a nested attribute
        of the returned parse results.

        Normally, results names are assigned as you would assign keys in a dict:
        any existing value is overwritten by later values. If it is necessary to
        keep all values captured for a particular results name, call ``set_results_name``
        with ``list_all_matches`` = True.

        NOTE: ``set_results_name`` returns a *copy* of the original :class:`ParserElement` object;
        this is so that the client can define a basic element, such as an
        integer, and reference it in multiple places with different names.

        You can also set results names using the abbreviated syntax,
        ``expr("name")`` in place of ``expr.set_results_name("name")``
        - see :class:`__call__`. If ``list_all_matches`` is required, use
        ``expr("name*")``.

        Example::

            date_str = (integer.set_results_name("year") + '/'
                        + integer.set_results_name("month") + '/'
                        + integer.set_results_name("day"))

            # equivalent form:
            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
        """
        listAllMatches = listAllMatches or list_all_matches
        return self._setResultsName(name, listAllMatches)

    def _setResultsName(self, name, listAllMatches=False):
        if name is None:
            return self
        newself = self.copy()
        if name.endswith("*"):
            name = name[:-1]
            listAllMatches = True
        newself.resultsName = name
        newself.modalResults = not listAllMatches
        return newself

    def set_break(self, break_flag: bool = True) -> "ParserElement":
        """
        Method to invoke the Python pdb debugger when this element is
        about to be parsed. Set ``break_flag`` to ``True`` to enable, ``False`` to
        disable.
        """
        if break_flag:
            _parseMethod = self._parse

            def breaker(instring, loc, doActions=True, callPreParse=True):
                import pdb

                # this call to pdb.set_trace() is intentional, not a checkin error
                pdb.set_trace()
                return _parseMethod(instring, loc, doActions, callPreParse)

            breaker._originalParseMethod = _parseMethod
            self._parse = breaker
        else:
            if hasattr(self._parse, "_originalParseMethod"):
                self._parse = self._parse._originalParseMethod
        return self

    def set_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement":
        """
        Define one or more actions to perform when successfully matching parse element definition.

        Parse actions can be called to perform data conversions, do extra validation,
        update external data structures, or enhance or replace the parsed tokens.
        Each parse action ``fn`` is a callable method with 0-3 arguments, called as
        ``fn(s, loc, toks)`` , ``fn(loc, toks)`` , ``fn(toks)`` , or just ``fn()`` , where:

        - s   = the original string being parsed (see note below)
        - loc = the location of the matching substring
        - toks = a list of the matched tokens, packaged as a :class:`ParseResults` object

        The parsed tokens are passed to the parse action as ParseResults. They can be
        modified in place using list-style append, extend, and pop operations to update
        the parsed list elements; and with dictionary-style item set and del operations
        to add, update, or remove any named results. If the tokens are modified in place,
        it is not necessary to return them with a return statement.

        Parse actions can also completely replace the given tokens, with another ``ParseResults``
        object, or with some entirely different object (common for parse actions that perform data
        conversions). A convenient way to build a new parse result is to define the values
        using a dict, and then create the return value using :class:`ParseResults.from_dict`.

        If None is passed as the ``fn`` parse action, all previously added parse actions for this
        expression are cleared.

        Optional keyword arguments:

        - call_during_try = (default= ``False``) indicate if parse action should be run during
          lookaheads and alternate testing. For parse actions that have side effects, it is
          important to only call the parse action once it is determined that it is being
          called as part of a successful parse. For parse actions that perform additional
          validation, then call_during_try should be passed as True, so that the validation
          code is included in the preliminary "try" parses.

        Note: the default parsing behavior is to expand tabs in the input string
        before starting the parsing process.  See :class:`parse_string` for more
        information on parsing strings containing ``<TAB>`` s, and suggested
        methods to maintain a consistent view of the parsed string, the parse
        location, and line and column positions within the parsed string.

        Example::

            # parse dates in the form YYYY/MM/DD

            # use parse action to convert toks from str to int at parse time
            def convert_to_int(toks):
                return int(toks[0])

            # use a parse action to verify that the date is a valid date
            def is_valid_date(instring, loc, toks):
                from datetime import date
                year, month, day = toks[::2]
                try:
                    date(year, month, day)
                except ValueError:
                    raise ParseException(instring, loc, "invalid date given")

            integer = Word(nums)
            date_str = integer + '/' + integer + '/' + integer

            # add parse actions
            integer.set_parse_action(convert_to_int)
            date_str.set_parse_action(is_valid_date)

            # note that integer fields are now ints, not strings
            date_str.run_tests('''
                # successful parse - note that integer fields were converted to ints
                1999/12/31

                # fail - invalid date
                1999/13/31
                ''')
        """
        if list(fns) == [None]:
            self.parseAction = []
        else:
            if not all(callable(fn) for fn in fns):
                raise TypeError("parse actions must be callable")
            self.parseAction = [_trim_arity(fn) for fn in fns]
            self.callDuringTry = kwargs.get(
                "call_during_try", kwargs.get("callDuringTry", False)
            )
        return self

    def add_parse_action(self, *fns: ParseAction, **kwargs) -> "ParserElement":
        """
        Add one or more parse actions to expression's list of parse actions. See :class:`set_parse_action`.

        See examples in :class:`copy`.
        """
        self.parseAction += [_trim_arity(fn) for fn in fns]
        self.callDuringTry = self.callDuringTry or kwargs.get(
            "call_during_try", kwargs.get("callDuringTry", False)
        )
        return self

    def add_condition(self, *fns: ParseCondition, **kwargs) -> "ParserElement":
        """Add a boolean predicate function to expression's list of parse actions. See
        :class:`set_parse_action` for function call signatures. Unlike ``set_parse_action``,
        functions passed to ``add_condition`` need to return boolean success/fail of the condition.

        Optional keyword arguments:

        - message = define a custom message to be used in the raised exception
        - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise
          ParseException
        - call_during_try = boolean to indicate if this method should be called during internal tryParse calls,
          default=False

        Example::

            integer = Word(nums).set_parse_action(lambda toks: int(toks[0]))
            year_int = integer.copy()
            year_int.add_condition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later")
            date_str = year_int + '/' + integer + '/' + integer

            result = date_str.parse_string("1999/12/31")  # -> Exception: Only support years 2000 and later (at char 0),
                                                                         (line:1, col:1)
        """
        for fn in fns:
            self.parseAction.append(
                condition_as_parse_action(
                    fn, message=kwargs.get("message"), fatal=kwargs.get("fatal", False)
                )
            )

        self.callDuringTry = self.callDuringTry or kwargs.get(
            "call_during_try", kwargs.get("callDuringTry", False)
        )
        return self

    def set_fail_action(self, fn: ParseFailAction) -> "ParserElement":
        """
        Define action to perform if parsing fails at this expression.
        Fail acton fn is a callable function that takes the arguments
        ``fn(s, loc, expr, err)`` where:

        - s = string being parsed
        - loc = location where expression match was attempted and failed
        - expr = the parse expression that failed
        - err = the exception thrown

        The function returns no value.  It may throw :class:`ParseFatalException`
        if it is desired to stop parsing immediately."""
        self.failAction = fn
        return self

    def _skipIgnorables(self, instring, loc):
        exprsFound = True
        while exprsFound:
            exprsFound = False
            for e in self.ignoreExprs:
                try:
                    while 1:
                        loc, dummy = e._parse(instring, loc)
                        exprsFound = True
                except ParseException:
                    pass
        return loc

    def preParse(self, instring, loc):
        if self.ignoreExprs:
            loc = self._skipIgnorables(instring, loc)

        if self.skipWhitespace:
            instrlen = len(instring)
            white_chars = self.whiteChars
            while loc < instrlen and instring[loc] in white_chars:
                loc += 1

        return loc

    def parseImpl(self, instring, loc, doActions=True):
        return loc, []

    def postParse(self, instring, loc, tokenlist):
        return tokenlist

    # @profile
    def _parseNoCache(
        self, instring, loc, doActions=True, callPreParse=True
    ) -> Tuple[int, ParseResults]:
        TRY, MATCH, FAIL = 0, 1, 2
        debugging = self.debug  # and doActions)
        len_instring = len(instring)

        if debugging or self.failAction:
            # print("Match {} at loc {}({}, {})".format(self, loc, lineno(loc, instring), col(loc, instring)))
            try:
                if callPreParse and self.callPreparse:
                    pre_loc = self.preParse(instring, loc)
                else:
                    pre_loc = loc
                tokens_start = pre_loc
                if self.debugActions.debug_try:
                    self.debugActions.debug_try(instring, tokens_start, self, False)
                if self.mayIndexError or pre_loc >= len_instring:
                    try:
                        loc, tokens = self.parseImpl(instring, pre_loc, doActions)
                    except IndexError:
                        raise ParseException(instring, len_instring, self.errmsg, self)
                else:
                    loc, tokens = self.parseImpl(instring, pre_loc, doActions)
            except Exception as err:
                # print("Exception raised:", err)
                if self.debugActions.debug_fail:
                    self.debugActions.debug_fail(
                        instring, tokens_start, self, err, False
                    )
                if self.failAction:
                    self.failAction(instring, tokens_start, self, err)
                raise
        else:
            if callPreParse and self.callPreparse:
                pre_loc = self.preParse(instring, loc)
            else:
                pre_loc = loc
            tokens_start = pre_loc
            if self.mayIndexError or pre_loc >= len_instring:
                try:
                    loc, tokens = self.parseImpl(instring, pre_loc, doActions)
                except IndexError:
                    raise ParseException(instring, len_instring, self.errmsg, self)
            else:
                loc, tokens = self.parseImpl(instring, pre_loc, doActions)

        tokens = self.postParse(instring, loc, tokens)

        ret_tokens = ParseResults(
            tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults
        )
        if self.parseAction and (doActions or self.callDuringTry):
            if debugging:
                try:
                    for fn in self.parseAction:
                        try:
                            tokens = fn(instring, tokens_start, ret_tokens)
                        except IndexError as parse_action_exc:
                            exc = ParseException("exception raised in parse action")
                            raise exc from parse_action_exc

                        if tokens is not None and tokens is not ret_tokens:
                            ret_tokens = ParseResults(
                                tokens,
                                self.resultsName,
                                asList=self.saveAsList
                                and isinstance(tokens, (ParseResults, list)),
                                modal=self.modalResults,
                            )
                except Exception as err:
                    # print "Exception raised in user parse action:", err
                    if self.debugActions.debug_fail:
                        self.debugActions.debug_fail(
                            instring, tokens_start, self, err, False
                        )
                    raise
            else:
                for fn in self.parseAction:
                    try:
                        tokens = fn(instring, tokens_start, ret_tokens)
                    except IndexError as parse_action_exc:
                        exc = ParseException("exception raised in parse action")
                        raise exc from parse_action_exc

                    if tokens is not None and tokens is not ret_tokens:
                        ret_tokens = ParseResults(
                            tokens,
                            self.resultsName,
                            asList=self.saveAsList
                            and isinstance(tokens, (ParseResults, list)),
                            modal=self.modalResults,
                        )
        if debugging:
            # print("Matched", self, "->", ret_tokens.as_list())
            if self.debugActions.debug_match:
                self.debugActions.debug_match(
                    instring, tokens_start, loc, self, ret_tokens, False
                )

        return loc, ret_tokens

    def try_parse(self, instring: str, loc: int, raise_fatal: bool = False) -> int:
        try:
            return self._parse(instring, loc, doActions=False)[0]
        except ParseFatalException:
            if raise_fatal:
                raise
            raise ParseException(instring, loc, self.errmsg, self)

    def can_parse_next(self, instring: str, loc: int) -> bool:
        try:
            self.try_parse(instring, loc)
        except (ParseException, IndexError):
            return False
        else:
            return True

    # cache for left-recursion in Forward references
    recursion_lock = RLock()
    recursion_memos: typing.Dict[
        Tuple[int, "Forward", bool], Tuple[int, Union[ParseResults, Exception]]
    ] = {}

    # argument cache for optimizing repeated calls when backtracking through recursive expressions
    packrat_cache = (
        {}
    )  # this is set later by enabled_packrat(); this is here so that reset_cache() doesn't fail
    packrat_cache_lock = RLock()
    packrat_cache_stats = [0, 0]

    # this method gets repeatedly called during backtracking with the same arguments -
    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
    def _parseCache(
        self, instring, loc, doActions=True, callPreParse=True
    ) -> Tuple[int, ParseResults]:
        HIT, MISS = 0, 1
        TRY, MATCH, FAIL = 0, 1, 2
        lookup = (self, instring, loc, callPreParse, doActions)
        with ParserElement.packrat_cache_lock:
            cache = ParserElement.packrat_cache
            value = cache.get(lookup)
            if value is cache.not_in_cache:
                ParserElement.packrat_cache_stats[MISS] += 1
                try:
                    value = self._parseNoCache(instring, loc, doActions, callPreParse)
                except ParseBaseException as pe:
                    # cache a copy of the exception, without the traceback
                    cache.set(lookup, pe.__class__(*pe.args))
                    raise
                else:
                    cache.set(lookup, (value[0], value[1].copy(), loc))
                    return value
            else:
                ParserElement.packrat_cache_stats[HIT] += 1
                if self.debug and self.debugActions.debug_try:
                    try:
                        self.debugActions.debug_try(instring, loc, self, cache_hit=True)
                    except TypeError:
                        pass
                if isinstance(value, Exception):
                    if self.debug and self.debugActions.debug_fail:
                        try:
                            self.debugActions.debug_fail(
                                instring, loc, self, value, cache_hit=True
                            )
                        except TypeError:
                            pass
                    raise value

                loc_, result, endloc = value[0], value[1].copy(), value[2]
                if self.debug and self.debugActions.debug_match:
                    try:
                        self.debugActions.debug_match(
                            instring, loc_, endloc, self, result, cache_hit=True
                        )
                    except TypeError:
                        pass

                return loc_, result

    _parse = _parseNoCache

    @staticmethod
    def reset_cache() -> None:
        ParserElement.packrat_cache.clear()
        ParserElement.packrat_cache_stats[:] = [0] * len(
            ParserElement.packrat_cache_stats
        )
        ParserElement.recursion_memos.clear()

    _packratEnabled = False
    _left_recursion_enabled = False

    @staticmethod
    def disable_memoization() -> None:
        """
        Disables active Packrat or Left Recursion parsing and their memoization

        This method also works if neither Packrat nor Left Recursion are enabled.
        This makes it safe to call before activating Packrat nor Left Recursion
        to clear any previous settings.
        """
        ParserElement.reset_cache()
        ParserElement._left_recursion_enabled = False
        ParserElement._packratEnabled = False
        ParserElement._parse = ParserElement._parseNoCache

    @staticmethod
    def enable_left_recursion(
        cache_size_limit: typing.Optional[int] = None, *, force=False
    ) -> None:
        """
        Enables "bounded recursion" parsing, which allows for both direct and indirect
        left-recursion. During parsing, left-recursive :class:`Forward` elements are
        repeatedly matched with a fixed recursion depth that is gradually increased
        until finding the longest match.

        Example::

            import pyparsing as pp
            pp.ParserElement.enable_left_recursion()

            E = pp.Forward("E")
            num = pp.Word(pp.nums)
            # match `num`, or `num '+' num`, or `num '+' num '+' num`, ...
            E <<= E + '+' - num | num

            print(E.parse_string("1+2+3"))

        Recursion search naturally memoizes matches of ``Forward`` elements and may
        thus skip reevaluation of parse actions during backtracking. This may break
        programs with parse actions which rely on strict ordering of side-effects.

        Parameters:

        - cache_size_limit - (default=``None``) - memoize at most this many
          ``Forward`` elements during matching; if ``None`` (the default),
          memoize all ``Forward`` elements.

        Bounded Recursion parsing works similar but not identical to Packrat parsing,
        thus the two cannot be used together. Use ``force=True`` to disable any
        previous, conflicting settings.
        """
        if force:
            ParserElement.disable_memoization()
        elif ParserElement._packratEnabled:
            raise RuntimeError("Packrat and Bounded Recursion are not compatible")
        if cache_size_limit is None:
            ParserElement.recursion_memos = _UnboundedMemo()
        elif cache_size_limit > 0:
            ParserElement.recursion_memos = _LRUMemo(capacity=cache_size_limit)
        else:
            raise NotImplementedError("Memo size of %s" % cache_size_limit)
        ParserElement._left_recursion_enabled = True

    @staticmethod
    def enable_packrat(cache_size_limit: int = 128, *, force: bool = False) -> None:
        """
        Enables "packrat" parsing, which adds memoizing to the parsing logic.
        Repeated parse attempts at the same string location (which happens
        often in many complex grammars) can immediately return a cached value,
        instead of re-executing parsing/validating code.  Memoizing is done of
        both valid results and parsing exceptions.

        Parameters:

        - cache_size_limit - (default= ``128``) - if an integer value is provided
          will limit the size of the packrat cache; if None is passed, then
          the cache size will be unbounded; if 0 is passed, the cache will
          be effectively disabled.

        This speedup may break existing programs that use parse actions that
        have side-effects.  For this reason, packrat parsing is disabled when
        you first import pyparsing.  To activate the packrat feature, your
        program must call the class method :class:`ParserElement.enable_packrat`.
        For best results, call ``enable_packrat()`` immediately after
        importing pyparsing.

        Example::

            import pyparsing
            pyparsing.ParserElement.enable_packrat()

        Packrat parsing works similar but not identical to Bounded Recursion parsing,
        thus the two cannot be used together. Use ``force=True`` to disable any
        previous, conflicting settings.
        """
        if force:
            ParserElement.disable_memoization()
        elif ParserElement._left_recursion_enabled:
            raise RuntimeError("Packrat and Bounded Recursion are not compatible")
        if not ParserElement._packratEnabled:
            ParserElement._packratEnabled = True
            if cache_size_limit is None:
                ParserElement.packrat_cache = _UnboundedCache()
            else:
                ParserElement.packrat_cache = _FifoCache(cache_size_limit)
            ParserElement._parse = ParserElement._parseCache

    def parse_string(
        self, instring: str, parse_all: bool = False, *, parseAll: bool = False
    ) -> ParseResults:
        """
        Parse a string with respect to the parser definition. This function is intended as the primary interface to the
        client code.

        :param instring: The input string to be parsed.
        :param parse_all: If set, the entire input string must match the grammar.
        :param parseAll: retained for pre-PEP8 compatibility, will be removed in a future release.
        :raises ParseException: Raised if ``parse_all`` is set and the input string does not match the whole grammar.
        :returns: the parsed data as a :class:`ParseResults` object, which may be accessed as a `list`, a `dict`, or
          an object with attributes if the given parser includes results names.

        If the input string is required to match the entire grammar, ``parse_all`` flag must be set to ``True``. This
        is also equivalent to ending the grammar with :class:`StringEnd`().

        To report proper column numbers, ``parse_string`` operates on a copy of the input string where all tabs are
        converted to spaces (8 spaces per tab, as per the default in ``string.expandtabs``). If the input string
        contains tabs and the grammar uses parse actions that use the ``loc`` argument to index into the string
        being parsed, one can ensure a consistent view of the input string by doing one of the following:

        - calling ``parse_with_tabs`` on your grammar before calling ``parse_string`` (see :class:`parse_with_tabs`),
        - define your parse action using the full ``(s,loc,toks)`` signature, and reference the input string using the
          parse action's ``s`` argument, or
        - explicitly expand the tabs in your input string before calling ``parse_string``.

        Examples:

        By default, partial matches are OK.

        >>> res = Word('a').parse_string('aaaaabaaa')
        >>> print(res)
        ['aaaaa']

        The parsing behavior varies by the inheriting class of this abstract class. Please refer to the children
        directly to see more examples.

        It raises an exception if parse_all flag is set and instring does not match the whole grammar.

        >>> res = Word('a').parse_string('aaaaabaaa', parse_all=True)
        Traceback (most recent call last):
        ...
        pyparsing.ParseException: Expected end of text, found 'b'  (at char 5), (line:1, col:6)
        """
        parseAll = parse_all or parseAll

        ParserElement.reset_cache()
        if not self.streamlined:
            self.streamline()
        for e in self.ignoreExprs:
            e.streamline()
        if not self.keepTabs:
            instring = instring.expandtabs()
        try:
            loc, tokens = self._parse(instring, 0)
            if parseAll:
                loc = self.preParse(instring, loc)
                se = Empty() + StringEnd()
                se._parse(instring, loc)
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clearing out pyparsing internal stack trace
                raise exc.with_traceback(None)
        else:
            return tokens

    def scan_string(
        self,
        instring: str,
        max_matches: int = _MAX_INT,
        overlap: bool = False,
        *,
        debug: bool = False,
        maxMatches: int = _MAX_INT,
    ) -> Generator[Tuple[ParseResults, int, int], None, None]:
        """
        Scan the input string for expression matches.  Each match will return the
        matching tokens, start location, and end location.  May be called with optional
        ``max_matches`` argument, to clip scanning after 'n' matches are found.  If
        ``overlap`` is specified, then overlapping matches will be reported.

        Note that the start and end locations are reported relative to the string
        being parsed.  See :class:`parse_string` for more information on parsing
        strings with embedded tabs.

        Example::

            source = "sldjf123lsdjjkf345sldkjf879lkjsfd987"
            print(source)
            for tokens, start, end in Word(alphas).scan_string(source):
                print(' '*start + '^'*(end-start))
                print(' '*start + tokens[0])

        prints::

            sldjf123lsdjjkf345sldkjf879lkjsfd987
            ^^^^^
            sldjf
                    ^^^^^^^
                    lsdjjkf
                              ^^^^^^
                              sldkjf
                                       ^^^^^^
                                       lkjsfd
        """
        maxMatches = min(maxMatches, max_matches)
        if not self.streamlined:
            self.streamline()
        for e in self.ignoreExprs:
            e.streamline()

        if not self.keepTabs:
            instring = str(instring).expandtabs()
        instrlen = len(instring)
        loc = 0
        preparseFn = self.preParse
        parseFn = self._parse
        ParserElement.resetCache()
        matches = 0
        try:
            while loc <= instrlen and matches < maxMatches:
                try:
                    preloc = preparseFn(instring, loc)
                    nextLoc, tokens = parseFn(instring, preloc, callPreParse=False)
                except ParseException:
                    loc = preloc + 1
                else:
                    if nextLoc > loc:
                        matches += 1
                        if debug:
                            print(
                                {
                                    "tokens": tokens.asList(),
                                    "start": preloc,
                                    "end": nextLoc,
                                }
                            )
                        yield tokens, preloc, nextLoc
                        if overlap:
                            nextloc = preparseFn(instring, loc)
                            if nextloc > loc:
                                loc = nextLoc
                            else:
                                loc += 1
                        else:
                            loc = nextLoc
                    else:
                        loc = preloc + 1
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def transform_string(self, instring: str, *, debug: bool = False) -> str:
        """
        Extension to :class:`scan_string`, to modify matching text with modified tokens that may
        be returned from a parse action.  To use ``transform_string``, define a grammar and
        attach a parse action to it that modifies the returned token list.
        Invoking ``transform_string()`` on a target string will then scan for matches,
        and replace the matched text patterns according to the logic in the parse
        action.  ``transform_string()`` returns the resulting transformed string.

        Example::

            wd = Word(alphas)
            wd.set_parse_action(lambda toks: toks[0].title())

            print(wd.transform_string("now is the winter of our discontent made glorious summer by this sun of york."))

        prints::

            Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York.
        """
        out: List[str] = []
        lastE = 0
        # force preservation of <TAB>s, to minimize unwanted transformation of string, and to
        # keep string locs straight between transform_string and scan_string
        self.keepTabs = True
        try:
            for t, s, e in self.scan_string(instring, debug=debug):
                out.append(instring[lastE:s])
                if t:
                    if isinstance(t, ParseResults):
                        out += t.as_list()
                    elif isinstance(t, Iterable) and not isinstance(t, str_type):
                        out.extend(t)
                    else:
                        out.append(t)
                lastE = e
            out.append(instring[lastE:])
            out = [o for o in out if o]
            return "".join([str(s) for s in _flatten(out)])
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def search_string(
        self,
        instring: str,
        max_matches: int = _MAX_INT,
        *,
        debug: bool = False,
        maxMatches: int = _MAX_INT,
    ) -> ParseResults:
        """
        Another extension to :class:`scan_string`, simplifying the access to the tokens found
        to match the given parse expression.  May be called with optional
        ``max_matches`` argument, to clip searching after 'n' matches are found.

        Example::

            # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters
            cap_word = Word(alphas.upper(), alphas.lower())

            print(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity"))

            # the sum() builtin can be used to merge results into a single ParseResults object
            print(sum(cap_word.search_string("More than Iron, more than Lead, more than Gold I need Electricity")))

        prints::

            [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']]
            ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
        """
        maxMatches = min(maxMatches, max_matches)
        try:
            return ParseResults(
                [t for t, s, e in self.scan_string(instring, maxMatches, debug=debug)]
            )
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def split(
        self,
        instring: str,
        maxsplit: int = _MAX_INT,
        include_separators: bool = False,
        *,
        includeSeparators=False,
    ) -> Generator[str, None, None]:
        """
        Generator method to split a string using the given expression as a separator.
        May be called with optional ``maxsplit`` argument, to limit the number of splits;
        and the optional ``include_separators`` argument (default= ``False``), if the separating
        matching text should be included in the split results.

        Example::

            punc = one_of(list(".,;:/-!?"))
            print(list(punc.split("This, this?, this sentence, is badly punctuated!")))

        prints::

            ['This', ' this', '', ' this sentence', ' is badly punctuated', '']
        """
        includeSeparators = includeSeparators or include_separators
        last = 0
        for t, s, e in self.scan_string(instring, max_matches=maxsplit):
            yield instring[last:s]
            if includeSeparators:
                yield t[0]
            last = e
        yield instring[last:]

    def __add__(self, other) -> "ParserElement":
        """
        Implementation of ``+`` operator - returns :class:`And`. Adding strings to a :class:`ParserElement`
        converts them to :class:`Literal`s by default.

        Example::

            greet = Word(alphas) + "," + Word(alphas) + "!"
            hello = "Hello, World!"
            print(hello, "->", greet.parse_string(hello))

        prints::

            Hello, World! -> ['Hello', ',', 'World', '!']

        ``...`` may be used as a parse expression as a short form of :class:`SkipTo`.

            Literal('start') + ... + Literal('end')

        is equivalent to:

            Literal('start') + SkipTo('end')("_skipped*") + Literal('end')

        Note that the skipped text is returned with '_skipped' as a results name,
        and to support having multiple skips in the same parser, the value returned is
        a list of all skipped text.
        """
        if other is Ellipsis:
            return _PendingSkip(self)

        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return And([self, other])

    def __radd__(self, other) -> "ParserElement":
        """
        Implementation of ``+`` operator when left operand is not a :class:`ParserElement`
        """
        if other is Ellipsis:
            return SkipTo(self)("_skipped*") + self

        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other + self

    def __sub__(self, other) -> "ParserElement":
        """
        Implementation of ``-`` operator, returns :class:`And` with error stop
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return self + And._ErrorStop() + other

    def __rsub__(self, other) -> "ParserElement":
        """
        Implementation of ``-`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other - self

    def __mul__(self, other) -> "ParserElement":
        """
        Implementation of ``*`` operator, allows use of ``expr * 3`` in place of
        ``expr + expr + expr``.  Expressions may also be multiplied by a 2-integer
        tuple, similar to ``{min, max}`` multipliers in regular expressions.  Tuples
        may also include ``None`` as in:
        - ``expr*(n, None)`` or ``expr*(n, )`` is equivalent
             to ``expr*n + ZeroOrMore(expr)``
             (read as "at least n instances of ``expr``")
        - ``expr*(None, n)`` is equivalent to ``expr*(0, n)``
             (read as "0 to n instances of ``expr``")
        - ``expr*(None, None)`` is equivalent to ``ZeroOrMore(expr)``
        - ``expr*(1, None)`` is equivalent to ``OneOrMore(expr)``

        Note that ``expr*(None, n)`` does not raise an exception if
        more than n exprs exist in the input stream; that is,
        ``expr*(None, n)`` does not enforce a maximum number of expr
        occurrences.  If this behavior is desired, then write
        ``expr*(None, n) + ~expr``
        """
        if other is Ellipsis:
            other = (0, None)
        elif isinstance(other, tuple) and other[:1] == (Ellipsis,):
            other = ((0,) + other[1:] + (None,))[:2]

        if isinstance(other, int):
            minElements, optElements = other, 0
        elif isinstance(other, tuple):
            other = tuple(o if o is not Ellipsis else None for o in other)
            other = (other + (None, None))[:2]
            if other[0] is None:
                other = (0, other[1])
            if isinstance(other[0], int) and other[1] is None:
                if other[0] == 0:
                    return ZeroOrMore(self)
                if other[0] == 1:
                    return OneOrMore(self)
                else:
                    return self * other[0] + ZeroOrMore(self)
            elif isinstance(other[0], int) and isinstance(other[1], int):
                minElements, optElements = other
                optElements -= minElements
            else:
                raise TypeError(
                    "cannot multiply ParserElement and ({}) objects".format(
                        ",".join(type(item).__name__ for item in other)
                    )
                )
        else:
            raise TypeError(
                "cannot multiply ParserElement and {} objects".format(
                    type(other).__name__
                )
            )

        if minElements < 0:
            raise ValueError("cannot multiply ParserElement by negative value")
        if optElements < 0:
            raise ValueError(
                "second tuple value must be greater or equal to first tuple value"
            )
        if minElements == optElements == 0:
            return And([])

        if optElements:

            def makeOptionalList(n):
                if n > 1:
                    return Opt(self + makeOptionalList(n - 1))
                else:
                    return Opt(self)

            if minElements:
                if minElements == 1:
                    ret = self + makeOptionalList(optElements)
                else:
                    ret = And([self] * minElements) + makeOptionalList(optElements)
            else:
                ret = makeOptionalList(optElements)
        else:
            if minElements == 1:
                ret = self
            else:
                ret = And([self] * minElements)
        return ret

    def __rmul__(self, other) -> "ParserElement":
        return self.__mul__(other)

    def __or__(self, other) -> "ParserElement":
        """
        Implementation of ``|`` operator - returns :class:`MatchFirst`
        """
        if other is Ellipsis:
            return _PendingSkip(self, must_skip=True)

        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return MatchFirst([self, other])

    def __ror__(self, other) -> "ParserElement":
        """
        Implementation of ``|`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other | self

    def __xor__(self, other) -> "ParserElement":
        """
        Implementation of ``^`` operator - returns :class:`Or`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return Or([self, other])

    def __rxor__(self, other) -> "ParserElement":
        """
        Implementation of ``^`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other ^ self

    def __and__(self, other) -> "ParserElement":
        """
        Implementation of ``&`` operator - returns :class:`Each`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return Each([self, other])

    def __rand__(self, other) -> "ParserElement":
        """
        Implementation of ``&`` operator when left operand is not a :class:`ParserElement`
        """
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        if not isinstance(other, ParserElement):
            raise TypeError(
                "Cannot combine element of type {} with ParserElement".format(
                    type(other).__name__
                )
            )
        return other & self

    def __invert__(self) -> "ParserElement":
        """
        Implementation of ``~`` operator - returns :class:`NotAny`
        """
        return NotAny(self)

    # disable __iter__ to override legacy use of sequential access to __getitem__ to
    # iterate over a sequence
    __iter__ = None

    def __getitem__(self, key):
        """
        use ``[]`` indexing notation as a short form for expression repetition:

        - ``expr[n]`` is equivalent to ``expr*n``
        - ``expr[m, n]`` is equivalent to ``expr*(m, n)``
        - ``expr[n, ...]`` or ``expr[n,]`` is equivalent
             to ``expr*n + ZeroOrMore(expr)``
             (read as "at least n instances of ``expr``")
        - ``expr[..., n]`` is equivalent to ``expr*(0, n)``
             (read as "0 to n instances of ``expr``")
        - ``expr[...]`` and ``expr[0, ...]`` are equivalent to ``ZeroOrMore(expr)``
        - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)``

        ``None`` may be used in place of ``...``.

        Note that ``expr[..., n]`` and ``expr[m, n]``do not raise an exception
        if more than ``n`` ``expr``s exist in the input stream.  If this behavior is
        desired, then write ``expr[..., n] + ~expr``.
        """

        # convert single arg keys to tuples
        try:
            if isinstance(key, str_type):
                key = (key,)
            iter(key)
        except TypeError:
            key = (key, key)

        if len(key) > 2:
            raise TypeError(
                "only 1 or 2 index arguments supported ({}{})".format(
                    key[:5], "... [{}]".format(len(key)) if len(key) > 5 else ""
                )
            )

        # clip to 2 elements
        ret = self * tuple(key[:2])
        return ret

    def __call__(self, name: str = None) -> "ParserElement":
        """
        Shortcut for :class:`set_results_name`, with ``list_all_matches=False``.

        If ``name`` is given with a trailing ``'*'`` character, then ``list_all_matches`` will be
        passed as ``True``.

        If ``name` is omitted, same as calling :class:`copy`.

        Example::

            # these are equivalent
            userdata = Word(alphas).set_results_name("name") + Word(nums + "-").set_results_name("socsecno")
            userdata = Word(alphas)("name") + Word(nums + "-")("socsecno")
        """
        if name is not None:
            return self._setResultsName(name)
        else:
            return self.copy()

    def suppress(self) -> "ParserElement":
        """
        Suppresses the output of this :class:`ParserElement`; useful to keep punctuation from
        cluttering up returned output.
        """
        return Suppress(self)

    def ignore_whitespace(self, recursive: bool = True) -> "ParserElement":
        """
        Enables the skipping of whitespace before matching the characters in the
        :class:`ParserElement`'s defined pattern.

        :param recursive: If ``True`` (the default), also enable whitespace skipping in child elements (if any)
        """
        self.skipWhitespace = True
        return self

    def leave_whitespace(self, recursive: bool = True) -> "ParserElement":
        """
        Disables the skipping of whitespace before matching the characters in the
        :class:`ParserElement`'s defined pattern.  This is normally only used internally by
        the pyparsing module, but may be needed in some whitespace-sensitive grammars.

        :param recursive: If true (the default), also disable whitespace skipping in child elements (if any)
        """
        self.skipWhitespace = False
        return self

    def set_whitespace_chars(
        self, chars: Union[Set[str], str], copy_defaults: bool = False
    ) -> "ParserElement":
        """
        Overrides the default whitespace chars
        """
        self.skipWhitespace = True
        self.whiteChars = set(chars)
        self.copyDefaultWhiteChars = copy_defaults
        return self

    def parse_with_tabs(self) -> "ParserElement":
        """
        Overrides default behavior to expand ``<TAB>`` s to spaces before parsing the input string.
        Must be called before ``parse_string`` when the input grammar contains elements that
        match ``<TAB>`` characters.
        """
        self.keepTabs = True
        return self

    def ignore(self, other: "ParserElement") -> "ParserElement":
        """
        Define expression to be ignored (e.g., comments) while doing pattern
        matching; may be called repeatedly, to define multiple comment or other
        ignorable patterns.

        Example::

            patt = Word(alphas)[1, ...]
            patt.parse_string('ablaj /* comment */ lskjd')
            # -> ['ablaj']

            patt.ignore(c_style_comment)
            patt.parse_string('ablaj /* comment */ lskjd')
            # -> ['ablaj', 'lskjd']
        """
        import typing

        if isinstance(other, str_type):
            other = Suppress(other)

        if isinstance(other, Suppress):
            if other not in self.ignoreExprs:
                self.ignoreExprs.append(other)
        else:
            self.ignoreExprs.append(Suppress(other.copy()))
        return self

    def set_debug_actions(
        self,
        start_action: DebugStartAction,
        success_action: DebugSuccessAction,
        exception_action: DebugExceptionAction,
    ) -> "ParserElement":
        """
        Customize display of debugging messages while doing pattern matching:

        - ``start_action`` - method to be called when an expression is about to be parsed;
          should have the signature ``fn(input_string: str, location: int, expression: ParserElement, cache_hit: bool)``

        - ``success_action`` - method to be called when an expression has successfully parsed;
          should have the signature ``fn(input_string: str, start_location: int, end_location: int, expression: ParserELement, parsed_tokens: ParseResults, cache_hit: bool)``

        - ``exception_action`` - method to be called when expression fails to parse;
          should have the signature ``fn(input_string: str, location: int, expression: ParserElement, exception: Exception, cache_hit: bool)``
        """
        self.debugActions = self.DebugActions(
            start_action or _default_start_debug_action,
            success_action or _default_success_debug_action,
            exception_action or _default_exception_debug_action,
        )
        self.debug = True
        return self

    def set_debug(self, flag: bool = True) -> "ParserElement":
        """
        Enable display of debugging messages while doing pattern matching.
        Set ``flag`` to ``True`` to enable, ``False`` to disable.

        Example::

            wd = Word(alphas).set_name("alphaword")
            integer = Word(nums).set_name("numword")
            term = wd | integer

            # turn on debugging for wd
            wd.set_debug()

            term[1, ...].parse_string("abc 123 xyz 890")

        prints::

            Match alphaword at loc 0(1,1)
            Matched alphaword -> ['abc']
            Match alphaword at loc 3(1,4)
            Exception raised:Expected alphaword (at char 4), (line:1, col:5)
            Match alphaword at loc 7(1,8)
            Matched alphaword -> ['xyz']
            Match alphaword at loc 11(1,12)
            Exception raised:Expected alphaword (at char 12), (line:1, col:13)
            Match alphaword at loc 15(1,16)
            Exception raised:Expected alphaword (at char 15), (line:1, col:16)

        The output shown is that produced by the default debug actions - custom debug actions can be
        specified using :class:`set_debug_actions`. Prior to attempting
        to match the ``wd`` expression, the debugging message ``"Match <exprname> at loc <n>(<line>,<col>)"``
        is shown. Then if the parse succeeds, a ``"Matched"`` message is shown, or an ``"Exception raised"``
        message is shown. Also note the use of :class:`set_name` to assign a human-readable name to the expression,
        which makes debugging and exception messages easier to understand - for instance, the default
        name created for the :class:`Word` expression without calling ``set_name`` is ``"W:(A-Za-z)"``.
        """
        if flag:
            self.set_debug_actions(
                _default_start_debug_action,
                _default_success_debug_action,
                _default_exception_debug_action,
            )
        else:
            self.debug = False
        return self

    @property
    def default_name(self) -> str:
        if self._defaultName is None:
            self._defaultName = self._generateDefaultName()
        return self._defaultName

    @abstractmethod
    def _generateDefaultName(self):
        """
        Child classes must define this method, which defines how the ``default_name`` is set.
        """

    def set_name(self, name: str) -> "ParserElement":
        """
        Define name for this expression, makes debugging and exception messages clearer.
        Example::
            Word(nums).parse_string("ABC")  # -> Exception: Expected W:(0-9) (at char 0), (line:1, col:1)
            Word(nums).set_name("integer").parse_string("ABC")  # -> Exception: Expected integer (at char 0), (line:1, col:1)
        """
        self.customName = name
        self.errmsg = "Expected " + self.name
        if __diag__.enable_debug_on_named_expressions:
            self.set_debug()
        return self

    @property
    def name(self) -> str:
        # This will use a user-defined name if available, but otherwise defaults back to the auto-generated name
        return self.customName if self.customName is not None else self.default_name

    def __str__(self) -> str:
        return self.name

    def __repr__(self) -> str:
        return str(self)

    def streamline(self) -> "ParserElement":
        self.streamlined = True
        self._defaultName = None
        return self

    def recurse(self) -> Sequence["ParserElement"]:
        return []

    def _checkRecursion(self, parseElementList):
        subRecCheckList = parseElementList[:] + [self]
        for e in self.recurse():
            e._checkRecursion(subRecCheckList)

    def validate(self, validateTrace=None) -> None:
        """
        Check defined expressions for valid structure, check for infinite recursive definitions.
        """
        self._checkRecursion([])

    def parse_file(
        self,
        file_or_filename: Union[str, Path, TextIO],
        encoding: str = "utf-8",
        parse_all: bool = False,
        *,
        parseAll: bool = False,
    ) -> ParseResults:
        """
        Execute the parse expression on the given file or filename.
        If a filename is specified (instead of a file object),
        the entire file is opened, read, and closed before parsing.
        """
        parseAll = parseAll or parse_all
        try:
            file_contents = file_or_filename.read()
        except AttributeError:
            with open(file_or_filename, "r", encoding=encoding) as f:
                file_contents = f.read()
        try:
            return self.parse_string(file_contents, parseAll)
        except ParseBaseException as exc:
            if ParserElement.verbose_stacktrace:
                raise
            else:
                # catch and re-raise exception from here, clears out pyparsing internal stack trace
                raise exc.with_traceback(None)

    def __eq__(self, other):
        if self is other:
            return True
        elif isinstance(other, str_type):
            return self.matches(other, parse_all=True)
        elif isinstance(other, ParserElement):
            return vars(self) == vars(other)
        return False

    def __hash__(self):
        return id(self)

    def matches(
        self, test_string: str, parse_all: bool = True, *, parseAll: bool = True
    ) -> bool:
        """
        Method for quick testing of a parser against a test string. Good for simple
        inline microtests of sub expressions while building up larger parser.

        Parameters:
        - ``test_string`` - to test against this expression for a match
        - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests

        Example::

            expr = Word(nums)
            assert expr.matches("100")
        """
        parseAll = parseAll and parse_all
        try:
            self.parse_string(str(test_string), parse_all=parseAll)
            return True
        except ParseBaseException:
            return False

    def run_tests(
        self,
        tests: Union[str, List[str]],
        parse_all: bool = True,
        comment: typing.Optional[Union["ParserElement", str]] = "#",
        full_dump: bool = True,
        print_results: bool = True,
        failure_tests: bool = False,
        post_parse: Callable[[str, ParseResults], str] = None,
        file: typing.Optional[TextIO] = None,
        with_line_numbers: bool = False,
        *,
        parseAll: bool = True,
        fullDump: bool = True,
        printResults: bool = True,
        failureTests: bool = False,
        postParse: Callable[[str, ParseResults], str] = None,
    ) -> Tuple[bool, List[Tuple[str, Union[ParseResults, Exception]]]]:
        """
        Execute the parse expression on a series of test strings, showing each
        test, the parsed results or where the parse failed. Quick and easy way to
        run a parse expression against a list of sample strings.

        Parameters:
        - ``tests`` - a list of separate test strings, or a multiline string of test strings
        - ``parse_all`` - (default= ``True``) - flag to pass to :class:`parse_string` when running tests
        - ``comment`` - (default= ``'#'``) - expression for indicating embedded comments in the test
          string; pass None to disable comment filtering
        - ``full_dump`` - (default= ``True``) - dump results as list followed by results names in nested outline;
          if False, only dump nested list
        - ``print_results`` - (default= ``True``) prints test output to stdout
        - ``failure_tests`` - (default= ``False``) indicates if these tests are expected to fail parsing
        - ``post_parse`` - (default= ``None``) optional callback for successful parse results; called as
          `fn(test_string, parse_results)` and returns a string to be added to the test output
        - ``file`` - (default= ``None``) optional file-like object to which test output will be written;
          if None, will default to ``sys.stdout``
        - ``with_line_numbers`` - default= ``False``) show test strings with line and column numbers

        Returns: a (success, results) tuple, where success indicates that all tests succeeded
        (or failed if ``failure_tests`` is True), and the results contain a list of lines of each
        test's output

        Example::

            number_expr = pyparsing_common.number.copy()

            result = number_expr.run_tests('''
                # unsigned integer
                100
                # negative integer
                -100
                # float with scientific notation
                6.02e23
                # integer with scientific notation
                1e-12
                ''')
            print("Success" if result[0] else "Failed!")

            result = number_expr.run_tests('''
                # stray character
                100Z
                # missing leading digit before '.'
                -.100
                # too many '.'
                3.14.159
                ''', failure_tests=True)
            print("Success" if result[0] else "Failed!")

        prints::

            # unsigned integer
            100
            [100]

            # negative integer
            -100
            [-100]

            # float with scientific notation
            6.02e23
            [6.02e+23]

            # integer with scientific notation
            1e-12
            [1e-12]

            Success

            # stray character
            100Z
               ^
            FAIL: Expected end of text (at char 3), (line:1, col:4)

            # missing leading digit before '.'
            -.100
            ^
            FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1)

            # too many '.'
            3.14.159
                ^
            FAIL: Expected end of text (at char 4), (line:1, col:5)

            Success

        Each test string must be on a single line. If you want to test a string that spans multiple
        lines, create a test like this::

            expr.run_tests(r"this is a test\\n of strings that spans \\n 3 lines")

        (Note that this is a raw string literal, you must include the leading ``'r'``.)
        """
        from .testing import pyparsing_test

        parseAll = parseAll and parse_all
        fullDump = fullDump and full_dump
        printResults = printResults and print_results
        failureTests = failureTests or failure_tests
        postParse = postParse or post_parse
        if isinstance(tests, str_type):
            line_strip = type(tests).strip
            tests = [line_strip(test_line) for test_line in tests.rstrip().splitlines()]
        if isinstance(comment, str_type):
            comment = Literal(comment)
        if file is None:
            file = sys.stdout
        print_ = file.write

        result: Union[ParseResults, Exception]
        allResults = []
        comments = []
        success = True
        NL = Literal(r"\n").add_parse_action(replace_with("\n")).ignore(quoted_string)
        BOM = "\ufeff"
        for t in tests:
            if comment is not None and comment.matches(t, False) or comments and not t:
                comments.append(
                    pyparsing_test.with_line_numbers(t) if with_line_numbers else t
                )
                continue
            if not t:
                continue
            out = [
                "\n" + "\n".join(comments) if comments else "",
                pyparsing_test.with_line_numbers(t) if with_line_numbers else t,
            ]
            comments = []
            try:
                # convert newline marks to actual newlines, and strip leading BOM if present
                t = NL.transform_string(t.lstrip(BOM))
                result = self.parse_string(t, parse_all=parseAll)
            except ParseBaseException as pe:
                fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else ""
                out.append(pe.explain())
                out.append("FAIL: " + str(pe))
                if ParserElement.verbose_stacktrace:
                    out.extend(traceback.format_tb(pe.__traceback__))
                success = success and failureTests
                result = pe
            except Exception as exc:
                out.append("FAIL-EXCEPTION: {}: {}".format(type(exc).__name__, exc))
                if ParserElement.verbose_stacktrace:
                    out.extend(traceback.format_tb(exc.__traceback__))
                success = success and failureTests
                result = exc
            else:
                success = success and not failureTests
                if postParse is not None:
                    try:
                        pp_value = postParse(t, result)
                        if pp_value is not None:
                            if isinstance(pp_value, ParseResults):
                                out.append(pp_value.dump())
                            else:
                                out.append(str(pp_value))
                        else:
                            out.append(result.dump())
                    except Exception as e:
                        out.append(result.dump(full=fullDump))
                        out.append(
                            "{} failed: {}: {}".format(
                                postParse.__name__, type(e).__name__, e
                            )
                        )
                else:
                    out.append(result.dump(full=fullDump))
            out.append("")

            if printResults:
                print_("\n".join(out))

            allResults.append((t, result))

        return success, allResults

    def create_diagram(
        self,
        output_html: Union[TextIO, Path, str],
        vertical: int = 3,
        show_results_names: bool = False,
        show_groups: bool = False,
        **kwargs,
    ) -> None:
        """
        Create a railroad diagram for the parser.

        Parameters:
        - output_html (str or file-like object) - output target for generated
          diagram HTML
        - vertical (int) - threshold for formatting multiple alternatives vertically
          instead of horizontally (default=3)
        - show_results_names - bool flag whether diagram should show annotations for
          defined results names
        - show_groups - bool flag whether groups should be highlighted with an unlabeled surrounding box
        Additional diagram-formatting keyword arguments can also be included;
        see railroad.Diagram class.
        """

        try:
            from .diagram import to_railroad, railroad_to_html
        except ImportError as ie:
            raise Exception(
                "must ``pip install pyparsing[diagrams]`` to generate parser railroad diagrams"
            ) from ie

        self.streamline()

        railroad = to_railroad(
            self,
            vertical=vertical,
            show_results_names=show_results_names,
            show_groups=show_groups,
            diagram_kwargs=kwargs,
        )
        if isinstance(output_html, (str, Path)):
            with open(output_html, "w", encoding="utf-8") as diag_file:
                diag_file.write(railroad_to_html(railroad))
        else:
            # we were passed a file-like object, just write to it
            output_html.write(railroad_to_html(railroad))

    setDefaultWhitespaceChars = set_default_whitespace_chars
    inlineLiteralsUsing = inline_literals_using
    setResultsName = set_results_name
    setBreak = set_break
    setParseAction = set_parse_action
    addParseAction = add_parse_action
    addCondition = add_condition
    setFailAction = set_fail_action
    tryParse = try_parse
    canParseNext = can_parse_next
    resetCache = reset_cache
    enableLeftRecursion = enable_left_recursion
    enablePackrat = enable_packrat
    parseString = parse_string
    scanString = scan_string
    searchString = search_string
    transformString = transform_string
    setWhitespaceChars = set_whitespace_chars
    parseWithTabs = parse_with_tabs
    setDebugActions = set_debug_actions
    setDebug = set_debug
    defaultName = default_name
    setName = set_name
    parseFile = parse_file
    runTests = run_tests
    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class _PendingSkip(ParserElement):
    # internal placeholder class to hold a place were '...' is added to a parser element,
    # once another ParserElement is added, this placeholder will be replaced with a SkipTo
    def __init__(self, expr: ParserElement, must_skip: bool = False):
        super().__init__()
        self.anchor = expr
        self.must_skip = must_skip

    def _generateDefaultName(self):
        return str(self.anchor + Empty()).replace("Empty", "...")

    def __add__(self, other) -> "ParserElement":
        skipper = SkipTo(other).set_name("...")("_skipped*")
        if self.must_skip:

            def must_skip(t):
                if not t._skipped or t._skipped.as_list() == [""]:
                    del t[0]
                    t.pop("_skipped", None)

            def show_skip(t):
                if t._skipped.as_list()[-1:] == [""]:
                    t.pop("_skipped")
                    t["_skipped"] = "missing <" + repr(self.anchor) + ">"

            return (
                self.anchor + skipper().add_parse_action(must_skip)
                | skipper().add_parse_action(show_skip)
            ) + other

        return self.anchor + skipper + other

    def __repr__(self):
        return self.defaultName

    def parseImpl(self, *args):
        raise Exception(
            "use of `...` expression without following SkipTo target expression"
        )


class Token(ParserElement):
    """Abstract :class:`ParserElement` subclass, for defining atomic
    matching patterns.
    """

    def __init__(self):
        super().__init__(savelist=False)

    def _generateDefaultName(self):
        return type(self).__name__


class Empty(Token):
    """
    An empty token, will always match.
    """

    def __init__(self):
        super().__init__()
        self.mayReturnEmpty = True
        self.mayIndexError = False


class NoMatch(Token):
    """
    A token that will never match.
    """

    def __init__(self):
        super().__init__()
        self.mayReturnEmpty = True
        self.mayIndexError = False
        self.errmsg = "Unmatchable token"

    def parseImpl(self, instring, loc, doActions=True):
        raise ParseException(instring, loc, self.errmsg, self)


class Literal(Token):
    """
    Token to exactly match a specified string.

    Example::

        Literal('blah').parse_string('blah')  # -> ['blah']
        Literal('blah').parse_string('blahfooblah')  # -> ['blah']
        Literal('blah').parse_string('bla')  # -> Exception: Expected "blah"

    For case-insensitive matching, use :class:`CaselessLiteral`.

    For keyword matching (force word break before and after the matched string),
    use :class:`Keyword` or :class:`CaselessKeyword`.
    """

    def __init__(self, match_string: str = "", *, matchString: str = ""):
        super().__init__()
        match_string = matchString or match_string
        self.match = match_string
        self.matchLen = len(match_string)
        try:
            self.firstMatchChar = match_string[0]
        except IndexError:
            raise ValueError("null string passed to Literal; use Empty() instead")
        self.errmsg = "Expected " + self.name
        self.mayReturnEmpty = False
        self.mayIndexError = False

        # Performance tuning: modify __class__ to select
        # a parseImpl optimized for single-character check
        if self.matchLen == 1 and type(self) is Literal:
            self.__class__ = _SingleCharLiteral

    def _generateDefaultName(self):
        return repr(self.match)

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] == self.firstMatchChar and instring.startswith(
            self.match, loc
        ):
            return loc + self.matchLen, self.match
        raise ParseException(instring, loc, self.errmsg, self)


class _SingleCharLiteral(Literal):
    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] == self.firstMatchChar:
            return loc + 1, self.match
        raise ParseException(instring, loc, self.errmsg, self)


ParserElement._literalStringClass = Literal


class Keyword(Token):
    """
    Token to exactly match a specified string as a keyword, that is,
    it must be immediately followed by a non-keyword character.  Compare
    with :class:`Literal`:

    - ``Literal("if")`` will match the leading ``'if'`` in
      ``'ifAndOnlyIf'``.
    - ``Keyword("if")`` will not; it will only match the leading
      ``'if'`` in ``'if x=1'``, or ``'if(y==2)'``

    Accepts two optional constructor arguments in addition to the
    keyword string:

    - ``identChars`` is a string of characters that would be valid
      identifier characters, defaulting to all alphanumerics + "_" and
      "$"
    - ``caseless`` allows case-insensitive matching, default is ``False``.

    Example::

        Keyword("start").parse_string("start")  # -> ['start']
        Keyword("start").parse_string("starting")  # -> Exception

    For case-insensitive matching, use :class:`CaselessKeyword`.
    """

    DEFAULT_KEYWORD_CHARS = alphanums + "_$"

    def __init__(
        self,
        match_string: str = "",
        ident_chars: typing.Optional[str] = None,
        caseless: bool = False,
        *,
        matchString: str = "",
        identChars: typing.Optional[str] = None,
    ):
        super().__init__()
        identChars = identChars or ident_chars
        if identChars is None:
            identChars = Keyword.DEFAULT_KEYWORD_CHARS
        match_string = matchString or match_string
        self.match = match_string
        self.matchLen = len(match_string)
        try:
            self.firstMatchChar = match_string[0]
        except IndexError:
            raise ValueError("null string passed to Keyword; use Empty() instead")
        self.errmsg = "Expected {} {}".format(type(self).__name__, self.name)
        self.mayReturnEmpty = False
        self.mayIndexError = False
        self.caseless = caseless
        if caseless:
            self.caselessmatch = match_string.upper()
            identChars = identChars.upper()
        self.identChars = set(identChars)

    def _generateDefaultName(self):
        return repr(self.match)

    def parseImpl(self, instring, loc, doActions=True):
        errmsg = self.errmsg
        errloc = loc
        if self.caseless:
            if instring[loc : loc + self.matchLen].upper() == self.caselessmatch:
                if loc == 0 or instring[loc - 1].upper() not in self.identChars:
                    if (
                        loc >= len(instring) - self.matchLen
                        or instring[loc + self.matchLen].upper() not in self.identChars
                    ):
                        return loc + self.matchLen, self.match
                    else:
                        # followed by keyword char
                        errmsg += ", was immediately followed by keyword character"
                        errloc = loc + self.matchLen
                else:
                    # preceded by keyword char
                    errmsg += ", keyword was immediately preceded by keyword character"
                    errloc = loc - 1
            # else no match just raise plain exception

        else:
            if (
                instring[loc] == self.firstMatchChar
                and self.matchLen == 1
                or instring.startswith(self.match, loc)
            ):
                if loc == 0 or instring[loc - 1] not in self.identChars:
                    if (
                        loc >= len(instring) - self.matchLen
                        or instring[loc + self.matchLen] not in self.identChars
                    ):
                        return loc + self.matchLen, self.match
                    else:
                        # followed by keyword char
                        errmsg += (
                            ", keyword was immediately followed by keyword character"
                        )
                        errloc = loc + self.matchLen
                else:
                    # preceded by keyword char
                    errmsg += ", keyword was immediately preceded by keyword character"
                    errloc = loc - 1
            # else no match just raise plain exception

        raise ParseException(instring, errloc, errmsg, self)

    @staticmethod
    def set_default_keyword_chars(chars) -> None:
        """
        Overrides the default characters used by :class:`Keyword` expressions.
        """
        Keyword.DEFAULT_KEYWORD_CHARS = chars

    setDefaultKeywordChars = set_default_keyword_chars


class CaselessLiteral(Literal):
    """
    Token to match a specified string, ignoring case of letters.
    Note: the matched results will always be in the case of the given
    match string, NOT the case of the input text.

    Example::

        CaselessLiteral("CMD")[1, ...].parse_string("cmd CMD Cmd10")
        # -> ['CMD', 'CMD', 'CMD']

    (Contrast with example for :class:`CaselessKeyword`.)
    """

    def __init__(self, match_string: str = "", *, matchString: str = ""):
        match_string = matchString or match_string
        super().__init__(match_string.upper())
        # Preserve the defining literal.
        self.returnString = match_string
        self.errmsg = "Expected " + self.name

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc : loc + self.matchLen].upper() == self.match:
            return loc + self.matchLen, self.returnString
        raise ParseException(instring, loc, self.errmsg, self)


class CaselessKeyword(Keyword):
    """
    Caseless version of :class:`Keyword`.

    Example::

        CaselessKeyword("CMD")[1, ...].parse_string("cmd CMD Cmd10")
        # -> ['CMD', 'CMD']

    (Contrast with example for :class:`CaselessLiteral`.)
    """

    def __init__(
        self,
        match_string: str = "",
        ident_chars: typing.Optional[str] = None,
        *,
        matchString: str = "",
        identChars: typing.Optional[str] = None,
    ):
        identChars = identChars or ident_chars
        match_string = matchString or match_string
        super().__init__(match_string, identChars, caseless=True)


class CloseMatch(Token):
    """A variation on :class:`Literal` which matches "close" matches,
    that is, strings with at most 'n' mismatching characters.
    :class:`CloseMatch` takes parameters:

    - ``match_string`` - string to be matched
    - ``caseless`` - a boolean indicating whether to ignore casing when comparing characters
    - ``max_mismatches`` - (``default=1``) maximum number of
      mismatches allowed to count as a match

    The results from a successful parse will contain the matched text
    from the input string and the following named results:

    - ``mismatches`` - a list of the positions within the
      match_string where mismatches were found
    - ``original`` - the original match_string used to compare
      against the input string

    If ``mismatches`` is an empty list, then the match was an exact
    match.

    Example::

        patt = CloseMatch("ATCATCGAATGGA")
        patt.parse_string("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']})
        patt.parse_string("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1)

        # exact match
        patt.parse_string("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']})

        # close match allowing up to 2 mismatches
        patt = CloseMatch("ATCATCGAATGGA", max_mismatches=2)
        patt.parse_string("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']})
    """

    def __init__(
        self,
        match_string: str,
        max_mismatches: int = None,
        *,
        maxMismatches: int = 1,
        caseless=False,
    ):
        maxMismatches = max_mismatches if max_mismatches is not None else maxMismatches
        super().__init__()
        self.match_string = match_string
        self.maxMismatches = maxMismatches
        self.errmsg = "Expected {!r} (with up to {} mismatches)".format(
            self.match_string, self.maxMismatches
        )
        self.caseless = caseless
        self.mayIndexError = False
        self.mayReturnEmpty = False

    def _generateDefaultName(self):
        return "{}:{!r}".format(type(self).__name__, self.match_string)

    def parseImpl(self, instring, loc, doActions=True):
        start = loc
        instrlen = len(instring)
        maxloc = start + len(self.match_string)

        if maxloc <= instrlen:
            match_string = self.match_string
            match_stringloc = 0
            mismatches = []
            maxMismatches = self.maxMismatches

            for match_stringloc, s_m in enumerate(
                zip(instring[loc:maxloc], match_string)
            ):
                src, mat = s_m
                if self.caseless:
                    src, mat = src.lower(), mat.lower()

                if src != mat:
                    mismatches.append(match_stringloc)
                    if len(mismatches) > maxMismatches:
                        break
            else:
                loc = start + match_stringloc + 1
                results = ParseResults([instring[start:loc]])
                results["original"] = match_string
                results["mismatches"] = mismatches
                return loc, results

        raise ParseException(instring, loc, self.errmsg, self)


class Word(Token):
    """Token for matching words composed of allowed character sets.
    Parameters:
    - ``init_chars`` - string of all characters that should be used to
      match as a word; "ABC" will match "AAA", "ABAB", "CBAC", etc.;
      if ``body_chars`` is also specified, then this is the string of
      initial characters
    - ``body_chars`` - string of characters that
      can be used for matching after a matched initial character as
      given in ``init_chars``; if omitted, same as the initial characters
      (default=``None``)
    - ``min`` - minimum number of characters to match (default=1)
    - ``max`` - maximum number of characters to match (default=0)
    - ``exact`` - exact number of characters to match (default=0)
    - ``as_keyword`` - match as a keyword (default=``False``)
    - ``exclude_chars`` - characters that might be
      found in the input ``body_chars`` string but which should not be
      accepted for matching ;useful to define a word of all
      printables except for one or two characters, for instance
      (default=``None``)

    :class:`srange` is useful for defining custom character set strings
    for defining :class:`Word` expressions, using range notation from
    regular expression character sets.

    A common mistake is to use :class:`Word` to match a specific literal
    string, as in ``Word("Address")``. Remember that :class:`Word`
    uses the string argument to define *sets* of matchable characters.
    This expression would match "Add", "AAA", "dAred", or any other word
    made up of the characters 'A', 'd', 'r', 'e', and 's'. To match an
    exact literal string, use :class:`Literal` or :class:`Keyword`.

    pyparsing includes helper strings for building Words:

    - :class:`alphas`
    - :class:`nums`
    - :class:`alphanums`
    - :class:`hexnums`
    - :class:`alphas8bit` (alphabetic characters in ASCII range 128-255
      - accented, tilded, umlauted, etc.)
    - :class:`punc8bit` (non-alphabetic characters in ASCII range
      128-255 - currency, symbols, superscripts, diacriticals, etc.)
    - :class:`printables` (any non-whitespace character)

    ``alphas``, ``nums``, and ``printables`` are also defined in several
    Unicode sets - see :class:`pyparsing_unicode``.

    Example::

        # a word composed of digits
        integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9"))

        # a word with a leading capital, and zero or more lowercase
        capital_word = Word(alphas.upper(), alphas.lower())

        # hostnames are alphanumeric, with leading alpha, and '-'
        hostname = Word(alphas, alphanums + '-')

        # roman numeral (not a strict parser, accepts invalid mix of characters)
        roman = Word("IVXLCDM")

        # any string of non-whitespace characters, except for ','
        csv_value = Word(printables, exclude_chars=",")
    """

    def __init__(
        self,
        init_chars: str = "",
        body_chars: typing.Optional[str] = None,
        min: int = 1,
        max: int = 0,
        exact: int = 0,
        as_keyword: bool = False,
        exclude_chars: typing.Optional[str] = None,
        *,
        initChars: typing.Optional[str] = None,
        bodyChars: typing.Optional[str] = None,
        asKeyword: bool = False,
        excludeChars: typing.Optional[str] = None,
    ):
        initChars = initChars or init_chars
        bodyChars = bodyChars or body_chars
        asKeyword = asKeyword or as_keyword
        excludeChars = excludeChars or exclude_chars
        super().__init__()
        if not initChars:
            raise ValueError(
                "invalid {}, initChars cannot be empty string".format(
                    type(self).__name__
                )
            )

        initChars = set(initChars)
        self.initChars = initChars
        if excludeChars:
            excludeChars = set(excludeChars)
            initChars -= excludeChars
            if bodyChars:
                bodyChars = set(bodyChars) - excludeChars
        self.initCharsOrig = "".join(sorted(initChars))

        if bodyChars:
            self.bodyCharsOrig = "".join(sorted(bodyChars))
            self.bodyChars = set(bodyChars)
        else:
            self.bodyCharsOrig = "".join(sorted(initChars))
            self.bodyChars = set(initChars)

        self.maxSpecified = max > 0

        if min < 1:
            raise ValueError(
                "cannot specify a minimum length < 1; use Opt(Word()) if zero-length word is permitted"
            )

        self.minLen = min

        if max > 0:
            self.maxLen = max
        else:
            self.maxLen = _MAX_INT

        if exact > 0:
            self.maxLen = exact
            self.minLen = exact

        self.errmsg = "Expected " + self.name
        self.mayIndexError = False
        self.asKeyword = asKeyword

        # see if we can make a regex for this Word
        if " " not in self.initChars | self.bodyChars and (min == 1 and exact == 0):
            if self.bodyChars == self.initChars:
                if max == 0:
                    repeat = "+"
                elif max == 1:
                    repeat = ""
                else:
                    repeat = "{{{},{}}}".format(
                        self.minLen, "" if self.maxLen == _MAX_INT else self.maxLen
                    )
                self.reString = "[{}]{}".format(
                    _collapse_string_to_ranges(self.initChars),
                    repeat,
                )
            elif len(self.initChars) == 1:
                if max == 0:
                    repeat = "*"
                else:
                    repeat = "{{0,{}}}".format(max - 1)
                self.reString = "{}[{}]{}".format(
                    re.escape(self.initCharsOrig),
                    _collapse_string_to_ranges(self.bodyChars),
                    repeat,
                )
            else:
                if max == 0:
                    repeat = "*"
                elif max == 2:
                    repeat = ""
                else:
                    repeat = "{{0,{}}}".format(max - 1)
                self.reString = "[{}][{}]{}".format(
                    _collapse_string_to_ranges(self.initChars),
                    _collapse_string_to_ranges(self.bodyChars),
                    repeat,
                )
            if self.asKeyword:
                self.reString = r"\b" + self.reString + r"\b"

            try:
                self.re = re.compile(self.reString)
            except re.error:
                self.re = None
            else:
                self.re_match = self.re.match
                self.__class__ = _WordRegex

    def _generateDefaultName(self):
        def charsAsStr(s):
            max_repr_len = 16
            s = _collapse_string_to_ranges(s, re_escape=False)
            if len(s) > max_repr_len:
                return s[: max_repr_len - 3] + "..."
            else:
                return s

        if self.initChars != self.bodyChars:
            base = "W:({}, {})".format(
                charsAsStr(self.initChars), charsAsStr(self.bodyChars)
            )
        else:
            base = "W:({})".format(charsAsStr(self.initChars))

        # add length specification
        if self.minLen > 1 or self.maxLen != _MAX_INT:
            if self.minLen == self.maxLen:
                if self.minLen == 1:
                    return base[2:]
                else:
                    return base + "{{{}}}".format(self.minLen)
            elif self.maxLen == _MAX_INT:
                return base + "{{{},...}}".format(self.minLen)
            else:
                return base + "{{{},{}}}".format(self.minLen, self.maxLen)
        return base

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] not in self.initChars:
            raise ParseException(instring, loc, self.errmsg, self)

        start = loc
        loc += 1
        instrlen = len(instring)
        bodychars = self.bodyChars
        maxloc = start + self.maxLen
        maxloc = min(maxloc, instrlen)
        while loc < maxloc and instring[loc] in bodychars:
            loc += 1

        throwException = False
        if loc - start < self.minLen:
            throwException = True
        elif self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
            throwException = True
        elif self.asKeyword:
            if (
                start > 0
                and instring[start - 1] in bodychars
                or loc < instrlen
                and instring[loc] in bodychars
            ):
                throwException = True

        if throwException:
            raise ParseException(instring, loc, self.errmsg, self)

        return loc, instring[start:loc]


class _WordRegex(Word):
    def parseImpl(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        return loc, result.group()


class Char(_WordRegex):
    """A short-cut class for defining :class:`Word` ``(characters, exact=1)``,
    when defining a match of any single character in a string of
    characters.
    """

    def __init__(
        self,
        charset: str,
        as_keyword: bool = False,
        exclude_chars: typing.Optional[str] = None,
        *,
        asKeyword: bool = False,
        excludeChars: typing.Optional[str] = None,
    ):
        asKeyword = asKeyword or as_keyword
        excludeChars = excludeChars or exclude_chars
        super().__init__(
            charset, exact=1, asKeyword=asKeyword, excludeChars=excludeChars
        )
        self.reString = "[{}]".format(_collapse_string_to_ranges(self.initChars))
        if asKeyword:
            self.reString = r"\b{}\b".format(self.reString)
        self.re = re.compile(self.reString)
        self.re_match = self.re.match


class Regex(Token):
    r"""Token for matching strings that match a given regular
    expression. Defined with string specifying the regular expression in
    a form recognized by the stdlib Python  `re module <https://docs.python.org/3/library/re.html>`_.
    If the given regex contains named groups (defined using ``(?P<name>...)``),
    these will be preserved as named :class:`ParseResults`.

    If instead of the Python stdlib ``re`` module you wish to use a different RE module
    (such as the ``regex`` module), you can do so by building your ``Regex`` object with
    a compiled RE that was compiled using ``regex``.

    Example::

        realnum = Regex(r"[+-]?\d+\.\d*")
        # ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
        roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")

        # named fields in a regex will be returned as named results
        date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)')

        # the Regex class will accept re's compiled using the regex module
        import regex
        parser = pp.Regex(regex.compile(r'[0-9]'))
    """

    def __init__(
        self,
        pattern: Any,
        flags: Union[re.RegexFlag, int] = 0,
        as_group_list: bool = False,
        as_match: bool = False,
        *,
        asGroupList: bool = False,
        asMatch: bool = False,
    ):
        """The parameters ``pattern`` and ``flags`` are passed
        to the ``re.compile()`` function as-is. See the Python
        `re module <https://docs.python.org/3/library/re.html>`_ module for an
        explanation of the acceptable patterns and flags.
        """
        super().__init__()
        asGroupList = asGroupList or as_group_list
        asMatch = asMatch or as_match

        if isinstance(pattern, str_type):
            if not pattern:
                raise ValueError("null string passed to Regex; use Empty() instead")

            self._re = None
            self.reString = self.pattern = pattern
            self.flags = flags

        elif hasattr(pattern, "pattern") and hasattr(pattern, "match"):
            self._re = pattern
            self.pattern = self.reString = pattern.pattern
            self.flags = flags

        else:
            raise TypeError(
                "Regex may only be constructed with a string or a compiled RE object"
            )

        self.errmsg = "Expected " + self.name
        self.mayIndexError = False
        self.asGroupList = asGroupList
        self.asMatch = asMatch
        if self.asGroupList:
            self.parseImpl = self.parseImplAsGroupList
        if self.asMatch:
            self.parseImpl = self.parseImplAsMatch

    @cached_property
    def re(self):
        if self._re:
            return self._re
        else:
            try:
                return re.compile(self.pattern, self.flags)
            except re.error:
                raise ValueError(
                    "invalid pattern ({!r}) passed to Regex".format(self.pattern)
                )

    @cached_property
    def re_match(self):
        return self.re.match

    @cached_property
    def mayReturnEmpty(self):
        return self.re_match("") is not None

    def _generateDefaultName(self):
        return "Re:({})".format(repr(self.pattern).replace("\\\\", "\\"))

    def parseImpl(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = ParseResults(result.group())
        d = result.groupdict()
        if d:
            for k, v in d.items():
                ret[k] = v
        return loc, ret

    def parseImplAsGroupList(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = result.groups()
        return loc, ret

    def parseImplAsMatch(self, instring, loc, doActions=True):
        result = self.re_match(instring, loc)
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = result
        return loc, ret

    def sub(self, repl: str) -> ParserElement:
        r"""
        Return :class:`Regex` with an attached parse action to transform the parsed
        result as if called using `re.sub(expr, repl, string) <https://docs.python.org/3/library/re.html#re.sub>`_.

        Example::

            make_html = Regex(r"(\w+):(.*?):").sub(r"<\1>\2</\1>")
            print(make_html.transform_string("h1:main title:"))
            # prints "<h1>main title</h1>"
        """
        if self.asGroupList:
            raise TypeError("cannot use sub() with Regex(asGroupList=True)")

        if self.asMatch and callable(repl):
            raise TypeError("cannot use sub() with a callable with Regex(asMatch=True)")

        if self.asMatch:

            def pa(tokens):
                return tokens[0].expand(repl)

        else:

            def pa(tokens):
                return self.re.sub(repl, tokens[0])

        return self.add_parse_action(pa)


class QuotedString(Token):
    r"""
    Token for matching strings that are delimited by quoting characters.

    Defined with the following parameters:

    - ``quote_char`` - string of one or more characters defining the
      quote delimiting string
    - ``esc_char`` - character to re_escape quotes, typically backslash
      (default= ``None``)
    - ``esc_quote`` - special quote sequence to re_escape an embedded quote
      string (such as SQL's ``""`` to re_escape an embedded ``"``)
      (default= ``None``)
    - ``multiline`` - boolean indicating whether quotes can span
      multiple lines (default= ``False``)
    - ``unquote_results`` - boolean indicating whether the matched text
      should be unquoted (default= ``True``)
    - ``end_quote_char`` - string of one or more characters defining the
      end of the quote delimited string (default= ``None``  => same as
      quote_char)
    - ``convert_whitespace_escapes`` - convert escaped whitespace
      (``'\t'``, ``'\n'``, etc.) to actual whitespace
      (default= ``True``)

    Example::

        qs = QuotedString('"')
        print(qs.search_string('lsjdf "This is the quote" sldjf'))
        complex_qs = QuotedString('{{', end_quote_char='}}')
        print(complex_qs.search_string('lsjdf {{This is the "quote"}} sldjf'))
        sql_qs = QuotedString('"', esc_quote='""')
        print(sql_qs.search_string('lsjdf "This is the quote with ""embedded"" quotes" sldjf'))

    prints::

        [['This is the quote']]
        [['This is the "quote"']]
        [['This is the quote with "embedded" quotes']]
    """
    ws_map = ((r"\t", "\t"), (r"\n", "\n"), (r"\f", "\f"), (r"\r", "\r"))

    def __init__(
        self,
        quote_char: str = "",
        esc_char: typing.Optional[str] = None,
        esc_quote: typing.Optional[str] = None,
        multiline: bool = False,
        unquote_results: bool = True,
        end_quote_char: typing.Optional[str] = None,
        convert_whitespace_escapes: bool = True,
        *,
        quoteChar: str = "",
        escChar: typing.Optional[str] = None,
        escQuote: typing.Optional[str] = None,
        unquoteResults: bool = True,
        endQuoteChar: typing.Optional[str] = None,
        convertWhitespaceEscapes: bool = True,
    ):
        super().__init__()
        escChar = escChar or esc_char
        escQuote = escQuote or esc_quote
        unquoteResults = unquoteResults and unquote_results
        endQuoteChar = endQuoteChar or end_quote_char
        convertWhitespaceEscapes = (
            convertWhitespaceEscapes and convert_whitespace_escapes
        )
        quote_char = quoteChar or quote_char

        # remove white space from quote chars - wont work anyway
        quote_char = quote_char.strip()
        if not quote_char:
            raise ValueError("quote_char cannot be the empty string")

        if endQuoteChar is None:
            endQuoteChar = quote_char
        else:
            endQuoteChar = endQuoteChar.strip()
            if not endQuoteChar:
                raise ValueError("endQuoteChar cannot be the empty string")

        self.quoteChar = quote_char
        self.quoteCharLen = len(quote_char)
        self.firstQuoteChar = quote_char[0]
        self.endQuoteChar = endQuoteChar
        self.endQuoteCharLen = len(endQuoteChar)
        self.escChar = escChar
        self.escQuote = escQuote
        self.unquoteResults = unquoteResults
        self.convertWhitespaceEscapes = convertWhitespaceEscapes

        sep = ""
        inner_pattern = ""

        if escQuote:
            inner_pattern += r"{}(?:{})".format(sep, re.escape(escQuote))
            sep = "|"

        if escChar:
            inner_pattern += r"{}(?:{}.)".format(sep, re.escape(escChar))
            sep = "|"
            self.escCharReplacePattern = re.escape(self.escChar) + "(.)"

        if len(self.endQuoteChar) > 1:
            inner_pattern += (
                "{}(?:".format(sep)
                + "|".join(
                    "(?:{}(?!{}))".format(
                        re.escape(self.endQuoteChar[:i]),
                        re.escape(self.endQuoteChar[i:]),
                    )
                    for i in range(len(self.endQuoteChar) - 1, 0, -1)
                )
                + ")"
            )
            sep = "|"

        if multiline:
            self.flags = re.MULTILINE | re.DOTALL
            inner_pattern += r"{}(?:[^{}{}])".format(
                sep,
                _escape_regex_range_chars(self.endQuoteChar[0]),
                (_escape_regex_range_chars(escChar) if escChar is not None else ""),
            )
        else:
            self.flags = 0
            inner_pattern += r"{}(?:[^{}\n\r{}])".format(
                sep,
                _escape_regex_range_chars(self.endQuoteChar[0]),
                (_escape_regex_range_chars(escChar) if escChar is not None else ""),
            )

        self.pattern = "".join(
            [
                re.escape(self.quoteChar),
                "(?:",
                inner_pattern,
                ")*",
                re.escape(self.endQuoteChar),
            ]
        )

        try:
            self.re = re.compile(self.pattern, self.flags)
            self.reString = self.pattern
            self.re_match = self.re.match
        except re.error:
            raise ValueError(
                "invalid pattern {!r} passed to Regex".format(self.pattern)
            )

        self.errmsg = "Expected " + self.name
        self.mayIndexError = False
        self.mayReturnEmpty = True

    def _generateDefaultName(self):
        if self.quoteChar == self.endQuoteChar and isinstance(self.quoteChar, str_type):
            return "string enclosed in {!r}".format(self.quoteChar)

        return "quoted string, starting with {} ending with {}".format(
            self.quoteChar, self.endQuoteChar
        )

    def parseImpl(self, instring, loc, doActions=True):
        result = (
            instring[loc] == self.firstQuoteChar
            and self.re_match(instring, loc)
            or None
        )
        if not result:
            raise ParseException(instring, loc, self.errmsg, self)

        loc = result.end()
        ret = result.group()

        if self.unquoteResults:

            # strip off quotes
            ret = ret[self.quoteCharLen : -self.endQuoteCharLen]

            if isinstance(ret, str_type):
                # replace escaped whitespace
                if "\\" in ret and self.convertWhitespaceEscapes:
                    for wslit, wschar in self.ws_map:
                        ret = ret.replace(wslit, wschar)

                # replace escaped characters
                if self.escChar:
                    ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret)

                # replace escaped quotes
                if self.escQuote:
                    ret = ret.replace(self.escQuote, self.endQuoteChar)

        return loc, ret


class CharsNotIn(Token):
    """Token for matching words composed of characters *not* in a given
    set (will include whitespace in matched characters if not listed in
    the provided exclusion set - see example). Defined with string
    containing all disallowed characters, and an optional minimum,
    maximum, and/or exact length.  The default value for ``min`` is
    1 (a minimum value < 1 is not valid); the default values for
    ``max`` and ``exact`` are 0, meaning no maximum or exact
    length restriction.

    Example::

        # define a comma-separated-value as anything that is not a ','
        csv_value = CharsNotIn(',')
        print(delimited_list(csv_value).parse_string("dkls,lsdkjf,s12 34,@!#,213"))

    prints::

        ['dkls', 'lsdkjf', 's12 34', '@!#', '213']
    """

    def __init__(
        self,
        not_chars: str = "",
        min: int = 1,
        max: int = 0,
        exact: int = 0,
        *,
        notChars: str = "",
    ):
        super().__init__()
        self.skipWhitespace = False
        self.notChars = not_chars or notChars
        self.notCharsSet = set(self.notChars)

        if min < 1:
            raise ValueError(
                "cannot specify a minimum length < 1; use "
                "Opt(CharsNotIn()) if zero-length char group is permitted"
            )

        self.minLen = min

        if max > 0:
            self.maxLen = max
        else:
            self.maxLen = _MAX_INT

        if exact > 0:
            self.maxLen = exact
            self.minLen = exact

        self.errmsg = "Expected " + self.name
        self.mayReturnEmpty = self.minLen == 0
        self.mayIndexError = False

    def _generateDefaultName(self):
        not_chars_str = _collapse_string_to_ranges(self.notChars)
        if len(not_chars_str) > 16:
            return "!W:({}...)".format(self.notChars[: 16 - 3])
        else:
            return "!W:({})".format(self.notChars)

    def parseImpl(self, instring, loc, doActions=True):
        notchars = self.notCharsSet
        if instring[loc] in notchars:
            raise ParseException(instring, loc, self.errmsg, self)

        start = loc
        loc += 1
        maxlen = min(start + self.maxLen, len(instring))
        while loc < maxlen and instring[loc] not in notchars:
            loc += 1

        if loc - start < self.minLen:
            raise ParseException(instring, loc, self.errmsg, self)

        return loc, instring[start:loc]


class White(Token):
    """Special matching class for matching whitespace.  Normally,
    whitespace is ignored by pyparsing grammars.  This class is included
    when some whitespace structures are significant.  Define with
    a string containing the whitespace characters to be matched; default
    is ``" \\t\\r\\n"``.  Also takes optional ``min``,
    ``max``, and ``exact`` arguments, as defined for the
    :class:`Word` class.
    """

    whiteStrs = {
        " ": "<SP>",
        "\t": "<TAB>",
        "\n": "<LF>",
        "\r": "<CR>",
        "\f": "<FF>",
        "\u00A0": "<NBSP>",
        "\u1680": "<OGHAM_SPACE_MARK>",
        "\u180E": "<MONGOLIAN_VOWEL_SEPARATOR>",
        "\u2000": "<EN_QUAD>",
        "\u2001": "<EM_QUAD>",
        "\u2002": "<EN_SPACE>",
        "\u2003": "<EM_SPACE>",
        "\u2004": "<THREE-PER-EM_SPACE>",
        "\u2005": "<FOUR-PER-EM_SPACE>",
        "\u2006": "<SIX-PER-EM_SPACE>",
        "\u2007": "<FIGURE_SPACE>",
        "\u2008": "<PUNCTUATION_SPACE>",
        "\u2009": "<THIN_SPACE>",
        "\u200A": "<HAIR_SPACE>",
        "\u200B": "<ZERO_WIDTH_SPACE>",
        "\u202F": "<NNBSP>",
        "\u205F": "<MMSP>",
        "\u3000": "<IDEOGRAPHIC_SPACE>",
    }

    def __init__(self, ws: str = " \t\r\n", min: int = 1, max: int = 0, exact: int = 0):
        super().__init__()
        self.matchWhite = ws
        self.set_whitespace_chars(
            "".join(c for c in self.whiteStrs if c not in self.matchWhite),
            copy_defaults=True,
        )
        # self.leave_whitespace()
        self.mayReturnEmpty = True
        self.errmsg = "Expected " + self.name

        self.minLen = min

        if max > 0:
            self.maxLen = max
        else:
            self.maxLen = _MAX_INT

        if exact > 0:
            self.maxLen = exact
            self.minLen = exact

    def _generateDefaultName(self):
        return "".join(White.whiteStrs[c] for c in self.matchWhite)

    def parseImpl(self, instring, loc, doActions=True):
        if instring[loc] not in self.matchWhite:
            raise ParseException(instring, loc, self.errmsg, self)
        start = loc
        loc += 1
        maxloc = start + self.maxLen
        maxloc = min(maxloc, len(instring))
        while loc < maxloc and instring[loc] in self.matchWhite:
            loc += 1

        if loc - start < self.minLen:
            raise ParseException(instring, loc, self.errmsg, self)

        return loc, instring[start:loc]


class PositionToken(Token):
    def __init__(self):
        super().__init__()
        self.mayReturnEmpty = True
        self.mayIndexError = False


class GoToColumn(PositionToken):
    """Token to advance to a specific column of input text; useful for
    tabular report scraping.
    """

    def __init__(self, colno: int):
        super().__init__()
        self.col = colno

    def preParse(self, instring, loc):
        if col(loc, instring) != self.col:
            instrlen = len(instring)
            if self.ignoreExprs:
                loc = self._skipIgnorables(instring, loc)
            while (
                loc < instrlen
                and instring[loc].isspace()
                and col(loc, instring) != self.col
            ):
                loc += 1
        return loc

    def parseImpl(self, instring, loc, doActions=True):
        thiscol = col(loc, instring)
        if thiscol > self.col:
            raise ParseException(instring, loc, "Text not in expected column", self)
        newloc = loc + self.col - thiscol
        ret = instring[loc:newloc]
        return newloc, ret


class LineStart(PositionToken):
    r"""Matches if current position is at the beginning of a line within
    the parse string

    Example::

        test = '''\
        AAA this line
        AAA and this line
          AAA but not this one
        B AAA and definitely not this one
        '''

        for t in (LineStart() + 'AAA' + restOfLine).search_string(test):
            print(t)

    prints::

        ['AAA', ' this line']
        ['AAA', ' and this line']

    """

    def __init__(self):
        super().__init__()
        self.leave_whitespace()
        self.orig_whiteChars = set() | self.whiteChars
        self.whiteChars.discard("\n")
        self.skipper = Empty().set_whitespace_chars(self.whiteChars)
        self.errmsg = "Expected start of line"

    def preParse(self, instring, loc):
        if loc == 0:
            return loc
        else:
            ret = self.skipper.preParse(instring, loc)
            if "\n" in self.orig_whiteChars:
                while instring[ret : ret + 1] == "\n":
                    ret = self.skipper.preParse(instring, ret + 1)
            return ret

    def parseImpl(self, instring, loc, doActions=True):
        if col(loc, instring) == 1:
            return loc, []
        raise ParseException(instring, loc, self.errmsg, self)


class LineEnd(PositionToken):
    """Matches if current position is at the end of a line within the
    parse string
    """

    def __init__(self):
        super().__init__()
        self.whiteChars.discard("\n")
        self.set_whitespace_chars(self.whiteChars, copy_defaults=False)
        self.errmsg = "Expected end of line"

    def parseImpl(self, instring, loc, doActions=True):
        if loc < len(instring):
            if instring[loc] == "\n":
                return loc + 1, "\n"
            else:
                raise ParseException(instring, loc, self.errmsg, self)
        elif loc == len(instring):
            return loc + 1, []
        else:
            raise ParseException(instring, loc, self.errmsg, self)


class StringStart(PositionToken):
    """Matches if current position is at the beginning of the parse
    string
    """

    def __init__(self):
        super().__init__()
        self.errmsg = "Expected start of text"

    def parseImpl(self, instring, loc, doActions=True):
        if loc != 0:
            # see if entire string up to here is just whitespace and ignoreables
            if loc != self.preParse(instring, 0):
                raise ParseException(instring, loc, self.errmsg, self)
        return loc, []


class StringEnd(PositionToken):
    """
    Matches if current position is at the end of the parse string
    """

    def __init__(self):
        super().__init__()
        self.errmsg = "Expected end of text"

    def parseImpl(self, instring, loc, doActions=True):
        if loc < len(instring):
            raise ParseException(instring, loc, self.errmsg, self)
        elif loc == len(instring):
            return loc + 1, []
        elif loc > len(instring):
            return loc, []
        else:
            raise ParseException(instring, loc, self.errmsg, self)


class WordStart(PositionToken):
    """Matches if the current position is at the beginning of a
    :class:`Word`, and is not preceded by any character in a given
    set of ``word_chars`` (default= ``printables``). To emulate the
    ``\b`` behavior of regular expressions, use
    ``WordStart(alphanums)``. ``WordStart`` will also match at
    the beginning of the string being parsed, or at the beginning of
    a line.
    """

    def __init__(self, word_chars: str = printables, *, wordChars: str = printables):
        wordChars = word_chars if wordChars == printables else wordChars
        super().__init__()
        self.wordChars = set(wordChars)
        self.errmsg = "Not at the start of a word"

    def parseImpl(self, instring, loc, doActions=True):
        if loc != 0:
            if (
                instring[loc - 1] in self.wordChars
                or instring[loc] not in self.wordChars
            ):
                raise ParseException(instring, loc, self.errmsg, self)
        return loc, []


class WordEnd(PositionToken):
    """Matches if the current position is at the end of a :class:`Word`,
    and is not followed by any character in a given set of ``word_chars``
    (default= ``printables``). To emulate the ``\b`` behavior of
    regular expressions, use ``WordEnd(alphanums)``. ``WordEnd``
    will also match at the end of the string being parsed, or at the end
    of a line.
    """

    def __init__(self, word_chars: str = printables, *, wordChars: str = printables):
        wordChars = word_chars if wordChars == printables else wordChars
        super().__init__()
        self.wordChars = set(wordChars)
        self.skipWhitespace = False
        self.errmsg = "Not at the end of a word"

    def parseImpl(self, instring, loc, doActions=True):
        instrlen = len(instring)
        if instrlen > 0 and loc < instrlen:
            if (
                instring[loc] in self.wordChars
                or instring[loc - 1] not in self.wordChars
            ):
                raise ParseException(instring, loc, self.errmsg, self)
        return loc, []


class ParseExpression(ParserElement):
    """Abstract subclass of ParserElement, for combining and
    post-processing parsed tokens.
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
        super().__init__(savelist)
        self.exprs: List[ParserElement]
        if isinstance(exprs, _generatorType):
            exprs = list(exprs)

        if isinstance(exprs, str_type):
            self.exprs = [self._literalStringClass(exprs)]
        elif isinstance(exprs, ParserElement):
            self.exprs = [exprs]
        elif isinstance(exprs, Iterable):
            exprs = list(exprs)
            # if sequence of strings provided, wrap with Literal
            if any(isinstance(expr, str_type) for expr in exprs):
                exprs = (
                    self._literalStringClass(e) if isinstance(e, str_type) else e
                    for e in exprs
                )
            self.exprs = list(exprs)
        else:
            try:
                self.exprs = list(exprs)
            except TypeError:
                self.exprs = [exprs]
        self.callPreparse = False

    def recurse(self) -> Sequence[ParserElement]:
        return self.exprs[:]

    def append(self, other) -> ParserElement:
        self.exprs.append(other)
        self._defaultName = None
        return self

    def leave_whitespace(self, recursive: bool = True) -> ParserElement:
        """
        Extends ``leave_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on
           all contained expressions.
        """
        super().leave_whitespace(recursive)

        if recursive:
            self.exprs = [e.copy() for e in self.exprs]
            for e in self.exprs:
                e.leave_whitespace(recursive)
        return self

    def ignore_whitespace(self, recursive: bool = True) -> ParserElement:
        """
        Extends ``ignore_whitespace`` defined in base class, and also invokes ``leave_whitespace`` on
           all contained expressions.
        """
        super().ignore_whitespace(recursive)
        if recursive:
            self.exprs = [e.copy() for e in self.exprs]
            for e in self.exprs:
                e.ignore_whitespace(recursive)
        return self

    def ignore(self, other) -> ParserElement:
        if isinstance(other, Suppress):
            if other not in self.ignoreExprs:
                super().ignore(other)
                for e in self.exprs:
                    e.ignore(self.ignoreExprs[-1])
        else:
            super().ignore(other)
            for e in self.exprs:
                e.ignore(self.ignoreExprs[-1])
        return self

    def _generateDefaultName(self):
        return "{}:({})".format(self.__class__.__name__, str(self.exprs))

    def streamline(self) -> ParserElement:
        if self.streamlined:
            return self

        super().streamline()

        for e in self.exprs:
            e.streamline()

        # collapse nested :class:`And`'s of the form ``And(And(And(a, b), c), d)`` to ``And(a, b, c, d)``
        # but only if there are no parse actions or resultsNames on the nested And's
        # (likewise for :class:`Or`'s and :class:`MatchFirst`'s)
        if len(self.exprs) == 2:
            other = self.exprs[0]
            if (
                isinstance(other, self.__class__)
                and not other.parseAction
                and other.resultsName is None
                and not other.debug
            ):
                self.exprs = other.exprs[:] + [self.exprs[1]]
                self._defaultName = None
                self.mayReturnEmpty |= other.mayReturnEmpty
                self.mayIndexError |= other.mayIndexError

            other = self.exprs[-1]
            if (
                isinstance(other, self.__class__)
                and not other.parseAction
                and other.resultsName is None
                and not other.debug
            ):
                self.exprs = self.exprs[:-1] + other.exprs[:]
                self._defaultName = None
                self.mayReturnEmpty |= other.mayReturnEmpty
                self.mayIndexError |= other.mayIndexError

        self.errmsg = "Expected " + str(self)

        return self

    def validate(self, validateTrace=None) -> None:
        tmp = (validateTrace if validateTrace is not None else [])[:] + [self]
        for e in self.exprs:
            e.validate(tmp)
        self._checkRecursion([])

    def copy(self) -> ParserElement:
        ret = super().copy()
        ret.exprs = [e.copy() for e in self.exprs]
        return ret

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_ungrouped_named_tokens_in_collection
            and Diagnostics.warn_ungrouped_named_tokens_in_collection
            not in self.suppress_warnings_
        ):
            for e in self.exprs:
                if (
                    isinstance(e, ParserElement)
                    and e.resultsName
                    and Diagnostics.warn_ungrouped_named_tokens_in_collection
                    not in e.suppress_warnings_
                ):
                    warnings.warn(
                        "{}: setting results name {!r} on {} expression "
                        "collides with {!r} on contained expression".format(
                            "warn_ungrouped_named_tokens_in_collection",
                            name,
                            type(self).__name__,
                            e.resultsName,
                        ),
                        stacklevel=3,
                    )

        return super()._setResultsName(name, listAllMatches)

    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class And(ParseExpression):
    """
    Requires all given :class:`ParseExpression` s to be found in the given order.
    Expressions may be separated by whitespace.
    May be constructed using the ``'+'`` operator.
    May also be constructed using the ``'-'`` operator, which will
    suppress backtracking.

    Example::

        integer = Word(nums)
        name_expr = Word(alphas)[1, ...]

        expr = And([integer("id"), name_expr("name"), integer("age")])
        # more easily written as:
        expr = integer("id") + name_expr("name") + integer("age")
    """

    class _ErrorStop(Empty):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.leave_whitespace()

        def _generateDefaultName(self):
            return "-"

    def __init__(
        self, exprs_arg: typing.Iterable[ParserElement], savelist: bool = True
    ):
        exprs: List[ParserElement] = list(exprs_arg)
        if exprs and Ellipsis in exprs:
            tmp = []
            for i, expr in enumerate(exprs):
                if expr is Ellipsis:
                    if i < len(exprs) - 1:
                        skipto_arg: ParserElement = (Empty() + exprs[i + 1]).exprs[-1]
                        tmp.append(SkipTo(skipto_arg)("_skipped*"))
                    else:
                        raise Exception(
                            "cannot construct And with sequence ending in ..."
                        )
                else:
                    tmp.append(expr)
            exprs[:] = tmp
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
            if not isinstance(self.exprs[0], White):
                self.set_whitespace_chars(
                    self.exprs[0].whiteChars,
                    copy_defaults=self.exprs[0].copyDefaultWhiteChars,
                )
                self.skipWhitespace = self.exprs[0].skipWhitespace
            else:
                self.skipWhitespace = False
        else:
            self.mayReturnEmpty = True
        self.callPreparse = True

    def streamline(self) -> ParserElement:
        # collapse any _PendingSkip's
        if self.exprs:
            if any(
                isinstance(e, ParseExpression)
                and e.exprs
                and isinstance(e.exprs[-1], _PendingSkip)
                for e in self.exprs[:-1]
            ):
                for i, e in enumerate(self.exprs[:-1]):
                    if e is None:
                        continue
                    if (
                        isinstance(e, ParseExpression)
                        and e.exprs
                        and isinstance(e.exprs[-1], _PendingSkip)
                    ):
                        e.exprs[-1] = e.exprs[-1] + self.exprs[i + 1]
                        self.exprs[i + 1] = None
                self.exprs = [e for e in self.exprs if e is not None]

        super().streamline()

        # link any IndentedBlocks to the prior expression
        for prev, cur in zip(self.exprs, self.exprs[1:]):
            # traverse cur or any first embedded expr of cur looking for an IndentedBlock
            # (but watch out for recursive grammar)
            seen = set()
            while cur:
                if id(cur) in seen:
                    break
                seen.add(id(cur))
                if isinstance(cur, IndentedBlock):
                    prev.add_parse_action(
                        lambda s, l, t, cur_=cur: setattr(
                            cur_, "parent_anchor", col(l, s)
                        )
                    )
                    break
                subs = cur.recurse()
                cur = next(iter(subs), None)

        self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
        return self

    def parseImpl(self, instring, loc, doActions=True):
        # pass False as callPreParse arg to _parse for first element, since we already
        # pre-parsed the string as part of our And pre-parsing
        loc, resultlist = self.exprs[0]._parse(
            instring, loc, doActions, callPreParse=False
        )
        errorStop = False
        for e in self.exprs[1:]:
            # if isinstance(e, And._ErrorStop):
            if type(e) is And._ErrorStop:
                errorStop = True
                continue
            if errorStop:
                try:
                    loc, exprtokens = e._parse(instring, loc, doActions)
                except ParseSyntaxException:
                    raise
                except ParseBaseException as pe:
                    pe.__traceback__ = None
                    raise ParseSyntaxException._from_exception(pe)
                except IndexError:
                    raise ParseSyntaxException(
                        instring, len(instring), self.errmsg, self
                    )
            else:
                loc, exprtokens = e._parse(instring, loc, doActions)
            if exprtokens or exprtokens.haskeys():
                resultlist += exprtokens
        return loc, resultlist

    def __iadd__(self, other):
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        return self.append(other)  # And([self, other])

    def _checkRecursion(self, parseElementList):
        subRecCheckList = parseElementList[:] + [self]
        for e in self.exprs:
            e._checkRecursion(subRecCheckList)
            if not e.mayReturnEmpty:
                break

    def _generateDefaultName(self):
        inner = " ".join(str(e) for e in self.exprs)
        # strip off redundant inner {}'s
        while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}":
            inner = inner[1:-1]
        return "{" + inner + "}"


class Or(ParseExpression):
    """Requires that at least one :class:`ParseExpression` is found. If
    two expressions match, the expression that matches the longest
    string will be used. May be constructed using the ``'^'``
    operator.

    Example::

        # construct Or using '^' operator

        number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums))
        print(number.search_string("123 3.1416 789"))

    prints::

        [['123'], ['3.1416'], ['789']]
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.skipWhitespace = all(e.skipWhitespace for e in self.exprs)
        else:
            self.mayReturnEmpty = True

    def streamline(self) -> ParserElement:
        super().streamline()
        if self.exprs:
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.saveAsList = any(e.saveAsList for e in self.exprs)
            self.skipWhitespace = all(
                e.skipWhitespace and not isinstance(e, White) for e in self.exprs
            )
        else:
            self.saveAsList = False
        return self

    def parseImpl(self, instring, loc, doActions=True):
        maxExcLoc = -1
        maxException = None
        matches = []
        fatals = []
        if all(e.callPreparse for e in self.exprs):
            loc = self.preParse(instring, loc)
        for e in self.exprs:
            try:
                loc2 = e.try_parse(instring, loc, raise_fatal=True)
            except ParseFatalException as pfe:
                pfe.__traceback__ = None
                pfe.parserElement = e
                fatals.append(pfe)
                maxException = None
                maxExcLoc = -1
            except ParseException as err:
                if not fatals:
                    err.__traceback__ = None
                    if err.loc > maxExcLoc:
                        maxException = err
                        maxExcLoc = err.loc
            except IndexError:
                if len(instring) > maxExcLoc:
                    maxException = ParseException(
                        instring, len(instring), e.errmsg, self
                    )
                    maxExcLoc = len(instring)
            else:
                # save match among all matches, to retry longest to shortest
                matches.append((loc2, e))

        if matches:
            # re-evaluate all matches in descending order of length of match, in case attached actions
            # might change whether or how much they match of the input.
            matches.sort(key=itemgetter(0), reverse=True)

            if not doActions:
                # no further conditions or parse actions to change the selection of
                # alternative, so the first match will be the best match
                best_expr = matches[0][1]
                return best_expr._parse(instring, loc, doActions)

            longest = -1, None
            for loc1, expr1 in matches:
                if loc1 <= longest[0]:
                    # already have a longer match than this one will deliver, we are done
                    return longest

                try:
                    loc2, toks = expr1._parse(instring, loc, doActions)
                except ParseException as err:
                    err.__traceback__ = None
                    if err.loc > maxExcLoc:
                        maxException = err
                        maxExcLoc = err.loc
                else:
                    if loc2 >= loc1:
                        return loc2, toks
                    # didn't match as much as before
                    elif loc2 > longest[0]:
                        longest = loc2, toks

            if longest != (-1, None):
                return longest

        if fatals:
            if len(fatals) > 1:
                fatals.sort(key=lambda e: -e.loc)
                if fatals[0].loc == fatals[1].loc:
                    fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement))))
            max_fatal = fatals[0]
            raise max_fatal

        if maxException is not None:
            maxException.msg = self.errmsg
            raise maxException
        else:
            raise ParseException(
                instring, loc, "no defined alternatives to match", self
            )

    def __ixor__(self, other):
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        return self.append(other)  # Or([self, other])

    def _generateDefaultName(self):
        return "{" + " ^ ".join(str(e) for e in self.exprs) + "}"

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_multiple_tokens_in_named_alternation
            and Diagnostics.warn_multiple_tokens_in_named_alternation
            not in self.suppress_warnings_
        ):
            if any(
                isinstance(e, And)
                and Diagnostics.warn_multiple_tokens_in_named_alternation
                not in e.suppress_warnings_
                for e in self.exprs
            ):
                warnings.warn(
                    "{}: setting results name {!r} on {} expression "
                    "will return a list of all parsed tokens in an And alternative, "
                    "in prior versions only the first token was returned; enclose "
                    "contained argument in Group".format(
                        "warn_multiple_tokens_in_named_alternation",
                        name,
                        type(self).__name__,
                    ),
                    stacklevel=3,
                )

        return super()._setResultsName(name, listAllMatches)


class MatchFirst(ParseExpression):
    """Requires that at least one :class:`ParseExpression` is found. If
    more than one expression matches, the first one listed is the one that will
    match. May be constructed using the ``'|'`` operator.

    Example::

        # construct MatchFirst using '|' operator

        # watch the order of expressions to match
        number = Word(nums) | Combine(Word(nums) + '.' + Word(nums))
        print(number.search_string("123 3.1416 789")) #  Fail! -> [['123'], ['3'], ['1416'], ['789']]

        # put more selective expression first
        number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums)
        print(number.search_string("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = False):
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.skipWhitespace = all(e.skipWhitespace for e in self.exprs)
        else:
            self.mayReturnEmpty = True

    def streamline(self) -> ParserElement:
        if self.streamlined:
            return self

        super().streamline()
        if self.exprs:
            self.saveAsList = any(e.saveAsList for e in self.exprs)
            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
            self.skipWhitespace = all(
                e.skipWhitespace and not isinstance(e, White) for e in self.exprs
            )
        else:
            self.saveAsList = False
            self.mayReturnEmpty = True
        return self

    def parseImpl(self, instring, loc, doActions=True):
        maxExcLoc = -1
        maxException = None

        for e in self.exprs:
            try:
                return e._parse(
                    instring,
                    loc,
                    doActions,
                )
            except ParseFatalException as pfe:
                pfe.__traceback__ = None
                pfe.parserElement = e
                raise
            except ParseException as err:
                if err.loc > maxExcLoc:
                    maxException = err
                    maxExcLoc = err.loc
            except IndexError:
                if len(instring) > maxExcLoc:
                    maxException = ParseException(
                        instring, len(instring), e.errmsg, self
                    )
                    maxExcLoc = len(instring)

        if maxException is not None:
            maxException.msg = self.errmsg
            raise maxException
        else:
            raise ParseException(
                instring, loc, "no defined alternatives to match", self
            )

    def __ior__(self, other):
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        return self.append(other)  # MatchFirst([self, other])

    def _generateDefaultName(self):
        return "{" + " | ".join(str(e) for e in self.exprs) + "}"

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_multiple_tokens_in_named_alternation
            and Diagnostics.warn_multiple_tokens_in_named_alternation
            not in self.suppress_warnings_
        ):
            if any(
                isinstance(e, And)
                and Diagnostics.warn_multiple_tokens_in_named_alternation
                not in e.suppress_warnings_
                for e in self.exprs
            ):
                warnings.warn(
                    "{}: setting results name {!r} on {} expression "
                    "will return a list of all parsed tokens in an And alternative, "
                    "in prior versions only the first token was returned; enclose "
                    "contained argument in Group".format(
                        "warn_multiple_tokens_in_named_alternation",
                        name,
                        type(self).__name__,
                    ),
                    stacklevel=3,
                )

        return super()._setResultsName(name, listAllMatches)


class Each(ParseExpression):
    """Requires all given :class:`ParseExpression` s to be found, but in
    any order. Expressions may be separated by whitespace.

    May be constructed using the ``'&'`` operator.

    Example::

        color = one_of("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN")
        shape_type = one_of("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON")
        integer = Word(nums)
        shape_attr = "shape:" + shape_type("shape")
        posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn")
        color_attr = "color:" + color("color")
        size_attr = "size:" + integer("size")

        # use Each (using operator '&') to accept attributes in any order
        # (shape and posn are required, color and size are optional)
        shape_spec = shape_attr & posn_attr & Opt(color_attr) & Opt(size_attr)

        shape_spec.run_tests('''
            shape: SQUARE color: BLACK posn: 100, 120
            shape: CIRCLE size: 50 color: BLUE posn: 50,80
            color:GREEN size:20 shape:TRIANGLE posn:20,40
            '''
            )

    prints::

        shape: SQUARE color: BLACK posn: 100, 120
        ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']]
        - color: BLACK
        - posn: ['100', ',', '120']
          - x: 100
          - y: 120
        - shape: SQUARE


        shape: CIRCLE size: 50 color: BLUE posn: 50,80
        ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']]
        - color: BLUE
        - posn: ['50', ',', '80']
          - x: 50
          - y: 80
        - shape: CIRCLE
        - size: 50


        color: GREEN size: 20 shape: TRIANGLE posn: 20,40
        ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']]
        - color: GREEN
        - posn: ['20', ',', '40']
          - x: 20
          - y: 40
        - shape: TRIANGLE
        - size: 20
    """

    def __init__(self, exprs: typing.Iterable[ParserElement], savelist: bool = True):
        super().__init__(exprs, savelist)
        if self.exprs:
            self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
        else:
            self.mayReturnEmpty = True
        self.skipWhitespace = True
        self.initExprGroups = True
        self.saveAsList = True

    def streamline(self) -> ParserElement:
        super().streamline()
        if self.exprs:
            self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
        else:
            self.mayReturnEmpty = True
        return self

    def parseImpl(self, instring, loc, doActions=True):
        if self.initExprGroups:
            self.opt1map = dict(
                (id(e.expr), e) for e in self.exprs if isinstance(e, Opt)
            )
            opt1 = [e.expr for e in self.exprs if isinstance(e, Opt)]
            opt2 = [
                e
                for e in self.exprs
                if e.mayReturnEmpty and not isinstance(e, (Opt, Regex, ZeroOrMore))
            ]
            self.optionals = opt1 + opt2
            self.multioptionals = [
                e.expr.set_results_name(e.resultsName, list_all_matches=True)
                for e in self.exprs
                if isinstance(e, _MultipleMatch)
            ]
            self.multirequired = [
                e.expr.set_results_name(e.resultsName, list_all_matches=True)
                for e in self.exprs
                if isinstance(e, OneOrMore)
            ]
            self.required = [
                e for e in self.exprs if not isinstance(e, (Opt, ZeroOrMore, OneOrMore))
            ]
            self.required += self.multirequired
            self.initExprGroups = False

        tmpLoc = loc
        tmpReqd = self.required[:]
        tmpOpt = self.optionals[:]
        multis = self.multioptionals[:]
        matchOrder = []

        keepMatching = True
        failed = []
        fatals = []
        while keepMatching:
            tmpExprs = tmpReqd + tmpOpt + multis
            failed.clear()
            fatals.clear()
            for e in tmpExprs:
                try:
                    tmpLoc = e.try_parse(instring, tmpLoc, raise_fatal=True)
                except ParseFatalException as pfe:
                    pfe.__traceback__ = None
                    pfe.parserElement = e
                    fatals.append(pfe)
                    failed.append(e)
                except ParseException:
                    failed.append(e)
                else:
                    matchOrder.append(self.opt1map.get(id(e), e))
                    if e in tmpReqd:
                        tmpReqd.remove(e)
                    elif e in tmpOpt:
                        tmpOpt.remove(e)
            if len(failed) == len(tmpExprs):
                keepMatching = False

        # look for any ParseFatalExceptions
        if fatals:
            if len(fatals) > 1:
                fatals.sort(key=lambda e: -e.loc)
                if fatals[0].loc == fatals[1].loc:
                    fatals.sort(key=lambda e: (-e.loc, -len(str(e.parserElement))))
            max_fatal = fatals[0]
            raise max_fatal

        if tmpReqd:
            missing = ", ".join([str(e) for e in tmpReqd])
            raise ParseException(
                instring,
                loc,
                "Missing one or more required elements ({})".format(missing),
            )

        # add any unmatched Opts, in case they have default values defined
        matchOrder += [e for e in self.exprs if isinstance(e, Opt) and e.expr in tmpOpt]

        total_results = ParseResults([])
        for e in matchOrder:
            loc, results = e._parse(instring, loc, doActions)
            total_results += results

        return loc, total_results

    def _generateDefaultName(self):
        return "{" + " & ".join(str(e) for e in self.exprs) + "}"


class ParseElementEnhance(ParserElement):
    """Abstract subclass of :class:`ParserElement`, for combining and
    post-processing parsed tokens.
    """

    def __init__(self, expr: Union[ParserElement, str], savelist: bool = False):
        super().__init__(savelist)
        if isinstance(expr, str_type):
            if issubclass(self._literalStringClass, Token):
                expr = self._literalStringClass(expr)
            elif issubclass(type(self), self._literalStringClass):
                expr = Literal(expr)
            else:
                expr = self._literalStringClass(Literal(expr))
        self.expr = expr
        if expr is not None:
            self.mayIndexError = expr.mayIndexError
            self.mayReturnEmpty = expr.mayReturnEmpty
            self.set_whitespace_chars(
                expr.whiteChars, copy_defaults=expr.copyDefaultWhiteChars
            )
            self.skipWhitespace = expr.skipWhitespace
            self.saveAsList = expr.saveAsList
            self.callPreparse = expr.callPreparse
            self.ignoreExprs.extend(expr.ignoreExprs)

    def recurse(self) -> Sequence[ParserElement]:
        return [self.expr] if self.expr is not None else []

    def parseImpl(self, instring, loc, doActions=True):
        if self.expr is not None:
            return self.expr._parse(instring, loc, doActions, callPreParse=False)
        else:
            raise ParseException(instring, loc, "No expression defined", self)

    def leave_whitespace(self, recursive: bool = True) -> ParserElement:
        super().leave_whitespace(recursive)

        if recursive:
            self.expr = self.expr.copy()
            if self.expr is not None:
                self.expr.leave_whitespace(recursive)
        return self

    def ignore_whitespace(self, recursive: bool = True) -> ParserElement:
        super().ignore_whitespace(recursive)

        if recursive:
            self.expr = self.expr.copy()
            if self.expr is not None:
                self.expr.ignore_whitespace(recursive)
        return self

    def ignore(self, other) -> ParserElement:
        if isinstance(other, Suppress):
            if other not in self.ignoreExprs:
                super().ignore(other)
                if self.expr is not None:
                    self.expr.ignore(self.ignoreExprs[-1])
        else:
            super().ignore(other)
            if self.expr is not None:
                self.expr.ignore(self.ignoreExprs[-1])
        return self

    def streamline(self) -> ParserElement:
        super().streamline()
        if self.expr is not None:
            self.expr.streamline()
        return self

    def _checkRecursion(self, parseElementList):
        if self in parseElementList:
            raise RecursiveGrammarException(parseElementList + [self])
        subRecCheckList = parseElementList[:] + [self]
        if self.expr is not None:
            self.expr._checkRecursion(subRecCheckList)

    def validate(self, validateTrace=None) -> None:
        if validateTrace is None:
            validateTrace = []
        tmp = validateTrace[:] + [self]
        if self.expr is not None:
            self.expr.validate(tmp)
        self._checkRecursion([])

    def _generateDefaultName(self):
        return "{}:({})".format(self.__class__.__name__, str(self.expr))

    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class IndentedBlock(ParseElementEnhance):
    """
    Expression to match one or more expressions at a given indentation level.
    Useful for parsing text where structure is implied by indentation (like Python source code).
    """

    class _Indent(Empty):
        def __init__(self, ref_col: int):
            super().__init__()
            self.errmsg = "expected indent at column {}".format(ref_col)
            self.add_condition(lambda s, l, t: col(l, s) == ref_col)

    class _IndentGreater(Empty):
        def __init__(self, ref_col: int):
            super().__init__()
            self.errmsg = "expected indent at column greater than {}".format(ref_col)
            self.add_condition(lambda s, l, t: col(l, s) > ref_col)

    def __init__(
        self, expr: ParserElement, *, recursive: bool = False, grouped: bool = True
    ):
        super().__init__(expr, savelist=True)
        # if recursive:
        #     raise NotImplementedError("IndentedBlock with recursive is not implemented")
        self._recursive = recursive
        self._grouped = grouped
        self.parent_anchor = 1

    def parseImpl(self, instring, loc, doActions=True):
        # advance parse position to non-whitespace by using an Empty()
        # this should be the column to be used for all subsequent indented lines
        anchor_loc = Empty().preParse(instring, loc)

        # see if self.expr matches at the current location - if not it will raise an exception
        # and no further work is necessary
        self.expr.try_parse(instring, anchor_loc, doActions)

        indent_col = col(anchor_loc, instring)
        peer_detect_expr = self._Indent(indent_col)

        inner_expr = Empty() + peer_detect_expr + self.expr
        if self._recursive:
            sub_indent = self._IndentGreater(indent_col)
            nested_block = IndentedBlock(
                self.expr, recursive=self._recursive, grouped=self._grouped
            )
            nested_block.set_debug(self.debug)
            nested_block.parent_anchor = indent_col
            inner_expr += Opt(sub_indent + nested_block)

        inner_expr.set_name(f"inner {hex(id(inner_expr))[-4:].upper()}@{indent_col}")
        block = OneOrMore(inner_expr)

        trailing_undent = self._Indent(self.parent_anchor) | StringEnd()

        if self._grouped:
            wrapper = Group
        else:
            wrapper = lambda expr: expr
        return (wrapper(block) + Optional(trailing_undent)).parseImpl(
            instring, anchor_loc, doActions
        )


class AtStringStart(ParseElementEnhance):
    """Matches if expression matches at the beginning of the parse
    string::

        AtStringStart(Word(nums)).parse_string("123")
        # prints ["123"]

        AtStringStart(Word(nums)).parse_string("    123")
        # raises ParseException
    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        self.callPreparse = False

    def parseImpl(self, instring, loc, doActions=True):
        if loc != 0:
            raise ParseException(instring, loc, "not found at string start")
        return super().parseImpl(instring, loc, doActions)


class AtLineStart(ParseElementEnhance):
    r"""Matches if an expression matches at the beginning of a line within
    the parse string

    Example::

        test = '''\
        AAA this line
        AAA and this line
          AAA but not this one
        B AAA and definitely not this one
        '''

        for t in (AtLineStart('AAA') + restOfLine).search_string(test):
            print(t)

    prints::

        ['AAA', ' this line']
        ['AAA', ' and this line']

    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        self.callPreparse = False

    def parseImpl(self, instring, loc, doActions=True):
        if col(loc, instring) != 1:
            raise ParseException(instring, loc, "not found at line start")
        return super().parseImpl(instring, loc, doActions)


class FollowedBy(ParseElementEnhance):
    """Lookahead matching of the given parse expression.
    ``FollowedBy`` does *not* advance the parsing position within
    the input string, it only verifies that the specified parse
    expression matches at the current position.  ``FollowedBy``
    always returns a null token list. If any results names are defined
    in the lookahead expression, those *will* be returned for access by
    name.

    Example::

        # use FollowedBy to match a label only if it is followed by a ':'
        data_word = Word(alphas)
        label = data_word + FollowedBy(':')
        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))

        attr_expr[1, ...].parse_string("shape: SQUARE color: BLACK posn: upper left").pprint()

    prints::

        [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']]
    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        self.mayReturnEmpty = True

    def parseImpl(self, instring, loc, doActions=True):
        # by using self._expr.parse and deleting the contents of the returned ParseResults list
        # we keep any named results that were defined in the FollowedBy expression
        _, ret = self.expr._parse(instring, loc, doActions=doActions)
        del ret[:]

        return loc, ret


class PrecededBy(ParseElementEnhance):
    """Lookbehind matching of the given parse expression.
    ``PrecededBy`` does not advance the parsing position within the
    input string, it only verifies that the specified parse expression
    matches prior to the current position.  ``PrecededBy`` always
    returns a null token list, but if a results name is defined on the
    given expression, it is returned.

    Parameters:

    - expr - expression that must match prior to the current parse
      location
    - retreat - (default= ``None``) - (int) maximum number of characters
      to lookbehind prior to the current parse location

    If the lookbehind expression is a string, :class:`Literal`,
    :class:`Keyword`, or a :class:`Word` or :class:`CharsNotIn`
    with a specified exact or maximum length, then the retreat
    parameter is not required. Otherwise, retreat must be specified to
    give a maximum number of characters to look back from
    the current parse position for a lookbehind match.

    Example::

        # VB-style variable names with type prefixes
        int_var = PrecededBy("#") + pyparsing_common.identifier
        str_var = PrecededBy("$") + pyparsing_common.identifier

    """

    def __init__(
        self, expr: Union[ParserElement, str], retreat: typing.Optional[int] = None
    ):
        super().__init__(expr)
        self.expr = self.expr().leave_whitespace()
        self.mayReturnEmpty = True
        self.mayIndexError = False
        self.exact = False
        if isinstance(expr, str_type):
            retreat = len(expr)
            self.exact = True
        elif isinstance(expr, (Literal, Keyword)):
            retreat = expr.matchLen
            self.exact = True
        elif isinstance(expr, (Word, CharsNotIn)) and expr.maxLen != _MAX_INT:
            retreat = expr.maxLen
            self.exact = True
        elif isinstance(expr, PositionToken):
            retreat = 0
            self.exact = True
        self.retreat = retreat
        self.errmsg = "not preceded by " + str(expr)
        self.skipWhitespace = False
        self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None)))

    def parseImpl(self, instring, loc=0, doActions=True):
        if self.exact:
            if loc < self.retreat:
                raise ParseException(instring, loc, self.errmsg)
            start = loc - self.retreat
            _, ret = self.expr._parse(instring, start)
        else:
            # retreat specified a maximum lookbehind window, iterate
            test_expr = self.expr + StringEnd()
            instring_slice = instring[max(0, loc - self.retreat) : loc]
            last_expr = ParseException(instring, loc, self.errmsg)
            for offset in range(1, min(loc, self.retreat + 1) + 1):
                try:
                    # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:]))
                    _, ret = test_expr._parse(
                        instring_slice, len(instring_slice) - offset
                    )
                except ParseBaseException as pbe:
                    last_expr = pbe
                else:
                    break
            else:
                raise last_expr
        return loc, ret


class Located(ParseElementEnhance):
    """
    Decorates a returned token with its starting and ending
    locations in the input string.

    This helper adds the following results names:

    - ``locn_start`` - location where matched expression begins
    - ``locn_end`` - location where matched expression ends
    - ``value`` - the actual parsed results

    Be careful if the input text contains ``<TAB>`` characters, you
    may want to call :class:`ParserElement.parse_with_tabs`

    Example::

        wd = Word(alphas)
        for match in Located(wd).search_string("ljsdf123lksdjjf123lkkjj1222"):
            print(match)

    prints::

        [0, ['ljsdf'], 5]
        [8, ['lksdjjf'], 15]
        [18, ['lkkjj'], 23]

    """

    def parseImpl(self, instring, loc, doActions=True):
        start = loc
        loc, tokens = self.expr._parse(instring, start, doActions, callPreParse=False)
        ret_tokens = ParseResults([start, tokens, loc])
        ret_tokens["locn_start"] = start
        ret_tokens["value"] = tokens
        ret_tokens["locn_end"] = loc
        if self.resultsName:
            # must return as a list, so that the name will be attached to the complete group
            return loc, [ret_tokens]
        else:
            return loc, ret_tokens


class NotAny(ParseElementEnhance):
    """
    Lookahead to disallow matching with the given parse expression.
    ``NotAny`` does *not* advance the parsing position within the
    input string, it only verifies that the specified parse expression
    does *not* match at the current position.  Also, ``NotAny`` does
    *not* skip over leading whitespace. ``NotAny`` always returns
    a null token list.  May be constructed using the ``'~'`` operator.

    Example::

        AND, OR, NOT = map(CaselessKeyword, "AND OR NOT".split())

        # take care not to mistake keywords for identifiers
        ident = ~(AND | OR | NOT) + Word(alphas)
        boolean_term = Opt(NOT) + ident

        # very crude boolean expression - to support parenthesis groups and
        # operation hierarchy, use infix_notation
        boolean_expr = boolean_term + ((AND | OR) + boolean_term)[...]

        # integers that are followed by "." are actually floats
        integer = Word(nums) + ~Char(".")
    """

    def __init__(self, expr: Union[ParserElement, str]):
        super().__init__(expr)
        # do NOT use self.leave_whitespace(), don't want to propagate to exprs
        # self.leave_whitespace()
        self.skipWhitespace = False

        self.mayReturnEmpty = True
        self.errmsg = "Found unwanted token, " + str(self.expr)

    def parseImpl(self, instring, loc, doActions=True):
        if self.expr.can_parse_next(instring, loc):
            raise ParseException(instring, loc, self.errmsg, self)
        return loc, []

    def _generateDefaultName(self):
        return "~{" + str(self.expr) + "}"


class _MultipleMatch(ParseElementEnhance):
    def __init__(
        self,
        expr: ParserElement,
        stop_on: typing.Optional[Union[ParserElement, str]] = None,
        *,
        stopOn: typing.Optional[Union[ParserElement, str]] = None,
    ):
        super().__init__(expr)
        stopOn = stopOn or stop_on
        self.saveAsList = True
        ender = stopOn
        if isinstance(ender, str_type):
            ender = self._literalStringClass(ender)
        self.stopOn(ender)

    def stopOn(self, ender) -> ParserElement:
        if isinstance(ender, str_type):
            ender = self._literalStringClass(ender)
        self.not_ender = ~ender if ender is not None else None
        return self

    def parseImpl(self, instring, loc, doActions=True):
        self_expr_parse = self.expr._parse
        self_skip_ignorables = self._skipIgnorables
        check_ender = self.not_ender is not None
        if check_ender:
            try_not_ender = self.not_ender.tryParse

        # must be at least one (but first see if we are the stopOn sentinel;
        # if so, fail)
        if check_ender:
            try_not_ender(instring, loc)
        loc, tokens = self_expr_parse(instring, loc, doActions)
        try:
            hasIgnoreExprs = not not self.ignoreExprs
            while 1:
                if check_ender:
                    try_not_ender(instring, loc)
                if hasIgnoreExprs:
                    preloc = self_skip_ignorables(instring, loc)
                else:
                    preloc = loc
                loc, tmptokens = self_expr_parse(instring, preloc, doActions)
                if tmptokens or tmptokens.haskeys():
                    tokens += tmptokens
        except (ParseException, IndexError):
            pass

        return loc, tokens

    def _setResultsName(self, name, listAllMatches=False):
        if (
            __diag__.warn_ungrouped_named_tokens_in_collection
            and Diagnostics.warn_ungrouped_named_tokens_in_collection
            not in self.suppress_warnings_
        ):
            for e in [self.expr] + self.expr.recurse():
                if (
                    isinstance(e, ParserElement)
                    and e.resultsName
                    and Diagnostics.warn_ungrouped_named_tokens_in_collection
                    not in e.suppress_warnings_
                ):
                    warnings.warn(
                        "{}: setting results name {!r} on {} expression "
                        "collides with {!r} on contained expression".format(
                            "warn_ungrouped_named_tokens_in_collection",
                            name,
                            type(self).__name__,
                            e.resultsName,
                        ),
                        stacklevel=3,
                    )

        return super()._setResultsName(name, listAllMatches)


class OneOrMore(_MultipleMatch):
    """
    Repetition of one or more of the given expression.

    Parameters:
    - expr - expression that must match one or more times
    - stop_on - (default= ``None``) - expression for a terminating sentinel
         (only required if the sentinel would ordinarily match the repetition
         expression)

    Example::

        data_word = Word(alphas)
        label = data_word + FollowedBy(':')
        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).set_parse_action(' '.join))

        text = "shape: SQUARE posn: upper left color: BLACK"
        attr_expr[1, ...].parse_string(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]

        # use stop_on attribute for OneOrMore to avoid reading label string as part of the data
        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))
        OneOrMore(attr_expr).parse_string(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]

        # could also be written as
        (attr_expr * (1,)).parse_string(text).pprint()
    """

    def _generateDefaultName(self):
        return "{" + str(self.expr) + "}..."


class ZeroOrMore(_MultipleMatch):
    """
    Optional repetition of zero or more of the given expression.

    Parameters:
    - ``expr`` - expression that must match zero or more times
    - ``stop_on`` - expression for a terminating sentinel
      (only required if the sentinel would ordinarily match the repetition
      expression) - (default= ``None``)

    Example: similar to :class:`OneOrMore`
    """

    def __init__(
        self,
        expr: ParserElement,
        stop_on: typing.Optional[Union[ParserElement, str]] = None,
        *,
        stopOn: typing.Optional[Union[ParserElement, str]] = None,
    ):
        super().__init__(expr, stopOn=stopOn or stop_on)
        self.mayReturnEmpty = True

    def parseImpl(self, instring, loc, doActions=True):
        try:
            return super().parseImpl(instring, loc, doActions)
        except (ParseException, IndexError):
            return loc, ParseResults([], name=self.resultsName)

    def _generateDefaultName(self):
        return "[" + str(self.expr) + "]..."


class _NullToken:
    def __bool__(self):
        return False

    def __str__(self):
        return ""


class Opt(ParseElementEnhance):
    """
    Optional matching of the given expression.

    Parameters:
    - ``expr`` - expression that must match zero or more times
    - ``default`` (optional) - value to be returned if the optional expression is not found.

    Example::

        # US postal code can be a 5-digit zip, plus optional 4-digit qualifier
        zip = Combine(Word(nums, exact=5) + Opt('-' + Word(nums, exact=4)))
        zip.run_tests('''
            # traditional ZIP code
            12345

            # ZIP+4 form
            12101-0001

            # invalid ZIP
            98765-
            ''')

    prints::

        # traditional ZIP code
        12345
        ['12345']

        # ZIP+4 form
        12101-0001
        ['12101-0001']

        # invalid ZIP
        98765-
             ^
        FAIL: Expected end of text (at char 5), (line:1, col:6)
    """

    __optionalNotMatched = _NullToken()

    def __init__(
        self, expr: Union[ParserElement, str], default: Any = __optionalNotMatched
    ):
        super().__init__(expr, savelist=False)
        self.saveAsList = self.expr.saveAsList
        self.defaultValue = default
        self.mayReturnEmpty = True

    def parseImpl(self, instring, loc, doActions=True):
        self_expr = self.expr
        try:
            loc, tokens = self_expr._parse(instring, loc, doActions, callPreParse=False)
        except (ParseException, IndexError):
            default_value = self.defaultValue
            if default_value is not self.__optionalNotMatched:
                if self_expr.resultsName:
                    tokens = ParseResults([default_value])
                    tokens[self_expr.resultsName] = default_value
                else:
                    tokens = [default_value]
            else:
                tokens = []
        return loc, tokens

    def _generateDefaultName(self):
        inner = str(self.expr)
        # strip off redundant inner {}'s
        while len(inner) > 1 and inner[0 :: len(inner) - 1] == "{}":
            inner = inner[1:-1]
        return "[" + inner + "]"


Optional = Opt


class SkipTo(ParseElementEnhance):
    """
    Token for skipping over all undefined text until the matched
    expression is found.

    Parameters:
    - ``expr`` - target expression marking the end of the data to be skipped
    - ``include`` - if ``True``, the target expression is also parsed
      (the skipped text and target expression are returned as a 2-element
      list) (default= ``False``).
    - ``ignore`` - (default= ``None``) used to define grammars (typically quoted strings and
      comments) that might contain false matches to the target expression
    - ``fail_on`` - (default= ``None``) define expressions that are not allowed to be
      included in the skipped test; if found before the target expression is found,
      the :class:`SkipTo` is not a match

    Example::

        report = '''
            Outstanding Issues Report - 1 Jan 2000

               # | Severity | Description                               |  Days Open
            -----+----------+-------------------------------------------+-----------
             101 | Critical | Intermittent system crash                 |          6
              94 | Cosmetic | Spelling error on Login ('log|n')         |         14
              79 | Minor    | System slow when running too many reports |         47
            '''
        integer = Word(nums)
        SEP = Suppress('|')
        # use SkipTo to simply match everything up until the next SEP
        # - ignore quoted strings, so that a '|' character inside a quoted string does not match
        # - parse action will call token.strip() for each matched token, i.e., the description body
        string_data = SkipTo(SEP, ignore=quoted_string)
        string_data.set_parse_action(token_map(str.strip))
        ticket_expr = (integer("issue_num") + SEP
                      + string_data("sev") + SEP
                      + string_data("desc") + SEP
                      + integer("days_open"))

        for tkt in ticket_expr.search_string(report):
            print tkt.dump()

    prints::

        ['101', 'Critical', 'Intermittent system crash', '6']
        - days_open: '6'
        - desc: 'Intermittent system crash'
        - issue_num: '101'
        - sev: 'Critical'
        ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14']
        - days_open: '14'
        - desc: "Spelling error on Login ('log|n')"
        - issue_num: '94'
        - sev: 'Cosmetic'
        ['79', 'Minor', 'System slow when running too many reports', '47']
        - days_open: '47'
        - desc: 'System slow when running too many reports'
        - issue_num: '79'
        - sev: 'Minor'
    """

    def __init__(
        self,
        other: Union[ParserElement, str],
        include: bool = False,
        ignore: bool = None,
        fail_on: typing.Optional[Union[ParserElement, str]] = None,
        *,
        failOn: Union[ParserElement, str] = None,
    ):
        super().__init__(other)
        failOn = failOn or fail_on
        self.ignoreExpr = ignore
        self.mayReturnEmpty = True
        self.mayIndexError = False
        self.includeMatch = include
        self.saveAsList = False
        if isinstance(failOn, str_type):
            self.failOn = self._literalStringClass(failOn)
        else:
            self.failOn = failOn
        self.errmsg = "No match found for " + str(self.expr)

    def parseImpl(self, instring, loc, doActions=True):
        startloc = loc
        instrlen = len(instring)
        self_expr_parse = self.expr._parse
        self_failOn_canParseNext = (
            self.failOn.canParseNext if self.failOn is not None else None
        )
        self_ignoreExpr_tryParse = (
            self.ignoreExpr.tryParse if self.ignoreExpr is not None else None
        )

        tmploc = loc
        while tmploc <= instrlen:
            if self_failOn_canParseNext is not None:
                # break if failOn expression matches
                if self_failOn_canParseNext(instring, tmploc):
                    break

            if self_ignoreExpr_tryParse is not None:
                # advance past ignore expressions
                while 1:
                    try:
                        tmploc = self_ignoreExpr_tryParse(instring, tmploc)
                    except ParseBaseException:
                        break

            try:
                self_expr_parse(instring, tmploc, doActions=False, callPreParse=False)
            except (ParseException, IndexError):
                # no match, advance loc in string
                tmploc += 1
            else:
                # matched skipto expr, done
                break

        else:
            # ran off the end of the input string without matching skipto expr, fail
            raise ParseException(instring, loc, self.errmsg, self)

        # build up return values
        loc = tmploc
        skiptext = instring[startloc:loc]
        skipresult = ParseResults(skiptext)

        if self.includeMatch:
            loc, mat = self_expr_parse(instring, loc, doActions, callPreParse=False)
            skipresult += mat

        return loc, skipresult


class Forward(ParseElementEnhance):
    """
    Forward declaration of an expression to be defined later -
    used for recursive grammars, such as algebraic infix notation.
    When the expression is known, it is assigned to the ``Forward``
    variable using the ``'<<'`` operator.

    Note: take care when assigning to ``Forward`` not to overlook
    precedence of operators.

    Specifically, ``'|'`` has a lower precedence than ``'<<'``, so that::

        fwd_expr << a | b | c

    will actually be evaluated as::

        (fwd_expr << a) | b | c

    thereby leaving b and c out as parseable alternatives.  It is recommended that you
    explicitly group the values inserted into the ``Forward``::

        fwd_expr << (a | b | c)

    Converting to use the ``'<<='`` operator instead will avoid this problem.

    See :class:`ParseResults.pprint` for an example of a recursive
    parser created using ``Forward``.
    """

    def __init__(self, other: typing.Optional[Union[ParserElement, str]] = None):
        self.caller_frame = traceback.extract_stack(limit=2)[0]
        super().__init__(other, savelist=False)
        self.lshift_line = None

    def __lshift__(self, other):
        if hasattr(self, "caller_frame"):
            del self.caller_frame
        if isinstance(other, str_type):
            other = self._literalStringClass(other)
        self.expr = other
        self.mayIndexError = self.expr.mayIndexError
        self.mayReturnEmpty = self.expr.mayReturnEmpty
        self.set_whitespace_chars(
            self.expr.whiteChars, copy_defaults=self.expr.copyDefaultWhiteChars
        )
        self.skipWhitespace = self.expr.skipWhitespace
        self.saveAsList = self.expr.saveAsList
        self.ignoreExprs.extend(self.expr.ignoreExprs)
        self.lshift_line = traceback.extract_stack(limit=2)[-2]
        return self

    def __ilshift__(self, other):
        return self << other

    def __or__(self, other):
        caller_line = traceback.extract_stack(limit=2)[-2]
        if (
            __diag__.warn_on_match_first_with_lshift_operator
            and caller_line == self.lshift_line
            and Diagnostics.warn_on_match_first_with_lshift_operator
            not in self.suppress_warnings_
        ):
            warnings.warn(
                "using '<<' operator with '|' is probably an error, use '<<='",
                stacklevel=2,
            )
        ret = super().__or__(other)
        return ret

    def __del__(self):
        # see if we are getting dropped because of '=' reassignment of var instead of '<<=' or '<<'
        if (
            self.expr is None
            and __diag__.warn_on_assignment_to_Forward
            and Diagnostics.warn_on_assignment_to_Forward not in self.suppress_warnings_
        ):
            warnings.warn_explicit(
                "Forward defined here but no expression attached later using '<<=' or '<<'",
                UserWarning,
                filename=self.caller_frame.filename,
                lineno=self.caller_frame.lineno,
            )

    def parseImpl(self, instring, loc, doActions=True):
        if (
            self.expr is None
            and __diag__.warn_on_parse_using_empty_Forward
            and Diagnostics.warn_on_parse_using_empty_Forward
            not in self.suppress_warnings_
        ):
            # walk stack until parse_string, scan_string, search_string, or transform_string is found
            parse_fns = [
                "parse_string",
                "scan_string",
                "search_string",
                "transform_string",
            ]
            tb = traceback.extract_stack(limit=200)
            for i, frm in enumerate(reversed(tb), start=1):
                if frm.name in parse_fns:
                    stacklevel = i + 1
                    break
            else:
                stacklevel = 2
            warnings.warn(
                "Forward expression was never assigned a value, will not parse any input",
                stacklevel=stacklevel,
            )
        if not ParserElement._left_recursion_enabled:
            return super().parseImpl(instring, loc, doActions)
        # ## Bounded Recursion algorithm ##
        # Recursion only needs to be processed at ``Forward`` elements, since they are
        # the only ones that can actually refer to themselves. The general idea is
        # to handle recursion stepwise: We start at no recursion, then recurse once,
        # recurse twice, ..., until more recursion offers no benefit (we hit the bound).
        #
        # The "trick" here is that each ``Forward`` gets evaluated in two contexts
        # - to *match* a specific recursion level, and
        # - to *search* the bounded recursion level
        # and the two run concurrently. The *search* must *match* each recursion level
        # to find the best possible match. This is handled by a memo table, which
        # provides the previous match to the next level match attempt.
        #
        # See also "Left Recursion in Parsing Expression Grammars", Medeiros et al.
        #
        # There is a complication since we not only *parse* but also *transform* via
        # actions: We do not want to run the actions too often while expanding. Thus,
        # we expand using `doActions=False` and only run `doActions=True` if the next
        # recursion level is acceptable.
        with ParserElement.recursion_lock:
            memo = ParserElement.recursion_memos
            try:
                # we are parsing at a specific recursion expansion - use it as-is
                prev_loc, prev_result = memo[loc, self, doActions]
                if isinstance(prev_result, Exception):
                    raise prev_result
                return prev_loc, prev_result.copy()
            except KeyError:
                act_key = (loc, self, True)
                peek_key = (loc, self, False)
                # we are searching for the best recursion expansion - keep on improving
                # both `doActions` cases must be tracked separately here!
                prev_loc, prev_peek = memo[peek_key] = (
                    loc - 1,
                    ParseException(
                        instring, loc, "Forward recursion without base case", self
                    ),
                )
                if doActions:
                    memo[act_key] = memo[peek_key]
                while True:
                    try:
                        new_loc, new_peek = super().parseImpl(instring, loc, False)
                    except ParseException:
                        # we failed before getting any match – do not hide the error
                        if isinstance(prev_peek, Exception):
                            raise
                        new_loc, new_peek = prev_loc, prev_peek
                    # the match did not get better: we are done
                    if new_loc <= prev_loc:
                        if doActions:
                            # replace the match for doActions=False as well,
                            # in case the action did backtrack
                            prev_loc, prev_result = memo[peek_key] = memo[act_key]
                            del memo[peek_key], memo[act_key]
                            return prev_loc, prev_result.copy()
                        del memo[peek_key]
                        return prev_loc, prev_peek.copy()
                    # the match did get better: see if we can improve further
                    else:
                        if doActions:
                            try:
                                memo[act_key] = super().parseImpl(instring, loc, True)
                            except ParseException as e:
                                memo[peek_key] = memo[act_key] = (new_loc, e)
                                raise
                        prev_loc, prev_peek = memo[peek_key] = new_loc, new_peek

    def leave_whitespace(self, recursive: bool = True) -> ParserElement:
        self.skipWhitespace = False
        return self

    def ignore_whitespace(self, recursive: bool = True) -> ParserElement:
        self.skipWhitespace = True
        return self

    def streamline(self) -> ParserElement:
        if not self.streamlined:
            self.streamlined = True
            if self.expr is not None:
                self.expr.streamline()
        return self

    def validate(self, validateTrace=None) -> None:
        if validateTrace is None:
            validateTrace = []

        if self not in validateTrace:
            tmp = validateTrace[:] + [self]
            if self.expr is not None:
                self.expr.validate(tmp)
        self._checkRecursion([])

    def _generateDefaultName(self):
        # Avoid infinite recursion by setting a temporary _defaultName
        self._defaultName = ": ..."

        # Use the string representation of main expression.
        retString = "..."
        try:
            if self.expr is not None:
                retString = str(self.expr)[:1000]
            else:
                retString = "None"
        finally:
            return self.__class__.__name__ + ": " + retString

    def copy(self) -> ParserElement:
        if self.expr is not None:
            return super().copy()
        else:
            ret = Forward()
            ret <<= self
            return ret

    def _setResultsName(self, name, list_all_matches=False):
        if (
            __diag__.warn_name_set_on_empty_Forward
            and Diagnostics.warn_name_set_on_empty_Forward
            not in self.suppress_warnings_
        ):
            if self.expr is None:
                warnings.warn(
                    "{}: setting results name {!r} on {} expression "
                    "that has no contained expression".format(
                        "warn_name_set_on_empty_Forward", name, type(self).__name__
                    ),
                    stacklevel=3,
                )

        return super()._setResultsName(name, list_all_matches)

    ignoreWhitespace = ignore_whitespace
    leaveWhitespace = leave_whitespace


class TokenConverter(ParseElementEnhance):
    """
    Abstract subclass of :class:`ParseExpression`, for converting parsed results.
    """

    def __init__(self, expr: Union[ParserElement, str], savelist=False):
        super().__init__(expr)  # , savelist)
        self.saveAsList = False


class Combine(TokenConverter):
    """Converter to concatenate all matching tokens to a single string.
    By default, the matching patterns must also be contiguous in the
    input string; this can be disabled by specifying
    ``'adjacent=False'`` in the constructor.

    Example::

        real = Word(nums) + '.' + Word(nums)
        print(real.parse_string('3.1416')) # -> ['3', '.', '1416']
        # will also erroneously match the following
        print(real.parse_string('3. 1416')) # -> ['3', '.', '1416']

        real = Combine(Word(nums) + '.' + Word(nums))
        print(real.parse_string('3.1416')) # -> ['3.1416']
        # no match when there are internal spaces
        print(real.parse_string('3. 1416')) # -> Exception: Expected W:(0123...)
    """

    def __init__(
        self,
        expr: ParserElement,
        join_string: str = "",
        adjacent: bool = True,
        *,
        joinString: typing.Optional[str] = None,
    ):
        super().__init__(expr)
        joinString = joinString if joinString is not None else join_string
        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
        if adjacent:
            self.leave_whitespace()
        self.adjacent = adjacent
        self.skipWhitespace = True
        self.joinString = joinString
        self.callPreparse = True

    def ignore(self, other) -> ParserElement:
        if self.adjacent:
            ParserElement.ignore(self, other)
        else:
            super().ignore(other)
        return self

    def postParse(self, instring, loc, tokenlist):
        retToks = tokenlist.copy()
        del retToks[:]
        retToks += ParseResults(
            ["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults
        )

        if self.resultsName and retToks.haskeys():
            return [retToks]
        else:
            return retToks


class Group(TokenConverter):
    """Converter to return the matched tokens as a list - useful for
    returning tokens of :class:`ZeroOrMore` and :class:`OneOrMore` expressions.

    The optional ``aslist`` argument when set to True will return the
    parsed tokens as a Python list instead of a pyparsing ParseResults.

    Example::

        ident = Word(alphas)
        num = Word(nums)
        term = ident | num
        func = ident + Opt(delimited_list(term))
        print(func.parse_string("fn a, b, 100"))
        # -> ['fn', 'a', 'b', '100']

        func = ident + Group(Opt(delimited_list(term)))
        print(func.parse_string("fn a, b, 100"))
        # -> ['fn', ['a', 'b', '100']]
    """

    def __init__(self, expr: ParserElement, aslist: bool = False):
        super().__init__(expr)
        self.saveAsList = True
        self._asPythonList = aslist

    def postParse(self, instring, loc, tokenlist):
        if self._asPythonList:
            return ParseResults.List(
                tokenlist.asList()
                if isinstance(tokenlist, ParseResults)
                else list(tokenlist)
            )
        else:
            return [tokenlist]


class Dict(TokenConverter):
    """Converter to return a repetitive expression as a list, but also
    as a dictionary. Each element can also be referenced using the first
    token in the expression as its key. Useful for tabular report
    scraping when the first column can be used as a item key.

    The optional ``asdict`` argument when set to True will return the
    parsed tokens as a Python dict instead of a pyparsing ParseResults.

    Example::

        data_word = Word(alphas)
        label = data_word + FollowedBy(':')

        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stop_on=label).set_parse_action(' '.join))

        # print attributes as plain groups
        print(attr_expr[1, ...].parse_string(text).dump())

        # instead of OneOrMore(expr), parse using Dict(Group(expr)[1, ...]) - Dict will auto-assign names
        result = Dict(Group(attr_expr)[1, ...]).parse_string(text)
        print(result.dump())

        # access named fields as dict entries, or output as dict
        print(result['shape'])
        print(result.as_dict())

    prints::

        ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap']
        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
        - color: 'light blue'
        - posn: 'upper left'
        - shape: 'SQUARE'
        - texture: 'burlap'
        SQUARE
        {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'}

    See more examples at :class:`ParseResults` of accessing fields by results name.
    """

    def __init__(self, expr: ParserElement, asdict: bool = False):
        super().__init__(expr)
        self.saveAsList = True
        self._asPythonDict = asdict

    def postParse(self, instring, loc, tokenlist):
        for i, tok in enumerate(tokenlist):
            if len(tok) == 0:
                continue

            ikey = tok[0]
            if isinstance(ikey, int):
                ikey = str(ikey).strip()

            if len(tok) == 1:
                tokenlist[ikey] = _ParseResultsWithOffset("", i)

            elif len(tok) == 2 and not isinstance(tok[1], ParseResults):
                tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i)

            else:
                try:
                    dictvalue = tok.copy()  # ParseResults(i)
                except Exception:
                    exc = TypeError(
                        "could not extract dict values from parsed results"
                        " - Dict expression must contain Grouped expressions"
                    )
                    raise exc from None

                del dictvalue[0]

                if len(dictvalue) != 1 or (
                    isinstance(dictvalue, ParseResults) and dictvalue.haskeys()
                ):
                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i)
                else:
                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i)

        if self._asPythonDict:
            return [tokenlist.as_dict()] if self.resultsName else tokenlist.as_dict()
        else:
            return [tokenlist] if self.resultsName else tokenlist


class Suppress(TokenConverter):
    """Converter for ignoring the results of a parsed expression.

    Example::

        source = "a, b, c,d"
        wd = Word(alphas)
        wd_list1 = wd + (',' + wd)[...]
        print(wd_list1.parse_string(source))

        # often, delimiters that are useful during parsing are just in the
        # way afterward - use Suppress to keep them out of the parsed output
        wd_list2 = wd + (Suppress(',') + wd)[...]
        print(wd_list2.parse_string(source))

        # Skipped text (using '...') can be suppressed as well
        source = "lead in START relevant text END trailing text"
        start_marker = Keyword("START")
        end_marker = Keyword("END")
        find_body = Suppress(...) + start_marker + ... + end_marker
        print(find_body.parse_string(source)

    prints::

        ['a', ',', 'b', ',', 'c', ',', 'd']
        ['a', 'b', 'c', 'd']
        ['START', 'relevant text ', 'END']

    (See also :class:`delimited_list`.)
    """

    def __init__(self, expr: Union[ParserElement, str], savelist: bool = False):
        if expr is ...:
            expr = _PendingSkip(NoMatch())
        super().__init__(expr)

    def __add__(self, other) -> "ParserElement":
        if isinstance(self.expr, _PendingSkip):
            return Suppress(SkipTo(other)) + other
        else:
            return super().__add__(other)

    def __sub__(self, other) -> "ParserElement":
        if isinstance(self.expr, _PendingSkip):
            return Suppress(SkipTo(other)) - other
        else:
            return super().__sub__(other)

    def postParse(self, instring, loc, tokenlist):
        return []

    def suppress(self) -> ParserElement:
        return self


def trace_parse_action(f: ParseAction) -> ParseAction:
    """Decorator for debugging parse actions.

    When the parse action is called, this decorator will print
    ``">> entering method-name(line:<current_source_line>, <parse_location>, <matched_tokens>)"``.
    When the parse action completes, the decorator will print
    ``"<<"`` followed by the returned value, or any exception that the parse action raised.

    Example::

        wd = Word(alphas)

        @trace_parse_action
        def remove_duplicate_chars(tokens):
            return ''.join(sorted(set(''.join(tokens))))

        wds = wd[1, ...].set_parse_action(remove_duplicate_chars)
        print(wds.parse_string("slkdjs sld sldd sdlf sdljf"))

    prints::

        >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {}))
        <<leaving remove_duplicate_chars (ret: 'dfjkls')
        ['dfjkls']
    """
    f = _trim_arity(f)

    def z(*paArgs):
        thisFunc = f.__name__
        s, l, t = paArgs[-3:]
        if len(paArgs) > 3:
            thisFunc = paArgs[0].__class__.__name__ + "." + thisFunc
        sys.stderr.write(
            ">>entering {}(line: {!r}, {}, {!r})\n".format(thisFunc, line(l, s), l, t)
        )
        try:
            ret = f(*paArgs)
        except Exception as exc:
            sys.stderr.write("<<leaving {} (exception: {})\n".format(thisFunc, exc))
            raise
        sys.stderr.write("<<leaving {} (ret: {!r})\n".format(thisFunc, ret))
        return ret

    z.__name__ = f.__name__
    return z


# convenience constants for positional expressions
empty = Empty().set_name("empty")
line_start = LineStart().set_name("line_start")
line_end = LineEnd().set_name("line_end")
string_start = StringStart().set_name("string_start")
string_end = StringEnd().set_name("string_end")

_escapedPunc = Word(_bslash, r"\[]-*.$+^?()~ ", exact=2).set_parse_action(
    lambda s, l, t: t[0][1]
)
_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").set_parse_action(
    lambda s, l, t: chr(int(t[0].lstrip(r"\0x"), 16))
)
_escapedOctChar = Regex(r"\\0[0-7]+").set_parse_action(
    lambda s, l, t: chr(int(t[0][1:], 8))
)
_singleChar = (
    _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r"\]", exact=1)
)
_charRange = Group(_singleChar + Suppress("-") + _singleChar)
_reBracketExpr = (
    Literal("[")
    + Opt("^").set_results_name("negate")
    + Group(OneOrMore(_charRange | _singleChar)).set_results_name("body")
    + "]"
)


def srange(s: str) -> str:
    r"""Helper to easily define string ranges for use in :class:`Word`
    construction. Borrows syntax from regexp ``'[]'`` string range
    definitions::

        srange("[0-9]")   -> "0123456789"
        srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
        srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"

    The input string must be enclosed in []'s, and the returned string
    is the expanded character set joined into a single string. The
    values enclosed in the []'s may be:

    - a single character
    - an escaped character with a leading backslash (such as ``\-``
      or ``\]``)
    - an escaped hex character with a leading ``'\x'``
      (``\x21``, which is a ``'!'`` character) (``\0x##``
      is also supported for backwards compatibility)
    - an escaped octal character with a leading ``'\0'``
      (``\041``, which is a ``'!'`` character)
    - a range of any of the above, separated by a dash (``'a-z'``,
      etc.)
    - any combination of the above (``'aeiouy'``,
      ``'a-zA-Z0-9_$'``, etc.)
    """
    _expanded = (
        lambda p: p
        if not isinstance(p, ParseResults)
        else "".join(chr(c) for c in range(ord(p[0]), ord(p[1]) + 1))
    )
    try:
        return "".join(_expanded(part) for part in _reBracketExpr.parse_string(s).body)
    except Exception:
        return ""


def token_map(func, *args) -> ParseAction:
    """Helper to define a parse action by mapping a function to all
    elements of a :class:`ParseResults` list. If any additional args are passed,
    they are forwarded to the given function as additional arguments
    after the token, as in
    ``hex_integer = Word(hexnums).set_parse_action(token_map(int, 16))``,
    which will convert the parsed data to an integer using base 16.

    Example (compare the last to example in :class:`ParserElement.transform_string`::

        hex_ints = Word(hexnums)[1, ...].set_parse_action(token_map(int, 16))
        hex_ints.run_tests('''
            00 11 22 aa FF 0a 0d 1a
            ''')

        upperword = Word(alphas).set_parse_action(token_map(str.upper))
        upperword[1, ...].run_tests('''
            my kingdom for a horse
            ''')

        wd = Word(alphas).set_parse_action(token_map(str.title))
        wd[1, ...].set_parse_action(' '.join).run_tests('''
            now is the winter of our discontent made glorious summer by this sun of york
            ''')

    prints::

        00 11 22 aa FF 0a 0d 1a
        [0, 17, 34, 170, 255, 10, 13, 26]

        my kingdom for a horse
        ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE']

        now is the winter of our discontent made glorious summer by this sun of york
        ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York']
    """

    def pa(s, l, t):
        return [func(tokn, *args) for tokn in t]

    func_name = getattr(func, "__name__", getattr(func, "__class__").__name__)
    pa.__name__ = func_name

    return pa


def autoname_elements() -> None:
    """
    Utility to simplify mass-naming of parser elements, for
    generating railroad diagram with named subdiagrams.
    """
    for name, var in sys._getframe().f_back.f_locals.items():
        if isinstance(var, ParserElement) and not var.customName:
            var.set_name(name)


dbl_quoted_string = Combine(
    Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"'
).set_name("string enclosed in double quotes")

sgl_quoted_string = Combine(
    Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'"
).set_name("string enclosed in single quotes")

quoted_string = Combine(
    Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"'
    | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'"
).set_name("quotedString using single or double quotes")

unicode_string = Combine("u" + quoted_string.copy()).set_name("unicode string literal")


alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")

# build list of built-in expressions, for future reference if a global default value
# gets updated
_builtin_exprs: List[ParserElement] = [
    v for v in vars().values() if isinstance(v, ParserElement)
]

# backward compatibility names
tokenMap = token_map
conditionAsParseAction = condition_as_parse_action
nullDebugAction = null_debug_action
sglQuotedString = sgl_quoted_string
dblQuotedString = dbl_quoted_string
quotedString = quoted_string
unicodeString = unicode_string
lineStart = line_start
lineEnd = line_end
stringStart = string_start
stringEnd = string_end
traceParseAction = trace_parse_action
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  # -*- coding: utf-8 -*-
"""Small, fast HTTP client library for Python."""

__author__ = "Joe Gregorio (joe@bitworking.org)"
__copyright__ = "Copyright 2006, Joe Gregorio"
__contributors__ = [
    "Thomas Broyer (t.broyer@ltgt.net)",
    "James Antill",
    "Xavier Verges Farrero",
    "Jonathan Feinberg",
    "Blair Zajac",
    "Sam Ruby",
    "Louis Nyffenegger",
    "Mark Pilgrim",
    "Alex Yu",
]
__license__ = "MIT"
__version__ = "0.20.4"

import base64
import calendar
import copy
import email
import email.feedparser
from email import header
import email.message
import email.utils
import errno
from gettext import gettext as _
import gzip
from hashlib import md5 as _md5
from hashlib import sha1 as _sha
import hmac
import http.client
import io
import os
import random
import re
import socket
import ssl
import sys
import time
import urllib.parse
import zlib

try:
    import socks
except ImportError:
    # TODO: remove this fallback and copypasted socksipy module upon py2/3 merge,
    # idea is to have soft-dependency on any compatible module called socks
    from . import socks
from . import auth
from .error import *
from .iri2uri import iri2uri


def has_timeout(timeout):
    if hasattr(socket, "_GLOBAL_DEFAULT_TIMEOUT"):
        return timeout is not None and timeout is not socket._GLOBAL_DEFAULT_TIMEOUT
    return timeout is not None


__all__ = [
    "debuglevel",
    "FailedToDecompressContent",
    "Http",
    "HttpLib2Error",
    "ProxyInfo",
    "RedirectLimit",
    "RedirectMissingLocation",
    "Response",
    "RETRIES",
    "UnimplementedDigestAuthOptionError",
    "UnimplementedHmacDigestAuthOptionError",
]

# The httplib debug level, set to a non-zero value to get debug output
debuglevel = 0

# A request will be tried 'RETRIES' times if it fails at the socket/connection level.
RETRIES = 2


# Open Items:
# -----------

# Are we removing the cached content too soon on PUT (only delete on 200 Maybe?)

# Pluggable cache storage (supports storing the cache in
#   flat files by default. We need a plug-in architecture
#   that can support Berkeley DB and Squid)

# == Known Issues ==
# Does not handle a resource that uses conneg and Last-Modified but no ETag as a cache validator.
# Does not handle Cache-Control: max-stale
# Does not use Age: headers when calculating cache freshness.

# The number of redirections to follow before giving up.
# Note that only GET redirects are automatically followed.
# Will also honor 301 requests by saving that info and never
# requesting that URI again.
DEFAULT_MAX_REDIRECTS = 5

# Which headers are hop-by-hop headers by default
HOP_BY_HOP = [
    "connection",
    "keep-alive",
    "proxy-authenticate",
    "proxy-authorization",
    "te",
    "trailers",
    "transfer-encoding",
    "upgrade",
]

# https://tools.ietf.org/html/rfc7231#section-8.1.3
SAFE_METHODS = ("GET", "HEAD", "OPTIONS", "TRACE")

# To change, assign to `Http().redirect_codes`
REDIRECT_CODES = frozenset((300, 301, 302, 303, 307, 308))


from httplib2 import certs

CA_CERTS = certs.where()

# PROTOCOL_TLS is python 3.5.3+. PROTOCOL_SSLv23 is deprecated.
# Both PROTOCOL_TLS and PROTOCOL_SSLv23 are equivalent and means:
# > Selects the highest protocol version that both the client and server support.
# > Despite the name, this option can select “TLS” protocols as well as “SSL”.
# source: https://docs.python.org/3.5/library/ssl.html#ssl.PROTOCOL_TLS
DEFAULT_TLS_VERSION = getattr(ssl, "PROTOCOL_TLS", None) or getattr(ssl, "PROTOCOL_SSLv23")


def _build_ssl_context(
    disable_ssl_certificate_validation,
    ca_certs,
    cert_file=None,
    key_file=None,
    maximum_version=None,
    minimum_version=None,
    key_password=None,
):
    if not hasattr(ssl, "SSLContext"):
        raise RuntimeError("httplib2 requires Python 3.2+ for ssl.SSLContext")

    context = ssl.SSLContext(DEFAULT_TLS_VERSION)
    context.verify_mode = ssl.CERT_NONE if disable_ssl_certificate_validation else ssl.CERT_REQUIRED

    # SSLContext.maximum_version and SSLContext.minimum_version are python 3.7+.
    # source: https://docs.python.org/3/library/ssl.html#ssl.SSLContext.maximum_version
    if maximum_version is not None:
        if hasattr(context, "maximum_version"):
            if isinstance(maximum_version, str):
                maximum_version = getattr(ssl.TLSVersion, maximum_version)
            context.maximum_version = maximum_version
        else:
            raise RuntimeError("setting tls_maximum_version requires Python 3.7 and OpenSSL 1.1 or newer")
    if minimum_version is not None:
        if hasattr(context, "minimum_version"):
            if isinstance(minimum_version, str):
                minimum_version = getattr(ssl.TLSVersion, minimum_version)
            context.minimum_version = minimum_version
        else:
            raise RuntimeError("setting tls_minimum_version requires Python 3.7 and OpenSSL 1.1 or newer")
    # check_hostname requires python 3.4+
    # we will perform the equivalent in HTTPSConnectionWithTimeout.connect() by calling ssl.match_hostname
    # if check_hostname is not supported.
    if hasattr(context, "check_hostname"):
        context.check_hostname = not disable_ssl_certificate_validation

    context.load_verify_locations(ca_certs)

    if cert_file:
        context.load_cert_chain(cert_file, key_file, key_password)

    return context


def _get_end2end_headers(response):
    hopbyhop = list(HOP_BY_HOP)
    hopbyhop.extend([x.strip() for x in response.get("connection", "").split(",")])
    return [header for header in list(response.keys()) if header not in hopbyhop]


def _errno_from_exception(e):
    # socket.error and common wrap in .args
    if len(e.args) > 0:
        return e.args[0].errno if isinstance(e.args[0], socket.error) else e.errno

    # pysocks.ProxyError wraps in .socket_err
    # https://github.com/httplib2/httplib2/pull/202
    if hasattr(e, "socket_err"):
        e_int = e.socket_err
        return e_int.args[0].errno if isinstance(e_int.args[0], socket.error) else e_int.errno

    return None


URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?")


def parse_uri(uri):
    """Parses a URI using the regex given in Appendix B of RFC 3986.

        (scheme, authority, path, query, fragment) = parse_uri(uri)
    """
    groups = URI.match(uri).groups()
    return (groups[1], groups[3], groups[4], groups[6], groups[8])


def urlnorm(uri):
    (scheme, authority, path, query, fragment) = parse_uri(uri)
    if not scheme or not authority:
        raise RelativeURIError("Only absolute URIs are allowed. uri = %s" % uri)
    authority = authority.lower()
    scheme = scheme.lower()
    if not path:
        path = "/"
    # Could do syntax based normalization of the URI before
    # computing the digest. See Section 6.2.2 of Std 66.
    request_uri = query and "?".join([path, query]) or path
    scheme = scheme.lower()
    defrag_uri = scheme + "://" + authority + request_uri
    return scheme, authority, request_uri, defrag_uri


# Cache filename construction (original borrowed from Venus http://intertwingly.net/code/venus/)
re_url_scheme = re.compile(r"^\w+://")
re_unsafe = re.compile(r"[^\w\-_.()=!]+", re.ASCII)


def safename(filename):
    """Return a filename suitable for the cache.
    Strips dangerous and common characters to create a filename we
    can use to store the cache in.
    """
    if isinstance(filename, bytes):
        filename_bytes = filename
        filename = filename.decode("utf-8")
    else:
        filename_bytes = filename.encode("utf-8")
    filemd5 = _md5(filename_bytes).hexdigest()
    filename = re_url_scheme.sub("", filename)
    filename = re_unsafe.sub("", filename)

    # limit length of filename (vital for Windows)
    # https://github.com/httplib2/httplib2/pull/74
    # C:\Users\    <username>    \AppData\Local\Temp\  <safe_filename>  ,   <md5>
    #   9 chars + max 104 chars  +     20 chars      +       x       +  1  +  32  = max 259 chars
    # Thus max safe filename x = 93 chars. Let it be 90 to make a round sum:
    filename = filename[:90]

    return ",".join((filename, filemd5))


NORMALIZE_SPACE = re.compile(r"(?:\r\n)?[ \t]+")


def _normalize_headers(headers):
    return dict(
        [
            (_convert_byte_str(key).lower(), NORMALIZE_SPACE.sub(_convert_byte_str(value), " ").strip(),)
            for (key, value) in headers.items()
        ]
    )


def _convert_byte_str(s):
    if not isinstance(s, str):
        return str(s, "utf-8")
    return s


def _parse_cache_control(headers):
    retval = {}
    if "cache-control" in headers:
        parts = headers["cache-control"].split(",")
        parts_with_args = [
            tuple([x.strip().lower() for x in part.split("=", 1)]) for part in parts if -1 != part.find("=")
        ]
        parts_wo_args = [(name.strip().lower(), 1) for name in parts if -1 == name.find("=")]
        retval = dict(parts_with_args + parts_wo_args)
    return retval


# Whether to use a strict mode to parse WWW-Authenticate headers
# Might lead to bad results in case of ill-formed header value,
# so disabled by default, falling back to relaxed parsing.
# Set to true to turn on, useful for testing servers.
USE_WWW_AUTH_STRICT_PARSING = 0


def _entry_disposition(response_headers, request_headers):
    """Determine freshness from the Date, Expires and Cache-Control headers.

    We don't handle the following:

    1. Cache-Control: max-stale
    2. Age: headers are not used in the calculations.

    Not that this algorithm is simpler than you might think
    because we are operating as a private (non-shared) cache.
    This lets us ignore 's-maxage'. We can also ignore
    'proxy-invalidate' since we aren't a proxy.
    We will never return a stale document as
    fresh as a design decision, and thus the non-implementation
    of 'max-stale'. This also lets us safely ignore 'must-revalidate'
    since we operate as if every server has sent 'must-revalidate'.
    Since we are private we get to ignore both 'public' and
    'private' parameters. We also ignore 'no-transform' since
    we don't do any transformations.
    The 'no-store' parameter is handled at a higher level.
    So the only Cache-Control parameters we look at are:

    no-cache
    only-if-cached
    max-age
    min-fresh
    """

    retval = "STALE"
    cc = _parse_cache_control(request_headers)
    cc_response = _parse_cache_control(response_headers)

    if "pragma" in request_headers and request_headers["pragma"].lower().find("no-cache") != -1:
        retval = "TRANSPARENT"
        if "cache-control" not in request_headers:
            request_headers["cache-control"] = "no-cache"
    elif "no-cache" in cc:
        retval = "TRANSPARENT"
    elif "no-cache" in cc_response:
        retval = "STALE"
    elif "only-if-cached" in cc:
        retval = "FRESH"
    elif "date" in response_headers:
        date = calendar.timegm(email.utils.parsedate_tz(response_headers["date"]))
        now = time.time()
        current_age = max(0, now - date)
        if "max-age" in cc_response:
            try:
                freshness_lifetime = int(cc_response["max-age"])
            except ValueError:
                freshness_lifetime = 0
        elif "expires" in response_headers:
            expires = email.utils.parsedate_tz(response_headers["expires"])
            if None == expires:
                freshness_lifetime = 0
            else:
                freshness_lifetime = max(0, calendar.timegm(expires) - date)
        else:
            freshness_lifetime = 0
        if "max-age" in cc:
            try:
                freshness_lifetime = int(cc["max-age"])
            except ValueError:
                freshness_lifetime = 0
        if "min-fresh" in cc:
            try:
                min_fresh = int(cc["min-fresh"])
            except ValueError:
                min_fresh = 0
            current_age += min_fresh
        if freshness_lifetime > current_age:
            retval = "FRESH"
    return retval


def _decompressContent(response, new_content):
    content = new_content
    try:
        encoding = response.get("content-encoding", None)
        if encoding in ["gzip", "deflate"]:
            if encoding == "gzip":
                content = gzip.GzipFile(fileobj=io.BytesIO(new_content)).read()
            if encoding == "deflate":
                content = zlib.decompress(content, -zlib.MAX_WBITS)
            response["content-length"] = str(len(content))
            # Record the historical presence of the encoding in a way the won't interfere.
            response["-content-encoding"] = response["content-encoding"]
            del response["content-encoding"]
    except (IOError, zlib.error):
        content = ""
        raise FailedToDecompressContent(
            _("Content purported to be compressed with %s but failed to decompress.") % response.get("content-encoding"),
            response,
            content,
        )
    return content


def _bind_write_headers(msg):
    def _write_headers(self):
        # Self refers to the Generator object.
        for h, v in msg.items():
            print("%s:" % h, end=" ", file=self._fp)
            if isinstance(v, header.Header):
                print(v.encode(maxlinelen=self._maxheaderlen), file=self._fp)
            else:
                # email.Header got lots of smarts, so use it.
                headers = header.Header(v, maxlinelen=self._maxheaderlen, charset="utf-8", header_name=h)
                print(headers.encode(), file=self._fp)
        # A blank line always separates headers from body.
        print(file=self._fp)

    return _write_headers


def _updateCache(request_headers, response_headers, content, cache, cachekey):
    if cachekey:
        cc = _parse_cache_control(request_headers)
        cc_response = _parse_cache_control(response_headers)
        if "no-store" in cc or "no-store" in cc_response:
            cache.delete(cachekey)
        else:
            info = email.message.Message()
            for key, value in response_headers.items():
                if key not in ["status", "content-encoding", "transfer-encoding"]:
                    info[key] = value

            # Add annotations to the cache to indicate what headers
            # are variant for this request.
            vary = response_headers.get("vary", None)
            if vary:
                vary_headers = vary.lower().replace(" ", "").split(",")
                for header in vary_headers:
                    key = "-varied-%s" % header
                    try:
                        info[key] = request_headers[header]
                    except KeyError:
                        pass

            status = response_headers.status
            if status == 304:
                status = 200

            status_header = "status: %d\r\n" % status

            try:
                header_str = info.as_string()
            except UnicodeEncodeError:
                setattr(info, "_write_headers", _bind_write_headers(info))
                header_str = info.as_string()

            header_str = re.sub("\r(?!\n)|(?<!\r)\n", "\r\n", header_str)
            text = b"".join([status_header.encode("utf-8"), header_str.encode("utf-8"), content])

            cache.set(cachekey, text)


def _cnonce():
    dig = _md5(
        ("%s:%s" % (time.ctime(), ["0123456789"[random.randrange(0, 9)] for i in range(20)])).encode("utf-8")
    ).hexdigest()
    return dig[:16]


def _wsse_username_token(cnonce, iso_now, password):
    return (
        base64.b64encode(_sha(("%s%s%s" % (cnonce, iso_now, password)).encode("utf-8")).digest()).strip().decode("utf-8")
    )


# For credentials we need two things, first
# a pool of credential to try (not necesarily tied to BAsic, Digest, etc.)
# Then we also need a list of URIs that have already demanded authentication
# That list is tricky since sub-URIs can take the same auth, or the
# auth scheme may change as you descend the tree.
# So we also need each Auth instance to be able to tell us
# how close to the 'top' it is.


class Authentication(object):
    def __init__(self, credentials, host, request_uri, headers, response, content, http):
        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
        self.path = path
        self.host = host
        self.credentials = credentials
        self.http = http

    def depth(self, request_uri):
        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
        return request_uri[len(self.path) :].count("/")

    def inscope(self, host, request_uri):
        # XXX Should we normalize the request_uri?
        (scheme, authority, path, query, fragment) = parse_uri(request_uri)
        return (host == self.host) and path.startswith(self.path)

    def request(self, method, request_uri, headers, content):
        """Modify the request headers to add the appropriate
        Authorization header. Over-rise this in sub-classes."""
        pass

    def response(self, response, content):
        """Gives us a chance to update with new nonces
        or such returned from the last authorized response.
        Over-rise this in sub-classes if necessary.

        Return TRUE is the request is to be retried, for
        example Digest may return stale=true.
        """
        return False

    def __eq__(self, auth):
        return False

    def __ne__(self, auth):
        return True

    def __lt__(self, auth):
        return True

    def __gt__(self, auth):
        return False

    def __le__(self, auth):
        return True

    def __ge__(self, auth):
        return False

    def __bool__(self):
        return True


class BasicAuthentication(Authentication):
    def __init__(self, credentials, host, request_uri, headers, response, content, http):
        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)

    def request(self, method, request_uri, headers, content):
        """Modify the request headers to add the appropriate
        Authorization header."""
        headers["authorization"] = "Basic " + base64.b64encode(
            ("%s:%s" % self.credentials).encode("utf-8")
        ).strip().decode("utf-8")


class DigestAuthentication(Authentication):
    """Only do qop='auth' and MD5, since that
    is all Apache currently implements"""

    def __init__(self, credentials, host, request_uri, headers, response, content, http):
        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
        self.challenge = auth._parse_www_authenticate(response, "www-authenticate")["digest"]
        qop = self.challenge.get("qop", "auth")
        self.challenge["qop"] = ("auth" in [x.strip() for x in qop.split()]) and "auth" or None
        if self.challenge["qop"] is None:
            raise UnimplementedDigestAuthOptionError(_("Unsupported value for qop: %s." % qop))
        self.challenge["algorithm"] = self.challenge.get("algorithm", "MD5").upper()
        if self.challenge["algorithm"] != "MD5":
            raise UnimplementedDigestAuthOptionError(
                _("Unsupported value for algorithm: %s." % self.challenge["algorithm"])
            )
        self.A1 = "".join([self.credentials[0], ":", self.challenge["realm"], ":", self.credentials[1],])
        self.challenge["nc"] = 1

    def request(self, method, request_uri, headers, content, cnonce=None):
        """Modify the request headers"""
        H = lambda x: _md5(x.encode("utf-8")).hexdigest()
        KD = lambda s, d: H("%s:%s" % (s, d))
        A2 = "".join([method, ":", request_uri])
        self.challenge["cnonce"] = cnonce or _cnonce()
        request_digest = '"%s"' % KD(
            H(self.A1),
            "%s:%s:%s:%s:%s"
            % (
                self.challenge["nonce"],
                "%08x" % self.challenge["nc"],
                self.challenge["cnonce"],
                self.challenge["qop"],
                H(A2),
            ),
        )
        headers["authorization"] = (
            'Digest username="%s", realm="%s", nonce="%s", '
            'uri="%s", algorithm=%s, response=%s, qop=%s, '
            'nc=%08x, cnonce="%s"'
        ) % (
            self.credentials[0],
            self.challenge["realm"],
            self.challenge["nonce"],
            request_uri,
            self.challenge["algorithm"],
            request_digest,
            self.challenge["qop"],
            self.challenge["nc"],
            self.challenge["cnonce"],
        )
        if self.challenge.get("opaque"):
            headers["authorization"] += ', opaque="%s"' % self.challenge["opaque"]
        self.challenge["nc"] += 1

    def response(self, response, content):
        if "authentication-info" not in response:
            challenge = auth._parse_www_authenticate(response, "www-authenticate").get("digest", {})
            if "true" == challenge.get("stale"):
                self.challenge["nonce"] = challenge["nonce"]
                self.challenge["nc"] = 1
                return True
        else:
            updated_challenge = auth._parse_authentication_info(response, "authentication-info")

            if "nextnonce" in updated_challenge:
                self.challenge["nonce"] = updated_challenge["nextnonce"]
                self.challenge["nc"] = 1
        return False


class HmacDigestAuthentication(Authentication):
    """Adapted from Robert Sayre's code and DigestAuthentication above."""

    __author__ = "Thomas Broyer (t.broyer@ltgt.net)"

    def __init__(self, credentials, host, request_uri, headers, response, content, http):
        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
        challenge = auth._parse_www_authenticate(response, "www-authenticate")
        self.challenge = challenge["hmacdigest"]
        # TODO: self.challenge['domain']
        self.challenge["reason"] = self.challenge.get("reason", "unauthorized")
        if self.challenge["reason"] not in ["unauthorized", "integrity"]:
            self.challenge["reason"] = "unauthorized"
        self.challenge["salt"] = self.challenge.get("salt", "")
        if not self.challenge.get("snonce"):
            raise UnimplementedHmacDigestAuthOptionError(
                _("The challenge doesn't contain a server nonce, or this one is empty.")
            )
        self.challenge["algorithm"] = self.challenge.get("algorithm", "HMAC-SHA-1")
        if self.challenge["algorithm"] not in ["HMAC-SHA-1", "HMAC-MD5"]:
            raise UnimplementedHmacDigestAuthOptionError(
                _("Unsupported value for algorithm: %s." % self.challenge["algorithm"])
            )
        self.challenge["pw-algorithm"] = self.challenge.get("pw-algorithm", "SHA-1")
        if self.challenge["pw-algorithm"] not in ["SHA-1", "MD5"]:
            raise UnimplementedHmacDigestAuthOptionError(
                _("Unsupported value for pw-algorithm: %s." % self.challenge["pw-algorithm"])
            )
        if self.challenge["algorithm"] == "HMAC-MD5":
            self.hashmod = _md5
        else:
            self.hashmod = _sha
        if self.challenge["pw-algorithm"] == "MD5":
            self.pwhashmod = _md5
        else:
            self.pwhashmod = _sha
        self.key = "".join(
            [
                self.credentials[0],
                ":",
                self.pwhashmod.new("".join([self.credentials[1], self.challenge["salt"]])).hexdigest().lower(),
                ":",
                self.challenge["realm"],
            ]
        )
        self.key = self.pwhashmod.new(self.key).hexdigest().lower()

    def request(self, method, request_uri, headers, content):
        """Modify the request headers"""
        keys = _get_end2end_headers(headers)
        keylist = "".join(["%s " % k for k in keys])
        headers_val = "".join([headers[k] for k in keys])
        created = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
        cnonce = _cnonce()
        request_digest = "%s:%s:%s:%s:%s" % (method, request_uri, cnonce, self.challenge["snonce"], headers_val,)
        request_digest = hmac.new(self.key, request_digest, self.hashmod).hexdigest().lower()
        headers["authorization"] = (
            'HMACDigest username="%s", realm="%s", snonce="%s",'
            ' cnonce="%s", uri="%s", created="%s", '
            'response="%s", headers="%s"'
        ) % (
            self.credentials[0],
            self.challenge["realm"],
            self.challenge["snonce"],
            cnonce,
            request_uri,
            created,
            request_digest,
            keylist,
        )

    def response(self, response, content):
        challenge = auth._parse_www_authenticate(response, "www-authenticate").get("hmacdigest", {})
        if challenge.get("reason") in ["integrity", "stale"]:
            return True
        return False


class WsseAuthentication(Authentication):
    """This is thinly tested and should not be relied upon.
    At this time there isn't any third party server to test against.
    Blogger and TypePad implemented this algorithm at one point
    but Blogger has since switched to Basic over HTTPS and
    TypePad has implemented it wrong, by never issuing a 401
    challenge but instead requiring your client to telepathically know that
    their endpoint is expecting WSSE profile="UsernameToken"."""

    def __init__(self, credentials, host, request_uri, headers, response, content, http):
        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)

    def request(self, method, request_uri, headers, content):
        """Modify the request headers to add the appropriate
        Authorization header."""
        headers["authorization"] = 'WSSE profile="UsernameToken"'
        iso_now = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
        cnonce = _cnonce()
        password_digest = _wsse_username_token(cnonce, iso_now, self.credentials[1])
        headers["X-WSSE"] = ('UsernameToken Username="%s", PasswordDigest="%s", ' 'Nonce="%s", Created="%s"') % (
            self.credentials[0],
            password_digest,
            cnonce,
            iso_now,
        )


class GoogleLoginAuthentication(Authentication):
    def __init__(self, credentials, host, request_uri, headers, response, content, http):
        from urllib.parse import urlencode

        Authentication.__init__(self, credentials, host, request_uri, headers, response, content, http)
        challenge = auth._parse_www_authenticate(response, "www-authenticate")
        service = challenge["googlelogin"].get("service", "xapi")
        # Bloggger actually returns the service in the challenge
        # For the rest we guess based on the URI
        if service == "xapi" and request_uri.find("calendar") > 0:
            service = "cl"
        # No point in guessing Base or Spreadsheet
        # elif request_uri.find("spreadsheets") > 0:
        #    service = "wise"

        auth = dict(Email=credentials[0], Passwd=credentials[1], service=service, source=headers["user-agent"],)
        resp, content = self.http.request(
            "https://www.google.com/accounts/ClientLogin",
            method="POST",
            body=urlencode(auth),
            headers={"Content-Type": "application/x-www-form-urlencoded"},
        )
        lines = content.split("\n")
        d = dict([tuple(line.split("=", 1)) for line in lines if line])
        if resp.status == 403:
            self.Auth = ""
        else:
            self.Auth = d["Auth"]

    def request(self, method, request_uri, headers, content):
        """Modify the request headers to add the appropriate
        Authorization header."""
        headers["authorization"] = "GoogleLogin Auth=" + self.Auth


AUTH_SCHEME_CLASSES = {
    "basic": BasicAuthentication,
    "wsse": WsseAuthentication,
    "digest": DigestAuthentication,
    "hmacdigest": HmacDigestAuthentication,
    "googlelogin": GoogleLoginAuthentication,
}

AUTH_SCHEME_ORDER = ["hmacdigest", "googlelogin", "digest", "wsse", "basic"]


class FileCache(object):
    """Uses a local directory as a store for cached files.
    Not really safe to use if multiple threads or processes are going to
    be running on the same cache.
    """

    def __init__(self, cache, safe=safename):  # use safe=lambda x: md5.new(x).hexdigest() for the old behavior
        self.cache = cache
        self.safe = safe
        if not os.path.exists(cache):
            os.makedirs(self.cache)

    def get(self, key):
        retval = None
        cacheFullPath = os.path.join(self.cache, self.safe(key))
        try:
            f = open(cacheFullPath, "rb")
            retval = f.read()
            f.close()
        except IOError:
            pass
        return retval

    def set(self, key, value):
        cacheFullPath = os.path.join(self.cache, self.safe(key))
        f = open(cacheFullPath, "wb")
        f.write(value)
        f.close()

    def delete(self, key):
        cacheFullPath = os.path.join(self.cache, self.safe(key))
        if os.path.exists(cacheFullPath):
            os.remove(cacheFullPath)


class Credentials(object):
    def __init__(self):
        self.credentials = []

    def add(self, name, password, domain=""):
        self.credentials.append((domain.lower(), name, password))

    def clear(self):
        self.credentials = []

    def iter(self, domain):
        for (cdomain, name, password) in self.credentials:
            if cdomain == "" or domain == cdomain:
                yield (name, password)


class KeyCerts(Credentials):
    """Identical to Credentials except that
    name/password are mapped to key/cert."""

    def add(self, key, cert, domain, password):
        self.credentials.append((domain.lower(), key, cert, password))

    def iter(self, domain):
        for (cdomain, key, cert, password) in self.credentials:
            if cdomain == "" or domain == cdomain:
                yield (key, cert, password)


class AllHosts(object):
    pass


class ProxyInfo(object):
    """Collect information required to use a proxy."""

    bypass_hosts = ()

    def __init__(
        self, proxy_type, proxy_host, proxy_port, proxy_rdns=True, proxy_user=None, proxy_pass=None, proxy_headers=None,
    ):
        """Args:

          proxy_type: The type of proxy server.  This must be set to one of
          socks.PROXY_TYPE_XXX constants.  For example:  p =
          ProxyInfo(proxy_type=socks.PROXY_TYPE_HTTP, proxy_host='localhost',
          proxy_port=8000)
          proxy_host: The hostname or IP address of the proxy server.
          proxy_port: The port that the proxy server is running on.
          proxy_rdns: If True (default), DNS queries will not be performed
          locally, and instead, handed to the proxy to resolve.  This is useful
          if the network does not allow resolution of non-local names. In
          httplib2 0.9 and earlier, this defaulted to False.
          proxy_user: The username used to authenticate with the proxy server.
          proxy_pass: The password used to authenticate with the proxy server.
          proxy_headers: Additional or modified headers for the proxy connect
          request.
        """
        if isinstance(proxy_user, bytes):
            proxy_user = proxy_user.decode()
        if isinstance(proxy_pass, bytes):
            proxy_pass = proxy_pass.decode()
        (
            self.proxy_type,
            self.proxy_host,
            self.proxy_port,
            self.proxy_rdns,
            self.proxy_user,
            self.proxy_pass,
            self.proxy_headers,
        ) = (
            proxy_type,
            proxy_host,
            proxy_port,
            proxy_rdns,
            proxy_user,
            proxy_pass,
            proxy_headers,
        )

    def astuple(self):
        return (
            self.proxy_type,
            self.proxy_host,
            self.proxy_port,
            self.proxy_rdns,
            self.proxy_user,
            self.proxy_pass,
            self.proxy_headers,
        )

    def isgood(self):
        return socks and (self.proxy_host != None) and (self.proxy_port != None)

    def applies_to(self, hostname):
        return not self.bypass_host(hostname)

    def bypass_host(self, hostname):
        """Has this host been excluded from the proxy config"""
        if self.bypass_hosts is AllHosts:
            return True

        hostname = "." + hostname.lstrip(".")
        for skip_name in self.bypass_hosts:
            # *.suffix
            if skip_name.startswith(".") and hostname.endswith(skip_name):
                return True
            # exact match
            if hostname == "." + skip_name:
                return True
        return False

    def __repr__(self):
        return (
            "<ProxyInfo type={p.proxy_type} "
            "host:port={p.proxy_host}:{p.proxy_port} rdns={p.proxy_rdns}"
            + " user={p.proxy_user} headers={p.proxy_headers}>"
        ).format(p=self)


def proxy_info_from_environment(method="http"):
    """Read proxy info from the environment variables.
    """
    if method not in ("http", "https"):
        return

    env_var = method + "_proxy"
    url = os.environ.get(env_var, os.environ.get(env_var.upper()))
    if not url:
        return
    return proxy_info_from_url(url, method, noproxy=None)


def proxy_info_from_url(url, method="http", noproxy=None):
    """Construct a ProxyInfo from a URL (such as http_proxy env var)
    """
    url = urllib.parse.urlparse(url)

    proxy_type = 3  # socks.PROXY_TYPE_HTTP
    pi = ProxyInfo(
        proxy_type=proxy_type,
        proxy_host=url.hostname,
        proxy_port=url.port or dict(https=443, http=80)[method],
        proxy_user=url.username or None,
        proxy_pass=url.password or None,
        proxy_headers=None,
    )

    bypass_hosts = []
    # If not given an explicit noproxy value, respect values in env vars.
    if noproxy is None:
        noproxy = os.environ.get("no_proxy", os.environ.get("NO_PROXY", ""))
    # Special case: A single '*' character means all hosts should be bypassed.
    if noproxy == "*":
        bypass_hosts = AllHosts
    elif noproxy.strip():
        bypass_hosts = noproxy.split(",")
        bypass_hosts = tuple(filter(bool, bypass_hosts))  # To exclude empty string.

    pi.bypass_hosts = bypass_hosts
    return pi


class HTTPConnectionWithTimeout(http.client.HTTPConnection):
    """HTTPConnection subclass that supports timeouts

    HTTPConnection subclass that supports timeouts

    All timeouts are in seconds. If None is passed for timeout then
    Python's default timeout for sockets will be used. See for example
    the docs of socket.setdefaulttimeout():
    http://docs.python.org/library/socket.html#socket.setdefaulttimeout
    """

    def __init__(self, host, port=None, timeout=None, proxy_info=None):
        http.client.HTTPConnection.__init__(self, host, port=port, timeout=timeout)

        self.proxy_info = proxy_info
        if proxy_info and not isinstance(proxy_info, ProxyInfo):
            self.proxy_info = proxy_info("http")

    def connect(self):
        """Connect to the host and port specified in __init__."""
        if self.proxy_info and socks is None:
            raise ProxiesUnavailableError("Proxy support missing but proxy use was requested!")
        if self.proxy_info and self.proxy_info.isgood() and self.proxy_info.applies_to(self.host):
            use_proxy = True
            (
                proxy_type,
                proxy_host,
                proxy_port,
                proxy_rdns,
                proxy_user,
                proxy_pass,
                proxy_headers,
            ) = self.proxy_info.astuple()

            host = proxy_host
            port = proxy_port
        else:
            use_proxy = False

            host = self.host
            port = self.port
            proxy_type = None

        socket_err = None

        for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
            af, socktype, proto, canonname, sa = res
            try:
                if use_proxy:
                    self.sock = socks.socksocket(af, socktype, proto)
                    self.sock.setproxy(
                        proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass,
                    )
                else:
                    self.sock = socket.socket(af, socktype, proto)
                    self.sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                if has_timeout(self.timeout):
                    self.sock.settimeout(self.timeout)
                if self.debuglevel > 0:
                    print("connect: ({0}, {1}) ************".format(self.host, self.port))
                    if use_proxy:
                        print(
                            "proxy: {0} ************".format(
                                str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers,))
                            )
                        )

                self.sock.connect((self.host, self.port) + sa[2:])
            except socket.error as e:
                socket_err = e
                if self.debuglevel > 0:
                    print("connect fail: ({0}, {1})".format(self.host, self.port))
                    if use_proxy:
                        print(
                            "proxy: {0}".format(
                                str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers,))
                            )
                        )
                if self.sock:
                    self.sock.close()
                self.sock = None
                continue
            break
        if not self.sock:
            raise socket_err


class HTTPSConnectionWithTimeout(http.client.HTTPSConnection):
    """This class allows communication via SSL.

    All timeouts are in seconds. If None is passed for timeout then
    Python's default timeout for sockets will be used. See for example
    the docs of socket.setdefaulttimeout():
    http://docs.python.org/library/socket.html#socket.setdefaulttimeout
    """

    def __init__(
        self,
        host,
        port=None,
        key_file=None,
        cert_file=None,
        timeout=None,
        proxy_info=None,
        ca_certs=None,
        disable_ssl_certificate_validation=False,
        tls_maximum_version=None,
        tls_minimum_version=None,
        key_password=None,
    ):

        self.disable_ssl_certificate_validation = disable_ssl_certificate_validation
        self.ca_certs = ca_certs if ca_certs else CA_CERTS

        self.proxy_info = proxy_info
        if proxy_info and not isinstance(proxy_info, ProxyInfo):
            self.proxy_info = proxy_info("https")

        context = _build_ssl_context(
            self.disable_ssl_certificate_validation,
            self.ca_certs,
            cert_file,
            key_file,
            maximum_version=tls_maximum_version,
            minimum_version=tls_minimum_version,
            key_password=key_password,
        )
        super(HTTPSConnectionWithTimeout, self).__init__(
            host, port=port, timeout=timeout, context=context,
        )
        self.key_file = key_file
        self.cert_file = cert_file
        self.key_password = key_password

    def connect(self):
        """Connect to a host on a given (SSL) port."""
        if self.proxy_info and self.proxy_info.isgood() and self.proxy_info.applies_to(self.host):
            use_proxy = True
            (
                proxy_type,
                proxy_host,
                proxy_port,
                proxy_rdns,
                proxy_user,
                proxy_pass,
                proxy_headers,
            ) = self.proxy_info.astuple()

            host = proxy_host
            port = proxy_port
        else:
            use_proxy = False

            host = self.host
            port = self.port
            proxy_type = None
            proxy_headers = None

        socket_err = None

        address_info = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)
        for family, socktype, proto, canonname, sockaddr in address_info:
            try:
                if use_proxy:
                    sock = socks.socksocket(family, socktype, proto)

                    sock.setproxy(
                        proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass,
                    )
                else:
                    sock = socket.socket(family, socktype, proto)
                    sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
                if has_timeout(self.timeout):
                    sock.settimeout(self.timeout)
                sock.connect((self.host, self.port))

                self.sock = self._context.wrap_socket(sock, server_hostname=self.host)

                # Python 3.3 compatibility: emulate the check_hostname behavior
                if not hasattr(self._context, "check_hostname") and not self.disable_ssl_certificate_validation:
                    try:
                        ssl.match_hostname(self.sock.getpeercert(), self.host)
                    except Exception:
                        self.sock.shutdown(socket.SHUT_RDWR)
                        self.sock.close()
                        raise

                if self.debuglevel > 0:
                    print("connect: ({0}, {1})".format(self.host, self.port))
                    if use_proxy:
                        print(
                            "proxy: {0}".format(
                                str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers,))
                            )
                        )
            except (ssl.SSLError, ssl.CertificateError) as e:
                if sock:
                    sock.close()
                if self.sock:
                    self.sock.close()
                self.sock = None
                raise
            except (socket.timeout, socket.gaierror):
                raise
            except socket.error as e:
                socket_err = e
                if self.debuglevel > 0:
                    print("connect fail: ({0}, {1})".format(self.host, self.port))
                    if use_proxy:
                        print(
                            "proxy: {0}".format(
                                str((proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers,))
                            )
                        )
                if self.sock:
                    self.sock.close()
                self.sock = None
                continue
            break
        if not self.sock:
            raise socket_err


SCHEME_TO_CONNECTION = {
    "http": HTTPConnectionWithTimeout,
    "https": HTTPSConnectionWithTimeout,
}


class Http(object):
    """An HTTP client that handles:

    - all methods
    - caching
    - ETags
    - compression,
    - HTTPS
    - Basic
    - Digest
    - WSSE

    and more.
    """

    def __init__(
        self,
        cache=None,
        timeout=None,
        proxy_info=proxy_info_from_environment,
        ca_certs=None,
        disable_ssl_certificate_validation=False,
        tls_maximum_version=None,
        tls_minimum_version=None,
    ):
        """If 'cache' is a string then it is used as a directory name for
        a disk cache. Otherwise it must be an object that supports the
        same interface as FileCache.

        All timeouts are in seconds. If None is passed for timeout
        then Python's default timeout for sockets will be used. See
        for example the docs of socket.setdefaulttimeout():
        http://docs.python.org/library/socket.html#socket.setdefaulttimeout

        `proxy_info` may be:
          - a callable that takes the http scheme ('http' or 'https') and
            returns a ProxyInfo instance per request. By default, uses
            proxy_info_from_environment.
          - a ProxyInfo instance (static proxy config).
          - None (proxy disabled).

        ca_certs is the path of a file containing root CA certificates for SSL
        server certificate validation.  By default, a CA cert file bundled with
        httplib2 is used.

        If disable_ssl_certificate_validation is true, SSL cert validation will
        not be performed.

        tls_maximum_version / tls_minimum_version require Python 3.7+ /
        OpenSSL 1.1.0g+. A value of "TLSv1_3" requires OpenSSL 1.1.1+.
        """
        self.proxy_info = proxy_info
        self.ca_certs = ca_certs
        self.disable_ssl_certificate_validation = disable_ssl_certificate_validation
        self.tls_maximum_version = tls_maximum_version
        self.tls_minimum_version = tls_minimum_version
        # Map domain name to an httplib connection
        self.connections = {}
        # The location of the cache, for now a directory
        # where cached responses are held.
        if cache and isinstance(cache, str):
            self.cache = FileCache(cache)
        else:
            self.cache = cache

        # Name/password
        self.credentials = Credentials()

        # Key/cert
        self.certificates = KeyCerts()

        # authorization objects
        self.authorizations = []

        # If set to False then no redirects are followed, even safe ones.
        self.follow_redirects = True

        self.redirect_codes = REDIRECT_CODES

        # Which HTTP methods do we apply optimistic concurrency to, i.e.
        # which methods get an "if-match:" etag header added to them.
        self.optimistic_concurrency_methods = ["PUT", "PATCH"]

        self.safe_methods = list(SAFE_METHODS)

        # If 'follow_redirects' is True, and this is set to True then
        # all redirecs are followed, including unsafe ones.
        self.follow_all_redirects = False

        self.ignore_etag = False

        self.force_exception_to_status_code = False

        self.timeout = timeout

        # Keep Authorization: headers on a redirect.
        self.forward_authorization_headers = False

    def close(self):
        """Close persistent connections, clear sensitive data.
        Not thread-safe, requires external synchronization against concurrent requests.
        """
        existing, self.connections = self.connections, {}
        for _, c in existing.items():
            c.close()
        self.certificates.clear()
        self.clear_credentials()

    def __getstate__(self):
        state_dict = copy.copy(self.__dict__)
        # In case request is augmented by some foreign object such as
        # credentials which handle auth
        if "request" in state_dict:
            del state_dict["request"]
        if "connections" in state_dict:
            del state_dict["connections"]
        return state_dict

    def __setstate__(self, state):
        self.__dict__.update(state)
        self.connections = {}

    def _auth_from_challenge(self, host, request_uri, headers, response, content):
        """A generator that creates Authorization objects
           that can be applied to requests.
        """
        challenges = auth._parse_www_authenticate(response, "www-authenticate")
        for cred in self.credentials.iter(host):
            for scheme in AUTH_SCHEME_ORDER:
                if scheme in challenges:
                    yield AUTH_SCHEME_CLASSES[scheme](cred, host, request_uri, headers, response, content, self)

    def add_credentials(self, name, password, domain=""):
        """Add a name and password that will be used
        any time a request requires authentication."""
        self.credentials.add(name, password, domain)

    def add_certificate(self, key, cert, domain, password=None):
        """Add a key and cert that will be used
        any time a request requires authentication."""
        self.certificates.add(key, cert, domain, password)

    def clear_credentials(self):
        """Remove all the names and passwords
        that are used for authentication"""
        self.credentials.clear()
        self.authorizations = []

    def _conn_request(self, conn, request_uri, method, body, headers):
        i = 0
        seen_bad_status_line = False
        while i < RETRIES:
            i += 1
            try:
                if conn.sock is None:
                    conn.connect()
                conn.request(method, request_uri, body, headers)
            except socket.timeout:
                conn.close()
                raise
            except socket.gaierror:
                conn.close()
                raise ServerNotFoundError("Unable to find the server at %s" % conn.host)
            except socket.error as e:
                errno_ = _errno_from_exception(e)
                if errno_ in (errno.ENETUNREACH, errno.EADDRNOTAVAIL) and i < RETRIES:
                    continue  # retry on potentially transient errors
                raise
            except http.client.HTTPException:
                if conn.sock is None:
                    if i < RETRIES - 1:
                        conn.close()
                        conn.connect()
                        continue
                    else:
                        conn.close()
                        raise
                if i < RETRIES - 1:
                    conn.close()
                    conn.connect()
                    continue
                # Just because the server closed the connection doesn't apparently mean
                # that the server didn't send a response.
                pass
            try:
                response = conn.getresponse()
            except (http.client.BadStatusLine, http.client.ResponseNotReady):
                # If we get a BadStatusLine on the first try then that means
                # the connection just went stale, so retry regardless of the
                # number of RETRIES set.
                if not seen_bad_status_line and i == 1:
                    i = 0
                    seen_bad_status_line = True
                    conn.close()
                    conn.connect()
                    continue
                else:
                    conn.close()
                    raise
            except socket.timeout:
                raise
            except (socket.error, http.client.HTTPException):
                conn.close()
                if i == 0:
                    conn.close()
                    conn.connect()
                    continue
                else:
                    raise
            else:
                content = b""
                if method == "HEAD":
                    conn.close()
                else:
                    content = response.read()
                response = Response(response)
                if method != "HEAD":
                    content = _decompressContent(response, content)

            break
        return (response, content)

    def _request(
        self, conn, host, absolute_uri, request_uri, method, body, headers, redirections, cachekey,
    ):
        """Do the actual request using the connection object
        and also follow one level of redirects if necessary"""

        auths = [(auth.depth(request_uri), auth) for auth in self.authorizations if auth.inscope(host, request_uri)]
        auth = auths and sorted(auths)[0][1] or None
        if auth:
            auth.request(method, request_uri, headers, body)

        (response, content) = self._conn_request(conn, request_uri, method, body, headers)

        if auth:
            if auth.response(response, body):
                auth.request(method, request_uri, headers, body)
                (response, content) = self._conn_request(conn, request_uri, method, body, headers)
                response._stale_digest = 1

        if response.status == 401:
            for authorization in self._auth_from_challenge(host, request_uri, headers, response, content):
                authorization.request(method, request_uri, headers, body)
                (response, content) = self._conn_request(conn, request_uri, method, body, headers)
                if response.status != 401:
                    self.authorizations.append(authorization)
                    authorization.response(response, body)
                    break

        if self.follow_all_redirects or method in self.safe_methods or response.status in (303, 308):
            if self.follow_redirects and response.status in self.redirect_codes:
                # Pick out the location header and basically start from the beginning
                # remembering first to strip the ETag header and decrement our 'depth'
                if redirections:
                    if "location" not in response and response.status != 300:
                        raise RedirectMissingLocation(
                            _("Redirected but the response is missing a Location: header."), response, content,
                        )
                    # Fix-up relative redirects (which violate an RFC 2616 MUST)
                    if "location" in response:
                        location = response["location"]
                        (scheme, authority, path, query, fragment) = parse_uri(location)
                        if authority == None:
                            response["location"] = urllib.parse.urljoin(absolute_uri, location)
                    if response.status == 308 or (response.status == 301 and (method in self.safe_methods)):
                        response["-x-permanent-redirect-url"] = response["location"]
                        if "content-location" not in response:
                            response["content-location"] = absolute_uri
                        _updateCache(headers, response, content, self.cache, cachekey)
                    if "if-none-match" in headers:
                        del headers["if-none-match"]
                    if "if-modified-since" in headers:
                        del headers["if-modified-since"]
                    if "authorization" in headers and not self.forward_authorization_headers:
                        del headers["authorization"]
                    if "location" in response:
                        location = response["location"]
                        old_response = copy.deepcopy(response)
                        if "content-location" not in old_response:
                            old_response["content-location"] = absolute_uri
                        redirect_method = method
                        if response.status in [302, 303]:
                            redirect_method = "GET"
                            body = None
                        (response, content) = self.request(
                            location, method=redirect_method, body=body, headers=headers, redirections=redirections - 1,
                        )
                        response.previous = old_response
                else:
                    raise RedirectLimit(
                        "Redirected more times than redirection_limit allows.", response, content,
                    )
            elif response.status in [200, 203] and method in self.safe_methods:
                # Don't cache 206's since we aren't going to handle byte range requests
                if "content-location" not in response:
                    response["content-location"] = absolute_uri
                _updateCache(headers, response, content, self.cache, cachekey)

        return (response, content)

    def _normalize_headers(self, headers):
        return _normalize_headers(headers)

    # Need to catch and rebrand some exceptions
    # Then need to optionally turn all exceptions into status codes
    # including all socket.* and httplib.* exceptions.

    def request(
        self, uri, method="GET", body=None, headers=None, redirections=DEFAULT_MAX_REDIRECTS, connection_type=None,
    ):
        """ Performs a single HTTP request.
The 'uri' is the URI of the HTTP resource and can begin
with either 'http' or 'https'. The value of 'uri' must be an absolute URI.

The 'method' is the HTTP method to perform, such as GET, POST, DELETE, etc.
There is no restriction on the methods allowed.

The 'body' is the entity body to be sent with the request. It is a string
object.

Any extra headers that are to be sent with the request should be provided in the
'headers' dictionary.

The maximum number of redirect to follow before raising an
exception is 'redirections. The default is 5.

The return value is a tuple of (response, content), the first
being and instance of the 'Response' class, the second being
a string that contains the response entity body.
        """
        conn_key = ""

        try:
            if headers is None:
                headers = {}
            else:
                headers = self._normalize_headers(headers)

            if "user-agent" not in headers:
                headers["user-agent"] = "Python-httplib2/%s (gzip)" % __version__

            uri = iri2uri(uri)
            # Prevent CWE-75 space injection to manipulate request via part of uri.
            # Prevent CWE-93 CRLF injection to modify headers via part of uri.
            uri = uri.replace(" ", "%20").replace("\r", "%0D").replace("\n", "%0A")

            (scheme, authority, request_uri, defrag_uri) = urlnorm(uri)

            conn_key = scheme + ":" + authority
            conn = self.connections.get(conn_key)
            if conn is None:
                if not connection_type:
                    connection_type = SCHEME_TO_CONNECTION[scheme]
                certs = list(self.certificates.iter(authority))
                if issubclass(connection_type, HTTPSConnectionWithTimeout):
                    if certs:
                        conn = self.connections[conn_key] = connection_type(
                            authority,
                            key_file=certs[0][0],
                            cert_file=certs[0][1],
                            timeout=self.timeout,
                            proxy_info=self.proxy_info,
                            ca_certs=self.ca_certs,
                            disable_ssl_certificate_validation=self.disable_ssl_certificate_validation,
                            tls_maximum_version=self.tls_maximum_version,
                            tls_minimum_version=self.tls_minimum_version,
                            key_password=certs[0][2],
                        )
                    else:
                        conn = self.connections[conn_key] = connection_type(
                            authority,
                            timeout=self.timeout,
                            proxy_info=self.proxy_info,
                            ca_certs=self.ca_certs,
                            disable_ssl_certificate_validation=self.disable_ssl_certificate_validation,
                            tls_maximum_version=self.tls_maximum_version,
                            tls_minimum_version=self.tls_minimum_version,
                        )
                else:
                    conn = self.connections[conn_key] = connection_type(
                        authority, timeout=self.timeout, proxy_info=self.proxy_info
                    )
                conn.set_debuglevel(debuglevel)

            if "range" not in headers and "accept-encoding" not in headers:
                headers["accept-encoding"] = "gzip, deflate"

            info = email.message.Message()
            cachekey = None
            cached_value = None
            if self.cache:
                cachekey = defrag_uri
                cached_value = self.cache.get(cachekey)
                if cached_value:
                    try:
                        info, content = cached_value.split(b"\r\n\r\n", 1)
                        info = email.message_from_bytes(info)
                        for k, v in info.items():
                            if v.startswith("=?") and v.endswith("?="):
                                info.replace_header(k, str(*email.header.decode_header(v)[0]))
                    except (IndexError, ValueError):
                        self.cache.delete(cachekey)
                        cachekey = None
                        cached_value = None

            if (
                method in self.optimistic_concurrency_methods
                and self.cache
                and "etag" in info
                and not self.ignore_etag
                and "if-match" not in headers
            ):
                # http://www.w3.org/1999/04/Editing/
                headers["if-match"] = info["etag"]

            # https://tools.ietf.org/html/rfc7234
            # A cache MUST invalidate the effective Request URI as well as [...] Location and Content-Location
            # when a non-error status code is received in response to an unsafe request method.
            if self.cache and cachekey and method not in self.safe_methods:
                self.cache.delete(cachekey)

            # Check the vary header in the cache to see if this request
            # matches what varies in the cache.
            if method in self.safe_methods and "vary" in info:
                vary = info["vary"]
                vary_headers = vary.lower().replace(" ", "").split(",")
                for header in vary_headers:
                    key = "-varied-%s" % header
                    value = info[key]
                    if headers.get(header, None) != value:
                        cached_value = None
                        break

            if (
                self.cache
                and cached_value
                and (method in self.safe_methods or info["status"] == "308")
                and "range" not in headers
            ):
                redirect_method = method
                if info["status"] not in ("307", "308"):
                    redirect_method = "GET"
                if "-x-permanent-redirect-url" in info:
                    # Should cached permanent redirects be counted in our redirection count? For now, yes.
                    if redirections <= 0:
                        raise RedirectLimit(
                            "Redirected more times than redirection_limit allows.", {}, "",
                        )
                    (response, new_content) = self.request(
                        info["-x-permanent-redirect-url"],
                        method=redirect_method,
                        headers=headers,
                        redirections=redirections - 1,
                    )
                    response.previous = Response(info)
                    response.previous.fromcache = True
                else:
                    # Determine our course of action:
                    #   Is the cached entry fresh or stale?
                    #   Has the client requested a non-cached response?
                    #
                    # There seems to be three possible answers:
                    # 1. [FRESH] Return the cache entry w/o doing a GET
                    # 2. [STALE] Do the GET (but add in cache validators if available)
                    # 3. [TRANSPARENT] Do a GET w/o any cache validators (Cache-Control: no-cache) on the request
                    entry_disposition = _entry_disposition(info, headers)

                    if entry_disposition == "FRESH":
                        response = Response(info)
                        response.fromcache = True
                        return (response, content)

                    if entry_disposition == "STALE":
                        if "etag" in info and not self.ignore_etag and not "if-none-match" in headers:
                            headers["if-none-match"] = info["etag"]
                        if "last-modified" in info and not "last-modified" in headers:
                            headers["if-modified-since"] = info["last-modified"]
                    elif entry_disposition == "TRANSPARENT":
                        pass

                    (response, new_content) = self._request(
                        conn, authority, uri, request_uri, method, body, headers, redirections, cachekey,
                    )

                if response.status == 304 and method == "GET":
                    # Rewrite the cache entry with the new end-to-end headers
                    # Take all headers that are in response
                    # and overwrite their values in info.
                    # unless they are hop-by-hop, or are listed in the connection header.

                    for key in _get_end2end_headers(response):
                        info[key] = response[key]
                    merged_response = Response(info)
                    if hasattr(response, "_stale_digest"):
                        merged_response._stale_digest = response._stale_digest
                    _updateCache(headers, merged_response, content, self.cache, cachekey)
                    response = merged_response
                    response.status = 200
                    response.fromcache = True

                elif response.status == 200:
                    content = new_content
                else:
                    self.cache.delete(cachekey)
                    content = new_content
            else:
                cc = _parse_cache_control(headers)
                if "only-if-cached" in cc:
                    info["status"] = "504"
                    response = Response(info)
                    content = b""
                else:
                    (response, content) = self._request(
                        conn, authority, uri, request_uri, method, body, headers, redirections, cachekey,
                    )
        except Exception as e:
            is_timeout = isinstance(e, socket.timeout)
            if is_timeout:
                conn = self.connections.pop(conn_key, None)
                if conn:
                    conn.close()

            if self.force_exception_to_status_code:
                if isinstance(e, HttpLib2ErrorWithResponse):
                    response = e.response
                    content = e.content
                    response.status = 500
                    response.reason = str(e)
                elif isinstance(e, socket.timeout):
                    content = b"Request Timeout"
                    response = Response({"content-type": "text/plain", "status": "408", "content-length": len(content),})
                    response.reason = "Request Timeout"
                else:
                    content = str(e).encode("utf-8")
                    response = Response({"content-type": "text/plain", "status": "400", "content-length": len(content),})
                    response.reason = "Bad Request"
            else:
                raise

        return (response, content)


class Response(dict):
    """An object more like email.message than httplib.HTTPResponse."""

    """Is this response from our local cache"""
    fromcache = False
    """HTTP protocol version used by server.

    10 for HTTP/1.0, 11 for HTTP/1.1.
    """
    version = 11

    "Status code returned by server. "
    status = 200
    """Reason phrase returned by server."""
    reason = "Ok"

    previous = None

    def __init__(self, info):
        # info is either an email.message or
        # an httplib.HTTPResponse object.
        if isinstance(info, http.client.HTTPResponse):
            for key, value in info.getheaders():
                key = key.lower()
                prev = self.get(key)
                if prev is not None:
                    value = ", ".join((prev, value))
                self[key] = value
            self.status = info.status
            self["status"] = str(self.status)
            self.reason = info.reason
            self.version = info.version
        elif isinstance(info, email.message.Message):
            for key, value in list(info.items()):
                self[key.lower()] = value
            self.status = int(self["status"])
        else:
            for key, value in info.items():
                self[key.lower()] = value
            self.status = int(self.get("status", self.status))

    def __getattr__(self, name):
        if name == "dict":
            return self
        else:
            raise AttributeError(name)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               ELF          >            @       0         @ 8 	 @                                  +       +                    0       0       0                              P      P      P     T      T                                      	      	                   0     0     0                              8      8      8      $       $              Ptd   $u     $u     $u                        Qtd                                                  Rtd                                                   GNU !)4
[    C   J      	   h$ 8I9 PB&* K @$\  @@3"l ` @J       K   M   O   P   R   S   T   U       V   X       [   \   ^   _       b   c   g       i   j               l   n       s       v       w   z           |       ~                                                                                        47c)}eX
рV1p[
X׺]l-= ohϸH34G+g,҈.DQ&Fˍs~D1aT\!Ў
z7=BbBr>+*#p*?K0/DxH y)BoSvRZ9E*b4&Q*Lr*__E
884}l}:;b
1#hMԩqλl.U=b]qdm4P                            D                     x                                                               b                                                                                                            %                     T                     j                      r                                          ~                                                                                                                                                     [                                                               X                                                                                                           x                                          "                                          d                     >                                                                                                                                                                                                                     
                                          7                                                               E                                          U                      |                     _                     ^                                                                                                                                j                                          ,                                                                                                           F   "                   j                                                                                    c                        
       H          
 @           f   
 @      ]       m    x               
               I   
             o   
 P      	       C   
       ,       7   
            8   
       ~       o    
 `7      a       U   
 pF                
              M   
       q      X   
      M          
 8             S   
 `      0         
 J               
 w      =         
 `!           '   
              &   
 @     K      i   
      M      )   
                
        ,       &   
  ;      5      a   
       Y         
 E      u       E   
                 
 u      |           
 `=                                   
 0                
 `      3          
 @               
        p          
 `~      m         
                
       3      5   
             |    
 7                
 PN               
       H         
       
       ,   
 P               
 Т                
        P       (   
              A   
 @F      !           
 >      J                            
                
 P                
 8                
        '         
      i           
 `?            3   
  #              
 D      ;         
 v               
 p      :      K   
                
      W         
 p                
 0                
                  
 9      O         
 P      4          
 PX      e         
       o          
                 
  }      [         
 n               
  D              __gmon_start__ _ITM_deregisterTMCloneTable _ITM_registerTMCloneTable __cxa_finalize __printf_chk putchar puts prop_dispose prop_new memset __stack_chk_fail prop_get prop_getnames strcmp prop_clear exit prop_erase strlen prop_format strncat strcat prop_set memcpy prop_setvals prop_dup sasl_auxprop_request sasl_seterror sasl_auxprop_getctx sasl_auxprop_add_plugin sasl_global_utils sasl_errstring __ctype_b_loc strcasecmp sasl_auxprop_store auxprop_plugin_info strdup strchr sasl_canonuser_add_plugin strncpy __fdelt_chk select __errno_location read _sasl_MD5Init _sasl_MD5Update _sasl_MD5Final writev strrchr socket connect fcntl __snprintf_chk __sprintf_chk strncasecmp sasl_client_add_plugin sasl_client_done sasl_common_done sasl_client_init sasl_client_new strtol sasl_client_step sasl_client_start strcpy sasl_client_plugin_info getenv sasl_getprop __assert_fail sasl_config_getstring __syslog_chk memcmp sasl_set_mutex getuid geteuid getgid getegid sasl_set_path sasl_version sasl_version_info sasl_decode sasl_set_alloc sasl_dispose sasl_mkchal sasl_rand sasl_utf8verify sasl_churn sasl_randcreate sasl_encode64 sasl_decode64 sasl_erasebuffer sasl_setprop sasl_randfree sasl_done sasl_idle sasl_errdetail strerror sasl_encodev sasl_encode getaddrinfo freeaddrinfo __strcpy_chk sasl_strlower sasl_global_listmech sasl_listmech malloc calloc realloc sasl_config_init fopen fgets __ctype_tolower_loc fclose sasl_config_done gettimeofday time clock sasl_randseed jrand48 gethostname sasl_server_add_plugin sasl_setpass sasl_server_done sasl_server_init sasl_server_new sasl_server_step sasl_server_start sasl_checkpass sasl_user_exists sasl_checkapop strspn sasl_server_plugin_info dlsym dlopen dlerror __stpcpy_chk __memcpy_chk opendir readdir __strncat_chk closedir dlclose uname libc.so.6 libsasl2.so.2 SASL2 HIDDEN GLIBC_2.3 GLIBC_2.14 GLIBC_2.15 GLIBC_2.4 GLIBC_2.34 GLIBC_2.3.4 GLIBC_2.2.5                                            	                            
 
                                                                                    
                 gW                                              ii
  
         	 *        5     ii
   @        J     ti	   U     ui	   a                   `6                   6                        (            %p     о                  @            p                        п                                                       0            Q     @            R      H            R                  U                 @]                  T                 0a                  U                 g                  U                  Z                                                       @                                          (                  `            WY     x            g                 p                                                      WY                 @                                                      q                 +q                 4q                 Aq                 Qq                 ]q                 nq     Ⱦ        c           ؾ                           	                   U                                      d                    S                   p                                      M                    ^           (        q           0        Y           8        P           H        r           P                   X                   `        [           h        '           p        T           x        h                                      {                                                         Z                                      m                   ?           ȿ                   ؿ                           D                   f                   y           @        /           H        #           P        2           X                   X                   `                   h                   p                   x                                                                                                       
                                                         l                   
           ȼ                   м                   ؼ                                              _                                                                                                                                                  (                   0                   8                   @                   H                   P                   X                   `                    h        !           p        "           x        $                   w                   %                   &                   (                                      )                   *                   +                   ,           Ƚ        -           н        .           ؽ        0                   1                   3                   4                   }                    5                   t                   6                   Q                    L           (        7           0        8           8        9           @        :           H        ;           P        W           X        <           `        =           h        >           p        @           x        A                   B                   k                   u                   C                   E                   F                   G                   H                   I                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           HH] HtH         5" %$ @ %" h    % h   % h   %
 h   % h   % h   % h   % h   p% h   `%ڋ h	   P%ҋ h
   @%ʋ h   0% h    % h
   % h    % h   % h   % h   % h   % h   % h   %z h   %r h   %j h   p%b h   `%Z h   P%R h   @%J h   0%B h    %: h   %2 h    %* h   %" h    % h!   % h"   %
 h#   % h$   % h%   % h&   % h'   p% h(   `%ڊ h)   P%Ҋ h*   @%ʊ h+   0% h,    % h-   % h.    % h/   % h0   % h1   % h2   % h3   % h4   %z h5   %r h6   %j h7   p%b h8   `%Z h9   P%R h:   @%J h;   0%B h<    %: h=   %2 h>    %* h?   %" h@   % hA   % hB   %
 hC   % hD   % hE   % hF   % hG   p% hH   `%ډ hI   P%҉ hJ   @%ʉ hK   0% hL    % hM   % f% f%ʉ f% f% f% f% f% f% f% f% f% f% f% f%* f%* f%B f%B f%B f        H=I HB H9tH Ht	        H= H5 H)HH?HHHtH HtfD      =Ռ  u+UH=  HtH= Qd ]     w    Vw&H
 HcHfD  tufD      D    Df     t|toSHW HH5    1l   H5 1   TH{(    HO HL H5i HE1*
   [?        H= @ Ht[USHHHHt=Hx(H- Ht f.     HHP(UHHx(HuHUH    H[]fD  ff.     @ AUATUSH(L%] dH%(   HD$1  8   DA$HD$HHts`LmLA$fHnflHtyL1H)$fo$HUHhHH@HHxHC(HQHK HCHSHK HC    H\$HD$dH+%(   u&H(H[]A\A]@ HC(    H|$ff.     @ HtH    1ff.     fAWAVAUATIUSHHH   M   H.IH   IE1D  IH3Hu[ HsHHtKHuoAA$HCID$ImIIHuHD[]A\A]A^A_fD  ID$    fA$E1Aff.     @ AWAAVAUATUSHH(GL%R H@HG(H@L4fInMnflL)D$A$fHnfl)$H   L1HHfoT$LmUEt}C    H{(HtD  HHC(AT$H{(HuLuCLfo$CH@HH)LHUL+MHC    HC Lk[(H([]A\A]A^A_ CtH@H31H@ HHTHH9u[1H    1l     H&  AWAVAUATIUSHH  H>    I1fD  PI< HH    u   EnAnF|)D9   IH$IHD$EtQfD  H$DI$H@IH,
II9;  I?HuHD$II9tEnEuH$A   
  fD  1Ln1H[]A\A]A^A_HI~(HwHHD9rDE~MDH@HH)HweD9rH@HH9   H H$Hr PHH   H$En1HPIF(LGAnDMH@HwHD)KDm 1HL$HTm I<HIHL$EnHH$IN     ALI$EnHH)IF(    I    IF    ff.     H   ATUHSH   HH3Huxf.     HsHHtaHuHCHtLH(Ht4E1 HxH1HHCJ     IJ, HuHC    HC    []A\D      AWAVAUATUSHH4$LL$H   HH   HEH  LcDE   ULm JI} AHtD  I}IAHuAGEtpAFD9   HD$ HtD8EtLHm H}  tAEA1@ tEtH4$LHHu HHH}     u1H[]A\A]A^A_ H<$Lc.D  DHD)[]AA\A]A^A_1E1 fD  AWAVAUATUSHHHT$0H  IHAH  LwMm  H|$0 K  H_0HK(    IFH9s%HsHH9sI.HG  HSIHvI} HjAL$HkLcHGH<$IE H    EH|$0LL$LL$LxL9  HCH, L9sHL9rH fHnLeflL)D$HHtL1hfoD$H@IE0H;LMV  IyMM0I} HIiHL)Ht$0L)I}IQIWIEH<$BD8 IEHGAFAFBD8AF1HH[]A\A]A^A_D  HH[]A\A]A^A_@ I] IE    H3Huf.     HsHHtHuHKI]H4  H|$0 tH9 b  HȽ   @ HH8 uDMLIM}0IwL9H  I} L)΍EIH|$0 IwH{H    MM HtHHt1 HHHHuE  AMcL9  IGL$ M9sf     MM9rH fInIT$flHT$H)$HHtHT$1Hnfo$HHIE0IL8M]  IGM}0IwIE J< L)L)IVI}IwHt$0IEUBD0 IMHCHЋCCBD0CfI}IGL4 M9sf.     MM9rH!~ fInIVLL$flH$HHT$8)T$ H$LL$HHt"HT$81foT$ LL$H$HPIE0I?L8MthIM}0IwIMuH|$0 A      H|$0H4$xH4$Lp<I}A           HttUSHHHt]HHtMH1HOHHt&t @ Ht11HH#HtH[]D  11fH1[]øÐATUSH dH%(   HD$1HD$    H   HH   HG(I1Ht@ xH HupHD$HH   AT$HO(BHqfnfnH@HfbH)HDfGHqHG tZ1fD  H|$A;\$sAHH@I$HH0H4HPtH|$ t#H|$D$D$ID$HG1H} HT$dH+%(   uH []A\øD  HtjS?Hu8H  H   Ht*y`	  [fD     ~1[1     H
 :ǃ`	  [øff.     1Ht?uH  H   D  ff.     @ SHIH H5x dH%(   HT$1HL$HT$H>   ЉÅua|$~UHD$Hx tsHzz    Htg~.| H'| D$ HD$dH+%(   uGH [    11xH	    1H1p`  뷻밻ff.     ATUSH{ Ht@L%y f     HHHUHBHtH
w HzH1HAT$HuH]{     []A\AWAVAUIATUHSHX4$HT$(   L$HL$0dH%(   HD$H1HGPHD$8    Hx D  u"E11H|$0HL$8H T$(  H|$8H  HD$@    1Ht$@GO    Lt$@D$    ALt$  @ T$OHT$H0@ IVI   DV uILu        HBH  DF tL%)z  1MthHT$D$fD  M|$I Ht5Lu)I$LHDD$AW߉?D$   M$$MuD$HT$uLrR    Hw H|$PD$u.HL$8HO HHDHEPH    Hx1]  HD$HdH+%(      HX[]A\A]A^A_fD  L%)y Mt   HT$D$HD$8    L=y Mt>D$$Dt$fD  IGLDHEHxP߉0M?Mu^H
 7Hv H|$P4fAWAVAUATUSHHxHt$HT$dH%(   HD$h1HD$X    H$  Hq  HHe  H  HD$]D$$HL$PHT$H   H"A     E11H|$PHL$XH T$H   HD$X    L-w D$4    1M  Hl$Dd$$Lt$L|$4    HzELLHЃM  Mm Mt$t IUHB(HuMm    1MuA   H|$XHcHD$`    1Ht$`K  A  HD$`HD$8  Ll$8D$4    E11DLM@ H8fD  M|$IE  BD uI$MuL  @ IFI7  DG tA L-v    M   1Lt$(D$0R    IF(   Ht,I~DD$$HL$HT$Ht$Ѓ   A@Mm Mt2@t-MuI~ HtLAǅtMm E1   Mu΋D$0Lt$(DuM~MfEfD  Hs H|$8AP   9\$4DDHD$hdH+%(      HxD[]A\A]A^A_ D$4CfD  L-Yu Mtu   Lt$(D$0(D  D$4   1HD$    D$$    HBs H|$8PHL$XHuH
 Hb    11tY  A8A-f     AWAVAUIATUSHXH$dH%(   HD$H1HHQLDH=}t  q  H11AH  HH\$L5Pt HD$HH           HMIH|     IMuafD  M?MtGMwHIv xuAoH$   H)AoN)KAoV )S AM?MuMtL5s LmD  MuH|$H$   1A1HT$HdH+%(   uuHX[]A\A]A^A_f.     HQs Hl$Ht    HCH$   Ho)] o`)eoh )m AHHuu{Of.     D  AWAVAUATUSH8LL$H(  IH  Hp IIDōzIH  LHH$TH$A FHIDB     1     9sHHLH1Dr u)@ sHH41Dr Z  ÅuLE1H9}  9AM^DFEMtA;tRLHLD$D$C4 9!  HD$HtDHo LP1H8[]A\A]A^A_@ I  LT$L\$HH$t@   LDL$,HL$ HL$ DL$,HH$L\$aHL\$ HL$yHt$LLIō@$$DL$,<9LT$L\$ s\E{C@I  )LD9AGŉ$9ADFE    AK@ L1nHn LP1I~H.  1A  ff.     HDD$H։HxPLLL$RfHDD$H։HxLLL$2fAWAVAUATUSHhH4$T$ dH%(   HD$X1HD$P    H  H  MM  H̓D$$    H	  HD$I@HD$    H\$(HD$    DL$ Eu
H<$D$ L|$HHT$8  HL^8  ucHD$8HtYHL$E1HtL  HAHLd$ ATh   Ll$(AUL$@HT$ Ht$hH   A$L,$D$ HT$@L   H7  u"HD$@HtH|$HHL$PE11H  Ld$PM  L=n Mu  D  M?M  M  IuHtLtIwLuH|$ I}   HD$AH  t$h   LL$ L$0HT$AU _AXu1   T$$tH
  IVtHà	  I^HT$XdH+%(   *  Hh[]A\A]A^A_ H
  HD$I@HD$H\$HD$(    D  H
B  HL$PI@ HD$(AH  t$h   LL$ L$0HT$AU(Y^$    H	  H
  H	  HH
  H)H	  H  H)ց   H
  HAVAVfD  1LH  1Hff.     AWAVAUIATAULSHTÅt&MtyA`	  H[]A\A]A^A_D  M   H   A} uEEA  DADEAAuZEu
   fD  DMHUI  Atm ÅY[f     MHUDI  :AEu
DD  MHUDD$I  DD$AtEuɃs뾻ff.     ATUSH%k HtCL%Ii f     HHH  HBHtH
f HzH1HAT$HuHj     []A\ff.     fATUSH dH%(   HD$1H  HHH=     Hf HL$HT$Iؾ   H8Aą   HD$Hx  t{H|h   HH   Hx  HHPD HD$H  Hj H-j HE HD$dH+%(      H D[]A\D  Hx( zHHS  11   A?N  D  AHH  1   1N   H  111AnAcff.     Ht#Ht~!HJf    H1fD  ff.     HH1   H  M  1Hff.     @ AWAAVAUATE1U   SHcHHH8  dH%(   H$(  1CLt$ D$HD$L$   HD$L   LH   LHHHH	l LD$|$1LLL|$H	Ġ   Ld$4t8tct>H$(  dH+%(   uZH8  []A\A]A^A_  n    s NED  H@H#l Hff.      AWAAVAUATE1U   SHcHHH8  dH%(   H$(  1CLt$ D$HD$L$   HD$L   LH   LHHHH	l LD$|$1LLL|$H	Ġ   Ld$t`udt ttQfD  wCH@H#l HH$(  dH+%(   u$H8  []A\A]A^A_ n   f     AVAAUAATAUHSf.     EuKHDnxtXHcH)u[D]A\A]A^f tăt[]A\A]A^ÐDDUtf.     A)ff.     AWH
)  AVfHnAUATUSH   dH%(   H$   H  HD$     fHnfl)D$H  IH  H  H1HLd$H   H  LH   9t-H$   dH+%(   L  H   []A\A]A^A_@ 1Lp  LH   _uH  HT$0LH    xHT$0H  H  HD$8HtkH8HtcHtHYH|$H tHt$PHt
L6Mu_H  Ht$D$H   HRPh  D$Ht$PH  L6M  Ht	H  H|$H tH81   IH)b IH  L$   L   LL   H5C  LDHLAoI|$LAD$ AT$I$!   IIFI3T$I3D$H	u-IVIFI3T$I3D$ H	uAD$(A8F ttf.     D$H`a LPD$H|$H Vf.     H8HVH|$H qt 1 AUE1ATAUSHH H{ uHD[]A\A] tDu1_    HDO#u. tZtHA[D]A\A]f     HSA9|HC    w     HHH)HSW    J_ 
~=_ 8AWAVIAUI   ATMUSHH%  H<$HL$(HT$ dH%(   H$%  1HD$0    HD$8    *  uH|$(HL$0E11H  T$ Hl$0H  HIHk  H$0  k   HBƄ<0   @   LHt01Ht$8L5  q  Ll$8@   L|  L`L
IH=  -  LHH=    HIH=    M  LHD$HH=    LD$Df      DAE)A9  AADE)A9  DD)D9|  fAfH$  fD$  AU fftIHAU ufAHtfD  IHAuf8Ht     HHuf0HXMu
HIA$u1Ҿ      LAă=     L$0  H|$BƄ$    LfT$@k   Lt$@LGn   LDDB 2  H$  HH$   DH)H$   1H$   	  11Ht$   DfD$5  T$ffT$f.    H$  Df9G1fT$D$9   DƄ   @H|$8Ht1f$  OKtH<$1   H  TH$%  dH+%(   7  Hĸ%  []A\A]A^A_fD  D1[@ fo  Hthd/mux )$0  H$?  zH<$H0  11H|$8HtmDlH<$11H%  DNH<$11H  D0H<$HH  11]H<$H  11@fDH<$11H  EH<$H  11,@ AUAATIUHHSH(   dH%(   H$   1H   DHÉL$$HD$9   H\$     DHxcHcD =  THL%+  tC H
 tHH<
u ?.uGt.LFtCHu1H  1H
H$   dH+%(   u)H(   []A\A]H     Hff.     @ AWAVIAUI   ATIUSH   H<$HL$(HT$ dH%(   H$   1HD$    2$  uH|$(HL$E11H:  T$ L|$M&  LHkL  1Ҿ      ÃM     H|$2k   LƄ$    Hl$0fD$0?11        ߉1ck  n   H  11   3     ߉1g  >  L?LI4LH)AT/	   L$   ,L  1LA         LtHW HcHt$HHH   H  AVMHAUL     HP1ATHt$(H|$ H HAAHjW HPH$   dH+%(      Hĸ   D[]A\A]A^A_     H<$H  11-xA띐L=  L|$    CH<$H  11 #H<$H  11H<$H  11H<$H  11Yf     AWAVAUATUSH   dH%(   H$   Hi  HD$    HD$H  IH  HH  IH  H  HT$ Ht$H   Å%  H|$    HD$(Hu  H8 k  Ld$PL$   LHHLH-  xHD$(HHpHL[LLL$   I  Ht$H   H@Ph  H$   HD$H EHH   H1HII9uH|$    LÅuFH$   dH+%(      H   []A\A]A^A_ 11H  Lu   L1H  Ht&a     L1H8  sAǅ`	  hH  1L1KKD@ ODN   AD1A!A   D!Ⱥ      A         A@   @      A         AuvumA   ubuYGDF   AE1D!u?E!кA   u.F   9r9rA   A9rD9҉    H	U HtdUHSHHXHt6fHSHBHHt1HtH  Hz HHЅuH[HuH1[] H   []@ 1ff.     fAWAVAUATUSH8dH%(   HT$(1Hv  HHj  H5VT IHL$ HT$LD$H>   ЉD$  |$:  D$1,   @ M^MuH`AEH\$ 9l$   HQ     IH   HD$ 1IvLIF(  upL-S D$H\$ M]AMtIsHpxMM[Mt @ IsHLMM[MuM^MwG    HAQ LPD$HD$(dH+%(   u\D$H8[]A\A]A^A_ALH  1   1U7  D$LH  11   17  D$fATUHSH  Ht!H@H@8HtH  Hh  HrH  Hǅh      HtL%nP AT$H  HtH1  L%MP H  AT$H:R H  H;XtHtL%!P HH[AT$Hu[H]A\+   0    SHWHH5     1H5     1H5  1   HCH   HH   1H5  H5e     1HC    @  g  7         @  H5     1<HC    @0            usuFu)
   [fD      H=  \@ H5     1 H5d     1HC|   @    H5.     1HC|   @i@ H5     1]HC|   @<@ H5     15HC|   @@ H5}     1
HC|   @@     H5<     1HC|   @    H5     1赿aH5     1蝿HC|   @5@ H5     1uHC|   @@ H5Z     1MHC|   @@ H5&     1%HC|   @@ H5     1HC|   @u@     H5     1оHC|   @@ff.     @ AUATUSHD-_N E   AD-KN    H=^N L%WL H_HtGfD  HH[HUHB@HtH
-N Hz H1H}AT$HAT$HuH=N B-  H=M AT$HM     HD[]A\A]D  HA   [D]A\A]Aff.     USHHM H-M H; HU t:   Ht"҅uHM H; HE     H    tH[]    Hu˸@ D$D$H[]@ ATUSH@dH%(   HD$8H   HD$     HD$(    H$HFI HD$H  HD$HH HD$HL  L   HJ H=L H    HL     L%L HL HH   ZL    1L@(  HHfL H8    H@    H5]T  H=]  @    jL*  Åt,HD$8dH+%(      H@[]A\     H-  HH--  HHH  ÅuHK H
;HHK H
H2F  fD  1ۉ}K qb褹@ AWAVAUATUSHh  HL$
DK Ht$H$  DL$dH%(   H$X  1D$,    HD$@    b  Hd  IHX  H
I IMǿ  HE H  HxH     E1Hǀ      HH)  LHH   H] HCHH Hǃ      H  H  HxH     LLdHǀ       HH)   LL%BJ H   H} ATAWt$(AVLL$(T$4A  H AŅtHHE HtE  fD  H$X  dH+%(     Hh  D[]A\A]A^A_@ H} L%  H} Hk  H  HxHL$8   HD$H    HBHT$0s  u4H|$8HL$HE11H  T$0H|$8HL$@1E1H  T$0H|$H   Ht
   1谸H  H|$@   IH  D'E1Ll$,E%  D  H|$莺H|$H @ EgIEtIDP tHH L`Mu}   fMd$MtqH|$@ID$LLH)H0F  tHF     H  Ao$ IT$H@    HPH   8  MtIF  IL|$@E'EtO¹IH f     L|$@E'IEt&IDP uH|$@D'IEfD  H  H} H   H  L$Ll$P   H      H   H@	  LHP 11H1    fGLi    LH  1  AŅQH}    HIE H} PHE     11H     +  H  D`	   HG HBRH    AH  1AkAAH} Ht&  HA  1誸HE Ht
ǀ`	  AlAaH     1*  չ  Huc DF E(  ATUSHH
  LMHu   p     HtHE     MtA$    H  Hh  IILZHp  RHH  ATAS0Y^uKH}  tT  u	    Hx   t
H   u"1H  1Hy`	  []A\ CuH
  HM A$    둹  H1     15ǃ`	  @ 1H9     HL)  D  AWAVAUATUSH   LD$HDD HT$0HL$8LL$XdH%(   HD$x1E  HH  IH  HD$0HtIH8 tCH|$8   H  H@@  LL$HLD$811HL$0jA)  f 	   	  )9¸    CE1D$DH  H    HXAA<$ L  LIHxS(HD$ H  XD$@    IHD$ Hl$PHD$    LMIHD$(DMfD  M1E1A I9   K4&HU LIru@_@-tII)tJL1Iv:J|	   LD$H5w  LL$H$LD$LL$H$A9tLI9zDMǅtW1PH|$(LHLD$L$WHD$(L$HD$LD$B JDHD$(D$@ADǉD$@@ H|$ Hl$P  H  H   Ht)H|$   |$@up  D$   D$    L  H|$dH\$pIMt[fH$Ld$ E1LLLHIEHH0?     HD$IMdI9uH$D  MmMuH1H  1̳H  H|$ H@P@A  fD  H1D$@HD$8H     HD$H     A   fD  HD$xdH+%(     HĈ   D[]A\A]A^A_    IEH$LpM  I6Ht3Ld$hfD  HLH	  IvIHuIE|$D9x	   	  ; 	  rAEEHх|$H  tHP	   u@t	 t	L  AI$    tT$dҺ   DT$T$H|$XHtH HMNH}I<$HP	  AD$8HtI|$AD$<H  I|$׭o 	  E|$pLAD$@D$Hh  o	  AD$PA$   IEAL$`Hx L  P(AąufH|$8 t(H  H@@t/HD$8H     HD$H     H  H|$ H@P@LL$HLD$811HL$0HOAH  H|$ H@P@ED`	  @  L5H  
KArH|$ AP@A봹  H     趰ǅ`	  A1褬HBH|$ P@ AWAVAUATUSHXHL$
7> Ht$L$   H$LD$LL$ dH%(   HD$H1^  HHG  ?  H|$ H  HD$ Ht     MtAE     H$H  L  HHE 	  H$ 	  )9¸    CD$(M~  D  En  HD$A   HtHzLpH<$A1McdLIGH8TMMuHT$M1HtH2LH	  H	  HT G  Aą  Ht$H	  H  rL  1MtvL$MDd$,     IFLxM?  I7H   Ld$@Hl$8    IwIH   LHHa  tMvMuDd$,H|$ tH	  Ht$Lt$ H	  MtH<AHD$HHD$HdH+%(     HXD[]A\A]A^A_ IFT$(9P{H#	  jHtHP	   TCt	 EMtAE T$u@H0H	  `MvD$   MfD  @  L=  H	  H4$IF _  H  11HAKǃ`	  A  1HH  1Aǃ`	    H     ǃ`	  AA  H     1軬ǃ`	  貨fj:    H{: ATUSHXHtDL%g8 1% Ht;HSfHn~fl H[HtHſ   A$HH	u1[]A\ H]@ HHAT$H[Huf1ff.     fAWAVAUIATUSH8dH%(   HD$(1HHLDH=9  T  H11IAH   HHl$H
9 HD$HH$H   @     H裧IH$LxMtsA$ IMuW MMt;IGHH0xuAoL   H)E IGHEAMMuMtH8 H$Lt@ MuH|$L   1A1HT$(dH+%(   uZH8[]A\A]A^A_ H8 Hl$HXHt oL   H)M HCHEAH[Hu뎸s    f.     1ff.     fff.     @ HtH\8 HtH1øøff.     fHtH$8 HtH1øøff.     f1ff.     fUSHHHHug@  u_H=   HpHt#HHtHkHE 1H[]fD  H=  <HHtHHt7HE ʐĸfSHHX  HHL  H   H|   H[  H@	  H   HH	  H   H H   HHu   fHHHH   H9uHHH
HPHHx [D  HH  H
  HDHH1[f     H9tHHHu_f.     Ht(A  1HH$  1%ǃ`	  [@ H   w,H   H   H1Hg    H@     H     H	  1H5D  HtBvH@  tH  tH    H1H  H       1hH H	3 HH3 fH3 HH3 f.     H  HHIHH    H1Hd  H       Hǃ`	  Ht%     H1Hx  賦ǃ`	  [f.     ATUSH dH%(   HD$1HtPHHH  fwHx  HcHD  +     H1H  5ǃ`	  AD  HD$dH+%(   n  H D[]A\H(	  HE D  E1H 	  H] H 	  H] ?  H  H   fHE H  HufD     H1AH  脥ǃ`	  UD  H  Hu?Q  H  H   HE R?  A1  1HH  1AD`	  G v  HE  H] HP	  HE ?uH  HE HÐ  H] HÔ  H] Hx  HH@	  HE HL$HT$   8Aą   HD$HE gW   H$H] O\  H  H{H@H HE Hb   H  H>H@HE H  H	H  HHGHE Hh	  HE fHE      11A1  HK  HKE"(D  H  H@HE 4@ H  H2k H  H@xHE @ H  H   HE H  H#  Hw     譢ǃ`	  s衞AWAVAUATUSHH  H  9HIAHMM   DHh  MLLЋU u'U y`	  H[]A\A]A^A_     H  A$H  H4H9  s3H- H  HPHH!  H  A$H  Iu H2H  A$H  H  IU A$1E H[]A\A]A^A_@ AH  H  HtZH9  s6H   H  H  H-- PHH   H  A$Iu 蚞H  fD  H   H  H  H, H  HHuO  1H=  1Hˠǃ`	  v  H
  A  H5)  H=5  	\  fAVAUIATIULSHtZHHtRHIHuED  HCHHt3HuHCHtLH{ILLLЅu[1]A\A]A^ L1vI$HHtHtE  []A\A]A^f.     H   AWIAVMAUIATIUHSHH@	  HtNHHuD@ HCHHt3HuH{MLLHSuH[]A\A]A^A_    IH	  MLLHH[]A\A]A^A_@ Ht?t&H  9   |#wiH
  HcHH  9pH}1Ð%   HH1   H  1Hf.     #   f     $   뾿'   fHtgH1Ht1: t$SHMt+D9u&Ldu[fD          H1H  1=ǃ`	  [øff.      1ff.     fH	, H8 tfH, H8 uHl) H8HpHPHHff.     ATIUHSH螙MtI$xH) HE HHtH1[]A\ø    H   USHHH+ HtH1H[]fD  [ԙ9t(H=  1H5P+ [uH@+ fD  賚9uH=  ̗HHu벸ff.     H   USHHH* HtH1H[]fD  軘49t(H=  1H5* uH* fD  L9uH=$  ,HHu벸ff.     H   SHtWuFH=>* HtH' PH$*     1H5* H#uHH' 1[D  H=) HtH' PH)     1H5) HuH[H\' 1뱸f.     Ht
HA  HHt D  HHt
H=  H8Ht
H  HHt   Ht   MtA    MtA    H  AVAUAATIULSHHHM   H   	    H  Ht8DHh  ЋU uI$    y`	  H[]A\A]A^fD  D9   H	  Ht;ELЗH	  B0 H	  I$1Dm H[]A\A]A^fD  H	& Ht$zHt$HH	  Hu1x  H]  1Hǃ`	  L1_     HH  輙ǃ`	  1H  1蘙ǃ`	  H  1vǃ`	  @ LA' A DHEuH$% H8HpHPHH@ Ht{ATUSH? HtfH-'' L%$ H} Ht?AT$uFHHtHPH$ H;PH    [H} ID$]A\D  A$HE HHu[]A\ ff.     @ USHHHP	  Ht
H-d$ UH(	  Ht
H-N$ UHX	  HtHH-5$ Ht
HUHX	  UHh	  Ht
H
$ PHp	  Ht
H# PH	  Ht
H# PH	  Ht
H# PH{Ht
H# PH  HtH# H@H[]fD  H[]f     Ht
H׽  HdfwHB  HcHf     H  H  HJ  HR  H^  Hh  Hw  H	  H}  H1  H  Hi  H  H9  H  H  H  H  H  H)  H  H  H  H  H  H!  HI  H  H  H  H  H  HQ  H@  H       AUIATUH  SHhL%" ~% ~-  ~5  ~= % ~ ~
U  -  )d$P52  = t  )l$@
p )t$0)|$ )D$)$A$HH  HhHxHfHnH  H! A$A~L$Hk[ fo\$PA~T$~@fod$@Hǃ       fol$0fot$ [hAT$@H@fo|$S0fo$K@HC`HN CPH   H cxH               H H   H H   H* H   HdH   H  H   H H  Hb H  H H   H H(  H H0  H H8  H H@  H6 HH  H@ HP  HB HX  Ht H`  H Hǃ      Hh  H Hǃ      Hp  Hǃx      HhH[]A\A]f.     H	LfHnff.     USHH-+ H|! HE HHt H
HxHH Ht$1H[] HuH1HE Ht>H5H=  ՒuHHtHH[]@ Hq H Ht7USHHH/HtH}H HPH    H1[]øff.      H=  SHtH\ PH      H=  HtH; PHm      1ƴ1  HH  H H;PH= H    8H=A  HtH PH'      [D  USHH HHtKЅuEH H- H    H     HE HtЅt:H; u*H}  u#H[]鲎fH- HE HuH; tH[] Ha HE     H          HtH8	  HtD  1D  HH H Ht1Љ¸   uH H Ht1ЅHfD  1HÐH Ht*HHu f.     HGHHtHuHHfD  HY HD  H) Ht*HHu f.     HGHHtHuHHfD  H HD  H Ht*HHu f.     HGHHtHuHHfD  H HD  AUIATIUHSHH?Ht=HH9r
1H[]A\A]HH9rH PI$Ht%I] D  Hq I$HtIm IE     ff.     @ AVA   AUIATIUH-  SHHtHHIHLLIT,Aąu%H;HI} fL3[D]A\A]A^    A     ATUSH   dH%(   H$   1H   H`	  11׌D`	  A   IH      PLʹ     L1NLFHh	  H7H	  Hp	  lHMLu^HM   HHp	  h	  Lr  HHp	  LH$   dH+%(   u!HĐ   []A\fD  1A3ĉ@ AWAVAUATUSH   t$H$   L$   L$   dH%(   H$   1HD$     HD$(d   HD$0    H  H5 HHӿ   HD$ H  HHL$@HT$8H   I  H|$8   H$   D$H   HD$PH$   HD$XM|  1HD$fLt$(L<HD$Ll$ A?%H-  tWfHD$0LLHL$HP'  HD$0A7HT$ HL$@4HHD$0L9   L<A?%uLD$D$f%LyHq
I)B<;D)ʍG<U	  HcD H@ HcHc@|fDf D$H/0  HT$XD$HD
LD$H|$p1         H|$誆HL$HT$0LLUuIIwI9   HD$0LLHPu$HT$ HD$0t$ HT$ H|$@T$8@ H|$ Ht
H7 PH$   dH+%(     H   []A\A]A^A_ C<8CD8 IM91  LHfD  D$H/;  HT$XD$HH
HT$0     D$H/#  HT$XD$H:ΉHT$0HD$H/  HT$XD$H:11誈HT$0HD  HD$0LLHPdHD$0HT$ Iw%HD$0!    HD$
2  HcfD$H/   HT$XD$HD$q HL$pHT$0D$p L9fHT$PHBHD$PD  HT$PHBHD$PD  HT$PHBHD$PD  HT$PHBHD$PD  HT$PHBHD$PcLt$(Ll$ If     Hh	  Hx	  HH:ff.     H-  AUIATUSHH  L"HM   ID$       HH1HHHPHH9uIT$It$L   I<$IT$1HHI$fD  H3HSHHHKHH9u1H[]A\A]@ H1    IE HtIfH@     Me ID$    >1It$LuI<$IT$1z돸늸냸@ AWAVAUATUSH   T$(HL$ LD$dH%(   HD$x1D$\    H=  IIH  H  M    	    H     HD$`    E111HD$`E1Lt$\ID$,    IHD$    DA$  A}H|$M
ISHH9  H)AUHD$hIHD$`9T$,sWH LT$HLD$@HH|$L\$8HL$0T$,PT$,HL$0HL\$8LD$@LT$H  T$,HD$H  HD$|$H(HL@   E  HD$foL$`LLT$8LL$LD$ L\$08HLL\$0LT$8M  T$A$  Hl$hHl$`HH)I[IҋT$(LT$D)Ll$ T$(@D  LL$ML   LLHl$`H)HHD$h
   A$  H9rH۸    LT$IHDE1D$(A9MMHt1LD$hLL$HL$\LLD$ Ht$`   Hl$`umD$(;  HD$Ht
HH P1fD  HD$xdH+%(     HĈ   []A\A]A^A_     Dl$HR H|$HtH L$PL$yA$`	  @ T$H1E.Ht$HH1AoHH9u     t$(HX	  L-u%I$X	  Ht$ 1HH@HHt$D$A  1LH  1L$FLL$LD$ LLT$(HL$\6HD$Ht
HH P  H  11L蘃AǄ$`	  z     L1H,  gAǄ$`	  IHb  11A/:f.     SH dH%(   HD$1Ht{HHtNtJHtEMt@H4$   HHD$xHT$dH+%(   u@H [fD  `	  ܹ&     H1Hb  蝂ǃ`	  ~ff.     @ AWAVAUATUSHX  dH%(   H$H  1HD$    H   IH#     HL$?;u   ;tHH=  tTAT uLc;HBD4@ LDO|5 M'Et_JHKD5
L HEtCBDbuAH$H  dH+%(      HX  D[]A\A]A^A_f     fHT$HL$LH|$@D$D$$D$   D$   D$0FAąuLl$HtAU9r IuH~L虀_1LAE|D  USHdH%(   HD$1H  HHՃ&      H^  HcHe  fuBHt	:   H$    H(	  Ht
HI PH$H(	  1M    du#? 	    H  Bp1"@ 1H  1H
`	  HT$dH+%(   '  H[]    ?  H  H   1D  ?  H  H   1D  ?_  Hp  }  f  1HH  H  Ht
HD PH$H  H  HB1:@ H  11H,  H{$!  H}C   Hǋ}  H  H{ zC@1f.     H  11H;  HE  !  H|C    Hǋ  &H  H{(QzCD1]    ?   H  HtH$
 PHǃ      Ht
}    H  H@    @4    1 f.     ?  H  H   1fRu1E t*1HY  1}ǃ`	  fD  oE ; 	  oM	    H  oU PPo]X`1]    H1  11H}6fD  H  11(}fD  G    6  H  H@     @@    1G     >  zH  H@(    @D    1     H     1@ 1HHT  1Hգ  1Hc|ǃ`	  M    H  H   11 H  H   1 H  Hhx1fD  H  oe ``omhp1     H  H@(    @D    1 H  H{0wCH1fD  H  H@0    @H    1y H  H{(PwCD1\fD  1H  H   H  H  H}wE41k     H1Hȡ  {ǃ`	  Hk  1H1zǃ`	  H5  vi  B  8fD  AWIHAVIwAUATMULS1H8  H$  L$p  L$x  HD$H$  HD$dH%(   H$(  1Avn  I 	  fL   Ix  IǇp      HHD$DIǇ      ) 	  1HA_LA 	  zÅt8  H$(  dH+%(     H8  []A\A]A^A_    L	   LyÅuHD$ffIǇX	      IǇh      Ix	  Ih	     I@	  HD$IǇ0	      IH	  HD$M8	  A 	  PAh	  fo.  AǇ`	      Ax	  (  I	  Ip	     Å  Ih	    Ip	    IǇ	      HthHIP	  1IP	  w  @ Hџ  1L1]xAǇ`	  ~A`	  r@ A?tIǇP	      Xf.     Ld$ H   1L   H1    fGL2(  u<IP	  1L
MfD    N  D  :sD  AWAVAUATUSHdH%(   HD$1H$IQ]  IM[  H   If     Ml$M*  I,$Lf     HCHt7HH;H)tuH- LUMt1MMmf.     LHMHL<$H@    MuM   L1@ H@ӍRHuH= H- HtUH     HcHHU H HtsH1H1rHH
 MMgILHHUMu1HT$dH+%(   u/H[]A\A]A^A_ LLM$I0qH5     1sff.     H      AWAVAUATUSHL|$PL\$XH!  HHIMM΃      HLHMASMLL\$Y^L$x3L\$PHMMLLHH[]A\A]A^A_f     HLMMASLHHL\$n`	  XZL$ASL\$AWHt$V  AYAZH4$L\$xlL|$PMMLL\$XHHH[]A\A]A^A_V  t	  HL     1tǃ`	  H[]A\A]A^A_f.     ASMHMAWLHHt$SV  `	  _AXL\$H4$`ff.     AV1AUIATIUHSHHv#LrH5*  J<7 oIDރAE HoH1H9rHHLq[]A\A]A^f.     fAWH5  AVAUATUSH(  dH%(   H$  1     qH$  D$    ILd$D  L   L8pH  Lo|
uD \$t}rLL8D  ]HtHADG u#tE tHH     <-L<_Cw@@utZtrH BCHuLﻜFnH$  dH+%(   1  H(  []A\A]A^A_ <:uHC LsufIFItADG uLnIDI9r      HL9tHADW uHc)  H=*  9T$u.D$dH  Hct$HPH  HHtmHc  HH41HÅuAHc5  1LHH5  HÅu  $L1"mLmLm9m   ff.     @ AVAUIATUHc-G  S~;HC  HD7IH HH9tH3D:6uLmuLk[L]A\A]A^   H=  ATUS~{L%  1fHHH/HHtHAT$H=  H/H@HtHAT$H=  H9  AT$[]H      r      A\    L%	      Mt+Ht&HFPHtH@HtH(	   tI     1øø@ HFPH@H(	  f.     Ht+USHHH?H-  HtUHEHH[]ff.     @ AWAVAUATUSHHl$PH  HFPHH  MLHM|  H    n  MIMMT  HK  I(	  Á @  E  H<  Fl   I    AE     M   H   E   I(	  I1LϹ   Ѕu9E    HE     HE(    HE0    HE8    HE@    ǅ       H[]A\A]A^A_H5L  LL$_kLL$XHk  1L)nf.     I   DLLЅuHCPI   1HxH(	     9D  H   []A\A]A^A_@ OfD  ?ff.      AWAVAUATUSH(dH%(   HD$1Lt$`L|$hHD$    HV  IH~HHC  HGH6  H    (  MMM@@  M  H(	        I    HL$1Ҿ@  A    LD$<k  é   LT$MtI:HtHEP@LT$I    !  H|$HS  nhPAIuLÅu\HUHt$H   HzHtk> tf1M   Ѕu'HE1M   HxH(	        D  HD$dH+%(     H([]A\A]A^A_ 1H(	  M   ЅuAIU  IE I$A   IG     IG(    IG0    IG8    IG@    AǇ       o    H}j E1E1j H
  H̝  Lj j j j j j  n  H@E*f   1@ I} AHt$hAf.     fD  fHtFHFHt=SHH@Ht=Ht8H(	   t5H     Htf H1[øø[ø[ø[f.     HIM@@uSHtNu!H     H1A        H1Iy1Hy  A  H@ fHt3Ht.Ht)Mt$u'H     H1A    D  fHI1HH  1A  Hf     S1E1f.     DAAHDF|DADD	LH9r[fD  fo  AWIAVAUfofofoATUSoofo^ on0ffqDffqGfgfgfo3GfoffD!ffq3GWfqfqfgfgfofoD1ffffqfqfgfgfqfgfgfoffDofDofof`ffD`fhf`fhfhfD`fhfofEofifafDafDifrfAqxj׋_fAfDofifEofrfDifrfAfDafAfArfDoffofDafafDafEf~T$frfAfifqfAfDofifA~fDofifrfiDfrffDafDfDaffpU!3Wf~L$f~ȋAfo̍Vfjfpf~f~L$fpUp $Df~1A1fof~d$ԉf~fj!fArf~L$D1fEA?νDfAf~\$!A1f~fp1|
1!A11э**ƇGDA!1A1f~fpUF0DAfA~f~L$fo!A1fj1f~fpf~DFDfA~!A1DFؘi
1fA~fpUD\$!A1f~L$1DF&DDA!A11DD[DfA~!1B\DAA1A!A1AB)"kA
1AD!1f~foȍ>qfjȉDfA~fpD1!1B CyD1!D1f~E !IAA1A!A1EDL$A
AF	b%D1!1DDL$DF@@D1!D1DFQZ^&	1D!1DGǶAA1A!A1ED)]/։AAD1!1DDSDDD1!D1DD؉	1D!1DDL$GAA1A!A1EDL$D\$AAF	!D1!1DF&7DD1!D1DDL$	F
1D!1DDL$GZEAA1A!A1EF㩉AAD1!1DDD$DFD1!ogD1DA	A1E!G)L*A1EAA)B9AAD1A!A1ED\$AED1A9|$>qDD11|$A8"amEA1G!8A1AA1AD1DDL$	F	D꾤DD11DDL$BKEA1E`KA1AA1AD1DDpB~(D\$DD11DEG'	A1A1AȉA1AD1DDL$B0ADE1A1At$A7DA1D1t$	E09ىDD1B)1DEA1A1AA|AAA1BeVAE1AɉAD1ED1A6D")DDt$	D	D1A*CDG!#AADL$	1D
	1DD)9	1DF.Y[e	Ή1DF2Dt$	1DD}\$
	1DF	]DL$	1DF6O~oAA֍,D	1D	1ЍCϋ\$
	1׍N\$B~SDL$	1щ	15:B*	1[]
A\A]A^	1B	ӆAfn	1A7ArA_fnABfnfbfnfbflA
ff.     @ fo8  HG    ff.     AWI1AVAAUB    ATA@   UHSHG?ȋO@ƉGDA)ȉGE9s7H1HDI1EtT HH9uH[]A\A]A^A_E1H    ADHI9u1HuHT$\T$   )D9rFt2   |D  E1K4/H'DA@D9rE)D   G     AT   UHSHHHdH%(   HD$1IL~C?7|   8   )HH5  ]Hߺ   L]HH1   4H{H    1HHCP    H)KXHHD$dH+%(   uH[]A\fD  x   )Yff.     @ AVAAUATUHSHH  dH%(   H$  1A@!  fƄ$    Ƅ$    )D$p)$   )$   )$   )$   )$   )$   )$   M  Ll$pLHLL$   7ZLHL)Zfoq  fo
y  LLH$   foHHf)Bfo@f)@H9uH=\@   LH5\HXH!\@   LH\H$  dH+%(      H  []A\A]A^IL[DHL[Hl$`LA   H+\fƄ$    Ƅ$    )D$p)$   )$   )$   )$   )$   )$   )$   L$   Ll$p~Wff.      UHSH   dH%(   H$   1HHHHUHt$HHɉJHTɉJH9uH$   dH+%(   u
H   []Vff.     H    HH1HǇ       HHH)   HɉLɉLXHHuBh   B   @ UHSHHXHZHHߺ   CZHHH[]Zf.     AWAVAAUAATIULSH(  H<$dH%(   H$  1@f  fƄ$    H\$Ƅ$   )$   )$   )$   )$   )$   )$   )$   )$     L$   DLLHT$L$   VHT$LLVfo7  fo
?  LLH$  foHHf)Bfo@f)@H9uHY@   LHXH4$DHXHHIYHX@   LHXHHߺ   XHHYH$  dH+%(      H(  []A\A]A^A_H\$HpXDLHjXLd$pHA   LXfƄ$    Ƅ$   )$   )$   )$   )$   )$   )$   )$   )$   qL$   L$   	Tf     t	H  FAIH!MtA 9   vzLc   HH?A BGO0	HA BGO<	HA BG?A Bwt>H
  ?0t(B=   BHB= 1     w@	?BG<øøAWAVAUATUSH(dH%(   HD$1H  Iхn  ?
     E1L  HD  1HHuHc$H   A,@   HcD$   A   HcD$=      E$A   Lct$A=1  A   IcA<t}E1A׍    AD	AAC9  D	ACAQ9   A=   AAIAG
$2EaA9   I   E HT$dH+%(      H([]A\A]A^A_      MtA     1D  |$=u    A	AA9sYwIA   A MtEtEq   l    A   D  IA/@ ;1A Mt1A wP    I1A   t|1A<@yc Du?t:fD  A      u9uB9r1     f.     B9r@ AU1I1ATUSH(dH%(   HD$1    fWH=  QtGAL       H~&HH)tHHDUPHuN8tD
P1HOtG1PfAnE fnffA~E NfA1EHD$dH+%(   u?H([]A\A]@ H$fA1E NHT$fA1UHHHfA3E1fAEN H  SH   HHt@    1[ø[@ Hy  H?` HtBHt=A   G   D9DFt%1ffDLHDfOD9r     HtKATUSHHHt/GIt9t!H,    LHPcH9uH[]A\     T$T$AD$   AVAUIATIUSH dH%(   HD$1H$    ,   tHP	  HthM-9s)1HT$dH+%(      H []A\A]A^fD  ILOuH<$Ht$   ^QLnPH|$NޅtNI$P	  HtAPL     Lt$LL$H1KLLL[f.     H   L1t$LL$L  HKXZLff.     fHt[UHSHHtAGHtKt31ɾfD  HH!<@)f|
 Hf1<CH9uH[]D      T$?C   T$f1L    HHt*Ht fD  r@w QHuff.     fAWAVAUAATUHcSHHLuN<3HxdH%(   HD$h19NA Aąu.   HKHt4HNHD$hdH+%(   	  HxD[]A\A]A^A_fD  1HL$(HT$0Hfo  D$@    HD$X    )D$0fD$HMtEtA@ HL$(HtvHy Htm.   HL$H|$JHL$HtOH|$HL$H|$JH|$HL$I9r,HHHHL$IA H|$MfD  HMEI =   SBJfODN   AD1A!A   D!Ⱥ      A         A@   @      A         AuvumA   ubuYGDF   AE1D!u?E!кA   u.F   9r9rA   A9rD9҉    H=   tfUHSHHtHH  Ht.@ HKHAPHtH  HyHЅuH[ HuH1[]D  H   []@ 1ff.     fAVAUATUSHdH%(   HD$1H$    H  HIHL  LnM?  HGH  oP	  o  o 	  o	  HH   	  fFV`   ^pHu!fD  H[HtL9#uHSHtpH$ 	  9   )AA9U  IEXHt{I}HЅtnu4H     HG  H  H@    L HPH  HT$dH+%(     H[]A\A]A^ IEXE1HuH$Ht	Ht~HCE9u[  A|$  EtAE ttAEt	   	  ; 	  rEAE!Љu[AE  1Mf     H     H   fIn$ H  HPH  LfD  1Hg     HbJ  H  1H9Jǅ`	  D  1     HH~  Jǅ`	  }IM H  H1   IYH     H1IIM H~  1H1I H  1H1I   H5~  1HkI-iEf     AWAVAUATUSH8dH%(   HT$(1HD$     H  HH  H5  IHL$ HT$LD$H>   ЉD$t	_  DL$Aw  D$1+   Ls I\$IhAD$L\$ 9l$   H  (   HH   f1HsLH@     HHD$ HC藪   L%  fnD$fnT$L\$ Mt$fbfMaIvLMMMv MtIvLMMv MuLs I_      D$    HD$(dH+%(      D$H8[]A\A]A^A_ÐH  HPD$f     ALH|  1   1赹D$A   L   1H|  1苹D$f9Cf     AU  ATUSHH(dH%(   HD$1HL$HT$违   H  H  Ld$L   1HtHBH  Hx  HAUPD  UHt$0L  AH yHu#HT$dH+%(   uWH([]A\A]     `	       Ht(AP  1HH$|  15Fǃ`	  'B    ATIHUSHALHHHC1uA,		[]A\f.     AWAVAUIATUHSHXHt$DD$dH%(   HD$H1HGHD$@    HD$EuHcAD$H\$8HT$0  HH%u7HD$0Ht-DD$Ht$8LHH  L   HT$Ѕ   HT$(Hپ   H՛  L|$@M  A? +  L%  I4$MHu        IvIHt)LtHL$Ht$LHL  AVÅufH5d  Lgt+1HD$HdH+%(   >  HX[]A\A]A^A_@ H  H   HtT$LH    E7EtOCHD  EwIEt2IDQ t	D  IItDA uA?     L|$@LHy  H1      H1H}  C`	  
H|$8HL$@E11H}  T$(L|$@MdLc  LT$@MZ1H}     H1C*?f.     AUATIUSHH{BH
fD  HHHA uHE1   u  HEHtKAII} tH  HHtLHH@B( HI,$HH[]A\A]fAEIHc@ AWH5g  AVAUATUSHH  dH%(   H$8  1@H  HHD$0L5`x  HD$Ht$fD  HT$H|$   ?H  H  (   IH:  H}  h   IE IH  HxHH     Ld$(HH@`    1LH)hHH|$iH|$(LIEXH|$(
   LI>H|$(AG?
tmLl$H-i  f     LHu HHtlI    IuIHtSH;<uAEA	GH;H|$(?
uLl$HQ  M}HPIU @Lh     IIL   11Ht$HU<H$8  dH+%(   u"HH  []A\A]A^A_Ht$1ȃ[<ff.     AUATUHSH     H  Ht!H@H@0HtH  Hh  HrPH  Hǅh      HtDL%  f.     IH[I}HtH  HpPIE H@P0LAT$HuHǅ      H  HxP責H  H    tHǘ   }?H  HtL%B  AT$H  HtL%*  AT$H  HtL%  AT$H  H  H;Xt"HtL%  D  HH[ AT$HuHH[]A\A]ED      SHWHH5Y     1<C    o  H5 y     1<H5Y     1o<HCH   Hx@ HLcY  H5t  HHNY     LE12<H5`     1<HC    @    S  #       @  H5a     1;HC    @D           S  "           HSHtH5x     1K;
   [`8    H=s  8@ H5w     1;H5dw     1:t     H5_     1:T     H5`     1:Q     H5T`     1:HC|   @@ H5`     1u:HC|   @@ H5v     1M:HC|   @@ H5v     1%:HC|   @@ H5_     19HC|   @X@ H5[v     19HC|   @(@ H5,_     19HC|   @@ H5^     19HC|   @@     H5^     1X9HC|   @    H5o^     1-9M     H5<^     1
9HC|   @@ H5^     18HC|   @@ H5]     18HC|   @@ H5]     18HC|   @@ H5_]     1m8HC|   @Y@     H5#]     1@8HC|   @$ff.     @ AUATUSHD-  E   AD-s     H=^  HtvH_L%  HtJf     HH[ HUHB8HtH
%  HzH1H}AT$HAT$HuH=  誦H=  AT$H      ^Kf)  6HD[]A\A]HA   [D]A\A]A@   f     AWAVAUL-&X  ATfInUSH   Dt  HT$  L$ LD$DL$$dH%(   HD$x1Ll$PHD$X    HD$p    HD$8    HD$@    )D$`E&  H=     HH{  ?  D$   D$ AD	  $     HHT$H   *8D$   A   EtH|$H    $   
  1117   H  H   E  Ht$P~7AE  H  L$ LHT$H   7Aąw  H  H   E  H   HHo7AąC  HH;r  H1   A   腩D$,    Q HD$H    EHm     H17ǃ`	  A   D$,    E1E1HL$@HT$8  H蓍   HD$8H   HH  HA$   L   HQDD$0HL$Ht$P_AYA    AHHDm  H1   蕨D$,L  Mu-      L  M
  Dd$(`Av  D$,A7  HL$=1HEI HRm     HPHL$ 1XZDd$(M M   IWLb@MtEtH2H|$HHT$2HT$uƋ$   H  AHzHPD$,PLL$(DD$0HL$AY^AIGHE.IH>p  H1   uAG    M M_Dd$(E   A   EyD`	  HD$xdH+%(     HĈ   D[]A\A]A^A_ 1HI   Hk  D$(E|$(IHo  H1   ǦfHHl  H1   触ZfD9l$,RE1QD  Ht$`3D$     HD$    AE_EHHn  H߾   1A   ?D$,   EDDxfD  HHj  H1   r11H5|n  3AąuH        H1H	h  |3ǃ`	  oAn   Hg     L3ǃ`	  ?@/AUATUSH(dH%(   HD$H'Y  H$Hf  H   H3  IAHL$   HT$詉   H,$H5n  H/   E <yt<1      H  Hj  H1   ԤHDLH  UE1E1H.ZYy`	  HT$dH+%(      H([]A\A]f     H|$HE11HZm  T$H,$H>1       UfD  <ou}n<1fD  <t*1qf       HDf     11ǃ`	  <-ff.     @ SHH  HHt<Ѕu/H_  H    H    Hb  H: u
D$k.D$H[ÐHA  H8H[    AWAVAUATIUSHH   dH%(   HD$x1H8l  HD$    HD$0H  HD$`    HD$8H$l  HD$@HD  HD$h    HD$HHT  HD$PH+  HD$XHw   HtH_,H=      t9E1վ  HD$xdH+%(     HĈ   D[]A\A]A^A_@ H=  褜AŅuMt0I<$ t)L@ HH8 tHx uA    L%A  HtH=  L=      7     AH%  Hn  1H5  NHW  H  H
LH   HHB    B    &H=ƽ   HD$(    IT  H=  谞H1  HL$(HxHL$HPAŅ   Hl$(Hu#!  f     HAWHl$(H   :   H*H   II)HhH=,  *ItH     H4$HAHH  H5  EHj/Li     1t$@Ht$ HB)I~H H޺   AVAŅCH,AŃ/HAWAv4     H1)I3fD  HD$(HD$H5gH=Q  -HL$1HT$    腄uHL$E1H3i  1H=	  T$ Ht$H   I~   AVAŅu[H|$	AEKHf  H
?HHE  H
H覵AAfD  HL$A   1H*e  1KA AD  H-M  Hl$(    AL}LHқH|$0HH"   A$A2(f.     AWAVAUATUSHhHT$H$   HL$LD$dH%(   HD$X1  D$,    HD$P      H  IH  H  IMο   HH  HxH     E1Hǀ      HH)   LHH     H+H  HA  HxH     LMHL[Hǀ       H)   LL=͹  HH   H;HGAWAVt$ t$ $   茰H AŅtIH;艒H  H;PH    HD$XdH+%(     HhD[]A\A]A^A_    H;L荔IH  HH  1I   HT$*HT$H   H  H      LHT$IxLD$H:V&HT$LD$H=͸  B0HtM? tH1H  zB  H  H  HzHT$&HT$LB4#f     Hǅ      HB    B4    IP	  LD$HT$Hz%Ld$HT$LD$MB8  1H  LLA%H  LB<H  HBLrXHL$8HT$0LHD$H       HD$@     uNH|$8HL$@E11HFM  T$0H|$8HL$H1E1HZd  T$0H|$8HL$P1E1H#M  T$0H|$@   Ht
   1C&H  H|$HBHLzPHt;<1<y  <t  <o  H5c  %  fH|$PIH  Lt$,HD$    &  fD  H|$T$'HT$H|$H fIWItDP tH  L`Mu       Md$ MtzH|$PID$LLH)H0۳tHг  (   H  Ao$ AoL$H@     HH     HL$HtHA   HD$L|$PE'Et>&MGH LD$PE IEtIDP uH|$PIH  o 	  o	  HRH$   P`H      XpE     AHǅ      Xn%111&(H  H
zH   fD  H  H  HP@H    ,A\AQH;Ht%  H
[  1C&HHt
ǀ`	  A)"f     AUATUSHD
  E  HH  IMHu    b  p    MtI$    MtA    H  HHh  MLQHp  QHH  AR(Y^ŅtZvDHh  Ht$H  HpPH  H@P0Hǃh      ǃp      y`	  H[]A\A]@ HŅuI<$ t
C     u	             uHx   t
H   u;HHF  11$Hh  H"ǃp      E@ H1[]A\A]f     ǃ        KJ  HX     1,$ǃ`	  H  H   H>@3H_\  1H1#Hh  Hmǃp      fH  H   H   L(L  LL HML1H\  1f#Hh  H@ H  H    xHH[  11(#Hh  HfD  H[  1H   H1H[  D  AWAVAUATUSHXHT$L$L$dH%(   HD$H1  D$$    J  HH  HH  MHu  H$HtH     MtA    HL  Ll$$IMu  f.     Mv M  IFLLHH0ޭtLH?AŅo  A~  Hh  Ht$H  HpPH  H@P0Hǅh      H  H  Hu=@ HGHHt,L97uH ]  HWHHGHh  H:  PHh   IFL  N  IFH|$ @k     HHZ  11!Hh  AH  H  HpPH  H@P0Hǅh      ǅp      EyD`	  HD$HdH+%(     HXD[]A\A]A^A_f.     H$T$MHHt$hAAvHh  HeD  HD$0    H=  HD$8    HD$@    I~HT$8H  AŅIH|$8HT$0H5J[  O  AŅ(HL$@HT$(   HN  LD$,H8T$0AŅ\$,~:IFLd$@H HD$@ AIhA9v  I<$Ht$uD9[  McI~KDm I\ HD$@HOHHH9H  H*  PH\$@AF    I^XHHHZ  11AHh  H
ǅp      .D  H  Hx11Lh  P AŅWL  tZH$Ht
H>  HMtA    A        H1HR  oǅ`	  AH$T$M1H=AAzHHW  H1   aAOHW  1H1A8 AWAVAUATUSH8LD$DN  LL$Ld$xE  HH  ?  H|$ j  H|$p IItHD$p     MtA$    L  MH8  LDM    D$  HD$     Mt
LHD$ L1HƋD$HHcHHHD$(fD  IFH8Mv MuHcD$Lt$(HTHD$ H1IHT$HtHJT5 H	  HH	  贌D$1  H	  M  L  L  E11   fD  LH   IFH  HH   @  H	  MtA$E  H0H	  L	  LS   IA-PLUfAOH  H   HtPu,MtA$H	  LMIvH6H	  :A   Mv 9  !H|$ tH	  Ht$H|$p H	  tH1HT$pHD$HD$H8[]A\A]A^A_    HtAuMtA$E`H@ H	  LIF      XD$댹  HBO     H1ǃ`	  D$ZA  1HHeP  1vD$ǃ`	  %  HO  11HGD$ǃ`	    eff.           H{  ATUSHXHtDL%ץ  1% Ht;HSfHn~fl H[ HtHſ   A$HH	u1[]A\ H]@ HHAT$H[Huf1ff.     f     H   AUATUSHHH   HHtyEĹ   Lp  A6ty`	  H[]A\A]D  Hx  EHDH0tyfD  H@ 1D  ù  HFM     1ǃ`	  ~fD  AWAVAUATUSH8H$HL$dH%(   HD$(1  HD$       IH  H  ?  IHk  HL$HT$    Ln  H\$H-  ; >  L%  I4$MHuh     IwIHt#HtL$Ht$L1LAWŅu,1HD$(dH+%(   >  H8[]A\A]A^A_D  D;EtOHD  D{HEt2IDQ t	D  HHtDA u; 6@ stVhA`	  \H|$HL$E11H+Q  T$ H\$HH.7  H\$Lw   L1HP  HHھ   L1뀹     L1HJ  oAǅ`	  S AWAVAUATUSH(dH%(   HD$H?5  HD$    H$    IH  HH  IH      H!HHe  LxH5mQ  LH H  H  L)H{LHIHAD  HH  H   +Aą   H  H4$H   H@Ph  H   Lp  L[6LAH  PEtVxF@ HD$dH+%(     H(D[]A\A]A^A_f.     Hɠ  LPEyD`	  D  H  LLHL  4JAątfx  Ey    HXA E1X     HP  1H1UAǅ`	  (     AO  HH     1ǅ`	  A AWAVAUIATUSHHdH%(   HD$81HHLDH=9   U  H11IAH   HHl$H
	  HD$HH$H   @     HIH$LxMtsA$ IMuY M Mt=IGHH0huAoL   H)E AoO)MAM MuMtHn  H$LrfMuH|$
L   1A1HT$8dH+%(   u[HH[]A\A]A^A_ H  Hl$HXHt oL   H)U o[)]AH[ Hu델bfAWAAVAUATUSH   H|$H$   L$   L$   dH%(   HD$x1HD$    HD$    H  HH  H|$HT$0Ht$(褈H
D$8   IH$   HD$@H$   HD$HM  E1L5M  Hl$VLL$A<$%t]HD$Ht$0H$H|$(HP脁   HD$(A4$H$HHD$H@4HD$L9'  L$A<$%uLaID$V%Hq
B#DI))π%J  B<wGIcL A  fD  HD$xdH+%(     Hĸ   []A\A]A^A_fC CD  IM9  LHVfD  HcǃTVD$8HcD<V /  HT$HD$8D
H|$`   I      1H<$&H$HT$Ht$0H|$(΀>It$I9rHD$(AHHD$ H\$HL$ HT$   HfHD$HHh	  H|$     D$8/;  HT$HD$8:  11
HHT$7@ D$8/+  HT$HD$8H
_A  HcfD= D$8/   HT$HD$8D$a HL$`D$`@ D$8/   HT$HD$8:HhfD  I91B#D)π%HD$Ht$0H|$(HP~HD$(It$HHD$%HD$ HT$@HBHD$@D  HT$@HBHD$@D  HT$@HBHD$@D  HT$@HBHD$@D  HT$@HBHD$@HL$ HT$   d	HD$HH|$ HI     7	f.     fSHtUHt;HHtH    HH[HJ     11[H;J     1HI     11ff.      AVHAUI1ATUHSH~HPÅuJL5     AIHt>   H
Ht3~\  fHnL%P  flA$IE []A\A]A^ûH   1IHAJ  1~LAV AWAVAUATUSHP  H|$8dH%(   H$xP  1HD$H    H  H  H>  HFHH@@  H:  Hz HT$  HL$HH~HAŅ  H\$HH  HH=    LL$Hl$`H$p@  1HL$LL$(Hl$Ht$D`E1McH)@ IBD#IcA<=BD&A<:tEtIT$uE1Hl$H\$  D` HHHٺ   H5H  H)HH  XHHD$H  Ld$ D  H|$H  HXHHHvIcHH=  wH|+H5yH  uL$`   HHLH$`0  Ht$Hߺ   Ƅ,`    L  Hߺ   P	H$`     H$c   HHI-.   HPHt  Ht$(HT$PHH\$8H+HHD$XDt$3MDl$4IH ImIHtSH|$PHHMeuHt$XLAԅtHMHF  1   1I{Im Hu@ H|$Dt$3Dl$4+H}fH|$Ld$ !EtH\$HIcAf     H$xP  dH+%(   uHĈP  D[]A\A]A^A_A68HL$HKF  1I   1{|ff.     fATUSH5  Ht1L%  f     HHH}HtHAT$HuH      [1]A\f.      AWAVAUATUSH  L$dH%(   H$  1HD$    H   IIH  HH  ;     H$   u#  f     ;tHH=  i  AuLc;BƄ<    HLDK,>Le E}    HKD>fD  L HEt[BDbuI}   11HE  A  AH$  dH+%(     H  D[]A\A]A^A_fD  fHT$ HL$HH$   D$$D$4D$(   D$    D$@Aą   L|$LD$P   LLD$AWIwIL!f|$P
LD$uD$XD$\u
|$`  tED9t$   DLHI}   11HD  A  1|D$dA   HD$X    D$T   fD$PHI}   11HC  A  I}   11HC  A  I}   11HC  AA  _@ H   AVIAUATIUSHtYIHtVH>Ht29r1[]A\A]A^Ð9rAV8I$HtGA] D  AV(I$HtXAm HtI~   11HB  A  AE     I~   1HB  A  oAE     I~   1HB  A  ӸHq  AVAUIATUSHH  IH  L!M   AD$    IT$   HH1H@ HHH9uAL$LL   AT$I<$1 I$     H3HSHHmHKHH9u1[]A\A]A^fD     AU(IHt~f M&J1LLuAT$I<$1 I}   11HA  A  HtI}   11H*A  A  bI}   HIA  1A  봸H   AVAUATUHSHHtDIHtAHIHxIU(IHHtBHDMtE,$1[]A\A]A^HtH}  11H@    1H}  1H@    밸 HtCATUSHHt+L&Mt#HL<L   H;U@H    []A\        Ht;USHHHt$HHtH0Hx   H;U@H    H[]fff.     @ Ht3HHt%HHt#    HP0H0HtH9uD  1D  AUILATAUSHH(dH%(   HD$1H    Ht7H@ Et	H   H1HT$dH+%(      H([]A\A]ÐI}HL$HT$A   uEtuHD$Ht1H|$HډЅuEtH; uI}l  H>  1A  qI}H>  1A  D  AUIHATIUHSH(dH%(   HD$1H    @      HtnHx  H   x(HAU(HE H   S(Hs HxHHE HD A$   1HT$dH+%(      H([]A\A]I}HL$HT$@  A   uHD$HtI}Ht$H@  ЅuH}  uI}  Hb=  1A  x    I}  Hx=  1A  NI}H=  11A  @AVIAUIATILUSLH dH%(   HD$1I     'Ht:H@ H   H1HT$dH+%(      H []A\A]A^    I|$HL$HT$A$   uHD$HtHLLIj E1H|$ ZYuH; uI|$  H1<  1A$  eD  I|$H=  1A$  3 ATI@  UHHSHH dH%(   HD$1H    Ht6H@ H   H1HT$dH+%(      H []A\    H}HL$HT$@     uHD$HtH|$HL@  ЅuH; uH}  H5;  1  w H}HU<  1  >ff.      AW   IAVAUIATIULSHHHM~  H|$P tH|$h tH$      L@ALD$LAW(LD$HH  HxH     JD0    HH)A1HHMtH<  H@  H0HBLjLbMtH;  H@  H0HBLBHjH|$P t(HG  H@  H0HBHD$PHBHD$XHBH|$h t&HD$`H@  H0HBHD$hHBHD$pHBH$    t,HD$xH@  H0HBH$   HBH$   HBH    f1HB    BH[]A\A]A^A_fH|$P H|$h H$    A`   ~1HH}:  1A  D  @AN1I*  1H9  A  dD  fH7GG   GW$fD  AWAVAUATUSHXH$   LD$(HD$H$   HD$ dH%(   HD$H1A      GIHIM̅   DwE>  EG$E9  IGHT  Aw D)H<09  t$HHT$DD$HT$HL$@IwH|$ AHHD$AWDLD$<D)Ѕ   T$<A$LI?LHT$(&   T$<Ht$@A<$I} IU D$<A$A$    AG      9ALDFH)H~HDD)HT$AGHT$D)HAG   AOAG     AAOE HT$HdH+%(   uHX[]A\A]A^A_f     IDP(IGHtKEwD  M1DH18     1A   @ HA_ 1{q@ HGHtHHHR@     AWAVAUATUHSHH  MM   ILϾ@   HT$IM?HT$HHtzIHp1HM) IALU(IE Ht%LLH'@HD[]A\A]A^A_fH}  11H5  A  fD  1MtA? u;LHPAEuHLLH[1]A\A]A^A_*f.     LHAH}  11H4  A  Gff.     HAVHAUIATIUSujHHtbHLHII|AU(HHHtZLL#L@   HfAH;81[]A\A]A^D  1I}  1H<4  A  1I}  1HZ4  A  @ SHHdH%(   HD$1AH1HHH$t1HT$dH+%(   uH[f.     ATUHSH  dH%(   H$  1ILHHcMH$   LV5     HPH1bLH$  dH+%(   uHĐ  []A\[   HH                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               yes no Plugin "%s"  , 	API version: %d
 	supports store: %s
 failed to allocate memory
 auxpropfunc error %s
 [all] auxprop_plugin  List of auxprop plugins follows Parameter error in ../../lib/auxprop.c near line %d     could not find auxprop plugin, was searching for '%s'   could not find auxprop plugin, was searching for %s            All-whitespace username. INTERNAL canon_user_plugin     desired canon_user plugin %s not found  bad plugname passed to sasl_canonuser_add_plugin
       %s_canonuser_plug_init() failed in sasl_canonuser_add_plugin(): %z
     canonuser plugin '%s' without either client or server side      AlwaysTrue Password Verifier Verified: %s       cannot create socket for saslauthd: %m  cannot connect to saslauthd server: %m  cannot create socket for connection to Courier authdaemond: %m  cannot set nonblocking bit: %m  cannot connect to Courier authdaemond: %m       cannot clear nonblocking bit: %m        Parameter error in ../../lib/checkpw.c near line %d     could not perform password lookup *userPassword *cmusaslsecretPLAIN sasldb saslauthd_path saslauthd request too large write failed size read failed bad response from saslauthd OK authentication failed FAIL could not verify password /dev/null authdaemond_path unix socket path too large AUTH %s
%s
%s
%s
%s

 login login incorrect could not find password %02x auxprop authdaemond alwaystrue           /var/run/saslautsasl_client_add_plugin(): entry_point(): failed for plugname %s: %z     version conflict in sasl_client_add_plugin for %s       List of client plugins follows  	SASL mechanism: %s, best SSF: %d
      Out of memory allocating connection context     Out of Memory in ../../lib/client.c near line %d        Out of memory in sasl_client_new        Parameter error in ../../lib/client.c near line %d      attempting client step after doneflag   mech did not call canon_user for both authzid and authid        Internal Error %d in ../../lib/client.c near line %d [loaded] 	security flags: %cNO_ANONYMOUS %cNO_PLAINTEXT %cNO_ACTIVE %cNO_DICTIONARY %cFORWARD_SECRECY %cPASS_CREDENTIALS %cMUTUAL_AUTH 
	features: %cWANT_CLIENT_FIRST %cSERVER_FIRST %cPROXY_AUTHENTICATION %cNEED_SERVER_FQDN %cGSS_FRAMING %cCHANNEL_BINDING %cSUPPORTS_HTTP sasl_client_plug_init sasl_canonuser_init EXTERNAL log_level client_mech_list No worthy mechs found -PLUS          @      @              USER USERNAME Unable to find a callback: %d ../../lib/common.c conn->oparams.encode != NULL SASL_CONF_PATH SASL_PATH Cyrus SASL 2.1.28 successful result generic failure no memory available overflowed buffer no mechanism available bad protocol / cancel invalid parameter supplied integrity check failed needs user interaction authentication failure authorization failure account disabled user not found version mismatch with plug-in passphrase locked channel binding failure undefined error! en-us (null) SASL(%d): %s:  %s%s Bad IPREMOTEPORT value Bad IPLOCALPORT value Unknown parameter type no olist        Parameter error in ../../lib/common.c near line %d      Internal Error %d in ../../lib/common.c near line %d    Information that was requested is not yet available.    Out of Memory in ../../lib/common.c near line %d        Requested identity not authenticated identity   /etc/sasl2:/etc/sasl:/usr/lib/x86_64-linux-gnu/sasl2:/usr/lib/sasl2     /usr/lib/x86_64-linux-gnu/sasl2 called sasl_decode with application that does not support security layers       input too large for default sasl_decode another step is needed in authentication        can't request information until later in exchange       transient failure (e.g., weak key)      SASL library is not initialized server failed mutual authentication step        mechanism doesn't support requested feature     mechanism too weak for this user        encryption needed to use mechanism      One time use of a plaintext password will enable requested mechanism for user   passphrase expired, has to be reset     remote authentication server unavailable        user exists, but no verifier for user   requested change was not needed passphrase is too weak for security policy      user supplied passwords are not permitted       sasl_setpass needs old password in order to perform password change     sasl_setpass can't store a property because of a constraint violation   error when parsing configuration file   called sasl_encode[v] with application that does not support security layers    Tried to set realm on non-server connection     Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0    Tried to set application name on non-server connection  ?./..
.d.,,T..-N//A/-..,/--x-6-,-,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
-,,`22d22d2:9999999999999999999999999999999999999999999999999999999999999999999:9:::::9::::x:p:h:`:X:P:H:@:8:0:(: :::: :9999::9<E|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|DC|D|D|D|D|D|D|D|D|D|D|EC|D|D|D|DC|D|D|DD|DC|D|D|DD|DC|D|DC|DEN$N$N$N$NO|O$N$N$N$N$N$N$NOLP$N$NdNN    _sasl_encodev c                       anonymous login not allowed EXTERNAL version mismatch   Please enter your authorization name                            #EgܺvT26666666666666666\\\\\\\\\\\\\\\\/dev/urandom <%lu.%lu@%s> <%lu.%lu>                             >?456789:;<= 	

 !"#$%&'()*+,-./0123ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????                   Parameter error in ../../lib/server.c near line %d      Out of Memory in ../../lib/server.c near line %d        security flags do not match required    mech %s requires unprovided secret facility     %s_client_plug_init() failed in sasl_server_add_plugin(): %z
   version mismatch on  sasl_server_add_plugin for '%s': %d expected, but %d reported      Internal Error %d in ../../lib/server.c near line %d    unknown password verifier(s) %s %s: couldn't identify flag '%s' List of server plugins follows  	SASL mechanism: %s, best SSF: %d, supports setpass: %s
        No current SASL mechanism available     setpass callback failed for %s: %z      setpass callback succeeded for %s       %s: failed to set secret for %s: constrain violation    %s: failed to set secret for %s: %z (%m)        secret not changed for %s: no writable auxprop plugin or setpass callback found transitioning user %s to auxprop database       unable to load plugin list %s: %z       attempting server step after doneflag   server requires channel binding but client provided none        client incorrectly assumed server had no channel binding        client provided channel binding but server had none     client channel binding %s does not match server %s      %s: security parameters don't match mechlist file       Got past mech_permitted with a disallowed mech! Remote sent first but mech does not allow it.   no plaintext password verifier? mech %s is too weak no users in secrets db pwcheck_method checkpass failed [delayed] [no users] [unknown] %cDONTUSE_USERPASSWD %cSERVICE %cNEED_GETSECRET 
	will be loaded from "%s" * setpass failed for %s: %z setpass succeeded for %s %s: set secret for %s %s: secret not changed for %s auto_transition noplain sasl_server_plug_init sasl_auxprop_plug_init %.*s%c%s.conf plugin_list Couldn't find mech %s 0123456789abcdef Bad Digest noplaintext noactive nodictionary forward_secrecy noanonymous pass_credentials mutual_auth             No sasl_conn_t passed to sasl_seterror  `@ no entryname in _sasl_locate_entry      no library in _sasl_locate_entry        no entrypoint output pointer in _sasl_locate_entry      _sasl_plugin_load failed on %s for plugin: %s
  looking for plugins in '%s', failed to open directory, error: %s unable to dlopen %s: %s / .so  Parameter Error in ../../common/plugin_common.c near line %d    Out of Memory in ../../common/plugin_common.c near line %d      Unexpectedly missing a prompt result in _plug_get_simple        Unexpectedly missing a prompt result in _plug_get_password      Unexpectedly missing a prompt result in _plug_challenge_prompt  Unexpectedly missing a prompt result in _plug_get_realm make_prompts() called with no actual prompts    encoded packet size too big (%d > %d) Authorization Name Authentication Name %s %s  ;       4  LL  `  <|        D    <    <|    \	  P	  x	  L	  ,	  	  \,
  ,|
  
    ,  @  \    ,<  p      L  |4
  
  ,
     <p  |    d  x    \  (  L  l        h  <	    T  ,          ,$  \8  lL  x      @  \   !  !  "4  ,"H  l"\  "  \#  #  $  $   ,%4  &  '  '  (   )4  ,t  \-  -  L.  .,  \/L  /`  /t  L0  0  \1  |2T  6  7  \8  =L  =p  L?  E  H4  lJ  |J  L@  L|  O  |O  P<  \PP  |Pd  P  R  LUh  U  ,V  V  V  `,  `@  a  b  d   Le4   eH   ep   <h   li   k$!  \l8!  lmt!  m!  m!  m!  ln!  oT"  ,p"  <p"  |p"  q"  s#  sH#  v#  y#  z$$  lzP$  }$  }$  ,%  \h%  %  %  %  p&  &  &  H'  '  l(  LX(  (  (  $)  p)  <)  ܭ*  \*  *  *  |+  ܷ<+  +  +  ,  d,  ,  \,  ,  -  L-  -  -  L.  l0.  .  .  ,.  8/  \\/         zR x  $         FJw ?;*3$"       D                 \   W          p   D    Jb (      a    FAG IAAG 8          BBA C(DP
(D ABBE              H     ̼    BBB B(D0A8D@
8D0A(B BBBG H   T  `O   BEB B(A0A8G`
8A0A(B BBBD T     d5   KBB B(D0A8DP
8A0A(B BBBA,  ,     L    KAD ABF  `   (  J   BBB B(A0A8DP
8A0A(B BBBDg
8D0A(E BBBA d        BBB B(A0A8D
8A0A(B BBBFD
8F0A(B BBBE   4         FAG R
AAFLCAA 0   ,  8;   BAA D@
 AABA$   `  Du    Fk
GM
AhA      !                 AJ0
CH (     t`    BAA XAB  L        BBB E(A0D8D
8C0A(B BBBG   L   <  (   BBB B(A0A8G
8D0A(B BBBD   L        BBB E(A0A8D:
8A0A(B BBBK   H     (   BBB B(A0A8Dp+
8A0A(B BBBE   (  l          <  x          P     BBB B(A0A8DMEGTESBM
8A0A(B BBBDcESA H     T   BBB E(D0D8DP_
8C0A(B BBBF  (      c    BAA [AB  0   L  e   BAA D@
 DABF      $6            P!    D\ H     h2   BEB B(D0F8P
8A0A(B BBBDH     \'   BEB B(D0F8P
8A0A(B BBBAL   D  @    BEE D(D0o
(D BBBCW
(A BBBB  H     
   BIG B(A0A8G
8A0A(B BBBEL     T    BED C(G0N
(D ABBDG
(G DBBJ   L   0  ,   BBE J(D0A8JK
8A0A(B BBBG   8     1   BED G(G@
(A ABBA`     7   BBE J(D0A8GHTDS
8D0A(B BBBI   P    	  <   BBB B(A0A8G
8C0A(B BBBD          t	  	      4   	  s    MDD C
CADDFAE H   	     BBB B(A0A8Dpg
8A0A(B BBBA(   
  X    BAD DB      8
  a   Rc   L   \
  8    BBA A(D0
(D ABBFD
(G DBBA   0   
  |    AAD0H
AAHaAA0   
     BAA D`
 CABI`     =   BBB B(A0A8G.BDBR}
8D0A(B BBBE   H   x  l[   RAA k(L0E(A X
ABDHF   L     m   BBB B(A0A8G
8D0A(B BBBH   L        BBB B(A0A8DI
8D0A(B BBBD   0   d  0    WAA P
ABD` H        BBB E(A0A8Dp1
8A0A(B BBBD                           
             
  #          4
   #          H
         (   \
      AAG F
AAG ,   
  |   A
K^
JS
Em 0   
     BAA D@
 DABA `   
  	   BBB B(A0A8D@_
8A0A(B BBBI
8A0A(B BBBEH   P  d    BBE D(D0R
(C BBBDi(F BBBd         KEE E(D0D8D@H
8A0A(B BBBHT8D0A(B BBB           I\$     r    U\GPcA      D            X  4       (   l  
I    BDD t
ABA,     ,
    JAG U
AAG^,     
    JAG U
AAG^          JX
FH                 0  P       `   D     KBE D(D0G@`
0A(A BBBGA
0A(A BBBG       <,       <     X    GAA L
JBGQABD   0         AAG 
AAHDAA   0  tH      <   D     BEA I(D
(D ABBK   4     @    AAD t
AADA
AAE (     B    FAG iCAA           H  4     P    AAD Q
AAGZ
AAD    <  o    d}
GF      \  K          p  DK            K       8         BED D(D0V
(A ABBA  <     x    BHE D(H0C
(D BBBH   L     P   BAA GFKJHX]Z
 AABG   L   d   w   BBB B(A0A8Gy
8A0A(B BBBD        P       @     \<   KEA A(D0
(A ABBEn L     X   BBB B(A0A8G
8C0A(B BBBI       \  "    AD0[
AG H     D#   BBB B(A0A8G	
8D0A(B BBBJ(     $:   AAD0
AAH H     *   BHF B(D0D8K
8C0A(B BBBHH   D  `-   BBB B(A0A8DPl
8A0A(B BBBD     .            .   BBB B(A0A8DPzXK`QXAPQ
8S0A(B BBBNDXK`ZXAPHXG`LXBPd
8G0A(B BBBEf
8F0A(B BBBKBXK`WXBP  8   P  /t    BDE D(D0Y(A BBB  L     0q   BIB B(A0A8G  
8C0A(B BBBD   8     H2]    BBE A(H0@(D BBB  0     l2    OAA _
AWH          L  2<          `  3       (   t  31    FAG ZDA   d     $3   BBB B(A0A8DP
8A0A(B BBBA
8F0A(B BBBE   l     4   BBB B(A0A8D`
8C0A(B BBBDvhHpSxBBBBBI`   ,   x  6f    O{AFF
AF
AF      7n    D_     t7g    Db         7J    AH  @     7	   JEB N(A0A8.	0A(E BDp    <  xA       H   P  A   BGE J(G0D8DP^
8A0A(B BBBA 0     XB    BFD K0
 AABG D     C   BEB A(D0J5
0A(A BBBA   (     Dt    ADG`
AAA   D  E\       $   X  \E6    ADK YGA P     tEG   BBE E(D0D8G{
8A0A(B BBBA            pG0      H     HY   BBB B(A0A8D`
8A0A(B BBBI   4  J       8   H  K
   BIA A(DP
(A ABBE      K,    H\
AF       L
            KH       8     8Lp    GAA G0x AABDH0X     lL3   BBE D(C0FPS
0A(A BBBGHXS`VP[XN`YXAP   0   d  PM~    FDD0JAAFH0       M	            M3       H     M~   BBB E(A0D8RR
8D0A(B BBBG     N	      4      Os    KDD C
CAFDFAE @   X  <PG   BBB A(A0D@@
0A(A BBBDH     HS'   BBB B(A0A8Dp
8A0A(B BBBBH     ,U	   BGA A(GPTXR`AhHpSP]
(A ABBI  (   4  UF    BGA xAB   L   `  V   BBB E(A0D8DS
8C0A(B BBBE   8     tX    BBD A(G0
(D ABBC L     X   BIB B(A0A8G	
8C0A(B BBBA   8   <  Zk   BBA D(D0P(D ABB       x  [   R]   L     `    BBA A(D0
(D ABBAD
(G DBBA        (a       |       $a   BBB I(F0A8GJ`RBXMAYESA
8D0A(B BBBDD      f   BBA A(DPXN`OXAPb
(A ABBJ (      gi    AD H
ABQD   `      0h   BBB B(D0A8J
8D0A(B BBBEFHRY  `   X!  llW   BBB B(A0A8D BDDP{
8D0A(B BBBH   X   !  hrK   BBA A(D0n8V@Q8A0S
(C ABBE
(C CBBJ L   "  \u   BBB B(A0A8D
8D0A(B BBBK   H   h"  y   BBB B(A0A8Dp
8A0A(B BBBH0   "  p}    WAA P
ABD` H   "  }    YBA A(G0x
(A ABBFxN0H   4#  p~M   BBB B(A0A8Dp 
8C0A(B BBBFH   #  tM   BBB B(A0A8D`:
8D0A(B BBBKL   #  x   BBB E(A0A8D1
8A0A(B BBBD   L   $  ȃ   BEB B(A0A8G
8A0A(B BBBC       l$  (r    Af
C[
A  <   $      BEG A(D0]
(A BBBA   L   $     BBB B(A0A8GY
8D0A(B BBBA  (    %  dS    BAA ICB  L   L%     BBB B(A0A8G
#
8D0A(B BBBG   D   %      KEB D(A0`
(A BBBB   D   %     KBE A(A0
(A BBBG  D   ,&      KBB A(D0D
(A BBBAG  ,   t&  PI    GAA tABH   (   &  pA    FAG mAAC     &  ;       8   &      BHD C(GPP
(A ABBB 8    '  `   BHD D(DP
(A ABBA L   \'  
   BEE G(C0GPK
0A(A BBBHkXK`MXAP 0   '  h    BIG G@K
 AABH H   '  4;   BJB E(D0D8GP
8A0A(B BBBC   ,(  (       L   @(  4L   BBB B(A0A8D
8A0A(B BBBJ      (  4       `   (  @E   BBB B(A0D8DP
8D0A(B BBBCL
8J0C(B BBBO<   )  ,    EHE I(A0_
(A BBBF       H)  V    AI E
AA <   l)      BAD Ib^QZ
 AABA                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 `6       6                           %p                                       0      
       @                                                          o    `                                
       m                           @            P                           #             8                   	              o    `      o                         o           o          o           o    6      o    +                                                                                       0                     60      F0      V0      f0      v0      0      0      0      0      0      0      0      0      1      1      &1      61      F1      V1      f1      v1      1      1      1      1      1      1      1      1      2      2      &2      62      F2      V2      f2      v2      2      2      2      2      2      2      2      2      3      3      &3      63      F3      V3      f3      v3      3      3      3      3      3      3      3      3      4      4      &4      64      F4      V4      f4      v4      4      4      4      4      4      4      4      4      5                                                                                                                            p                                                                                                                                                                                                                                      Q             R      R                                                     U     @]      T     0a      U     g      U      Z                                                   @                                                                                                      WY            "       g             p                                                  WY            "               @                                                                                                                                                         q            +q            4q            Aq            Qq            ]q             nq     @                       e1d60c82212988ff0187e8f9340d5b8d9dc817.debug     .shstrtab .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_d .gnu.version_r .rela.dyn .rela.plt .init .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .data.rel.ro .dynamic .data .bss .gnu_debuglink                                                                                8      8      $                                 o       `      `                                  (                         
                          0                         m                             8   o       6      6      (                           E   o       `      `      T                            T   o                                               c             8      8                                 m      B       #      #      P                          w              0       0                                    r              0       0                                  }             5      5                                                5      5      U
                                         @     @     	                                            P      P     #%                                           $u     $u                                               {     {     )                                                                                                                                                                                                          0     0                                             @     @                                                                                                                                                                            4                                                    4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   ELF          >            @                @ 8 	 @                                                                                                                                d     d                                 H      P                   
                                        8      8      8      $       $              Ptd                     T       T              Qtd                                                  Rtd                  0      0                      GNU X5<,	V 
                !           E}L%B~3`4F'(                                                                                                                      ,                       F   "                   U             h            @                  0                  P                        t                        n                                       __gmon_start__ _ITM_deregisterTMCloneTable _ITM_registerTMCloneTable __cxa_finalize _kBrotliPrefixCodeRanges _kBrotliContextLookupTable BrotliGetDictionary BrotliSetDictionaryData BrotliDefaultAllocFunc malloc BrotliDefaultFreeFunc free BrotliGetTransforms BrotliTransformDictionaryWord libc.so.6 libbrotlicommon.so.1 GLIBC_2.2.5                                    ui	   ?                                                      (                   
                 	                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       HH HtH         5 % @ % h    % h   %z f        H= H H9tH> Ht	        H= H5z H)HH?HHHtH
 HtfD      ==  u+UH=  HtH= Yd ]     w    H      f.     D  H     H     Ё   %     )yKvMwQ~Cw  ?	
?	Ƹ   @wfD      w       wډ~DGwG   fn EAAAA  A  E	AA?D	E	D		A҉AA?AA?A?	D	fnȸ   fD	fofnff~    DGw   D%  	Љ?	D?	Ƹ   ?@w	ʈWfD  H
      AUC@AIATHG USHQ HHiHyDDDOGHD!HEtL1THH9uA	   A)E~KIc1HfHA91ACENEd
   ty    E Hƍxt'Ic1Hf     THH9uFd'[D]A\A]ÍGwxGHcA)HEYu@ DD)HH% v{p      A)HEgw֍Jw       D  E
ufDD)HHv{   p p            IQ(McDD)BDBHcHEDDD5HcA)HEJ @ IA(McDDD)BTBHcHVp MHH                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       	  
      !  )  1  A  Q  a  q          1 q  	 
    
 @                          	

 !"#$%&'()*+,-./0123456789:;<=>? 	

 !"#$%&'()*+,-./0123456789:;<=>? 	

 !"#$%&'()*+,-./0123456789:;<=>? 	

 !"#$%&'()*+,-./0123456789:;<=>?                                                                                                                                                                                                                                                                    				







    !!!!""""####$$$$%%%%&&&&''''(((())))****++++,,,,----....////0000111122223333444455556666777788889999::::;;;;<<<<====>>>>????                                                                                                                                                                                                                                                                                              $,,,,,,,,,,  (044404440444440444440444448<<<8<<<8<<<<<8<<<<<8<<<<<                                                                                                                                                                                                                                    ((((((((((((((((((((((((((((((((((((((((((((((((0000000000000008 timedownlifeleftbackcodedatashowonlysitecityopenjustlikefreeworktextyearoverbodyloveformbookplaylivelinehelphomesidemorewordlongthemviewfindpagedaysfullheadtermeachareafromtruemarkableuponhighdatelandnewsevennextcasebothpostusedmadehandherewhatnameLinkblogsizebaseheldmakemainuser') +holdendswithNewsreadweresigntakehavegameseencallpathwellplusmenufilmpartjointhislistgoodneedwayswestjobsmindalsologorichuseslastteamarmyfoodkingwilleastwardbestfirePageknowaway.pngmovethanloadgiveselfnotemuchfeedmanyrockicononcelookhidediedHomerulehostajaxinfoclublawslesshalfsomesuchzone100%onescareTimeracebluefourweekfacehopegavehardlostwhenparkkeptpassshiproomHTMLplanTypedonesavekeepflaglinksoldfivetookratetownjumpthusdarkcardfilefearstaykillthatfallautoever.comtalkshopvotedeepmoderestturnbornbandfellroseurl(skinrolecomeactsagesmeetgold.jpgitemvaryfeltthensenddropViewcopy1.0"</a>stopelseliestourpack.gifpastcss?graymean&gt;rideshotlatesaidroadvar feeljohnrickportfast'UA-dead</b>poorbilltypeU.S.woodmust2px;Inforankwidewantwalllead[0];paulwavesure$('#waitmassarmsgoesgainlangpaid!-- lockunitrootwalkfirmwifexml"songtest20pxkindrowstoolfontmailsafestarmapscorerainflowbabyspansays4px;6px;artsfootrealwikiheatsteptriporg/lakeweaktoldFormcastfansbankveryrunsjulytask1px;goalgrewslowedgeid="sets5px;.js?40pxif (soonseatnonetubezerosentreedfactintogiftharm18pxcamehillboldzoomvoideasyringfillpeakinitcost3px;jacktagsbitsrolleditknewnear<!--growJSONdutyNamesaleyou lotspainjazzcoldeyesfishwww.risktabsprev10pxrise25pxBlueding300,ballfordearnwildbox.fairlackverspairjunetechif(!pickevil$("#warmlorddoespull,000ideadrawhugespotfundburnhrefcellkeystickhourlossfuel12pxsuitdealRSS"agedgreyGET"easeaimsgirlaids8px;navygridtips#999warsladycars); }php?helltallwhomzh:*/
 100hall.

A7px;pushchat0px;crew*/</hash75pxflatrare && tellcampontolaidmissskiptentfinemalegetsplot400,

coolfeet.php<br>ericmostguidbelldeschairmathatom/img&#82luckcent000;tinygonehtmlselldrugFREEnodenick?id=losenullvastwindRSS wearrelybeensamedukenasacapewishgulfT23:hitsslotgatekickblurthey15px''););">msiewinsbirdsortbetaseekT18:ordstreemall60pxfarm’sboys[0].');"POSTbearkids);}}marytend(UK)quadzh:-siz----prop');
liftT19:viceandydebt>RSSpoolneckblowT16:doorevalT17:letsfailoralpollnovacolsgene —softrometillross<h3>pourfadepink<tr>mini)|!(minezh:barshear00);milk -->ironfreddiskwentsoilputs/js/holyT22:ISBNT20:adamsees<h2>json', 'contT21: RSSloopasiamoon</p>soulLINEfortcartT14:<h1>80px!--<9px;T04:mike:46ZniceinchYorkricezh:'));puremageparatonebond:37Z_of_']);000,zh:tankyardbowlbush:56ZJava30px
|}
%C3%:34ZjeffEXPIcashvisagolfsnowzh:quer.csssickmeatmin.binddellhirepicsrent:36ZHTTP-201fotowolfEND xbox:54ZBODYdick;
}
exit:35Zvarsbeat'});diet999;anne}}</[i].Langkm²wiretoysaddssealalex;
	}echonine.org005)tonyjewssandlegsroof000) 200winegeardogsbootgarycutstyletemption.xmlcockgang$('.50pxPh.Dmiscalanloandeskmileryanunixdisc);}
dustclip).

70px-200DVDs7]><tapedemoi++)wageeurophiloptsholeFAQsasin-26TlabspetsURL bulkcook;}
HEAD[0])abbrjuan(198leshtwin</i>sonyguysfuckpipe|-
!002)ndow[1];[];
Log salt
		bangtrimbath){
00px
});ko:feesad>
s:// [];tollplug(){
{
 .js'200pdualboat.JPG);
}quot);

');

}
201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037201320122011201020092008200720062005200420032002200120001999199819971996199519941993199219911990198919881987198619851984198319821981198019791978197719761975197419731972197119701969196819671966196519641963196219611960195919581957195619551954195319521951195010001024139400009999comomásesteestaperotodohacecadaañobiendíaasívidacasootroforosolootracualdijosidograntipotemadebealgoquéestonadatrespococasabajotodasinoaguapuesunosantediceluisellamayozonaamorpisoobraclicellodioshoracasiзанаомрарутанепоотизнодотожеонихНаеебымыВысовывоНообПолиниРФНеМытыОнимдаЗаДаНуОбтеИзейнуммТыужفيأنمامعكلأورديافىهولملكاولهبسالإنهيأيقدهلثمبهلوليبلايبكشيامأمنتبيلنحبهممشوشfirstvideolightworldmediawhitecloseblackrightsmallbooksplacemusicfieldorderpointvalueleveltableboardhousegroupworksyearsstatetodaywaterstartstyledeathpowerphonenighterrorinputabouttermstitletoolseventlocaltimeslargewordsgamesshortspacefocusclearmodelblockguideradiosharewomenagainmoneyimagenamesyounglineslatercolorgreenfront&amp;watchforcepricerulesbeginaftervisitissueareasbelowindextotalhourslabelprintpressbuiltlinksspeedstudytradefoundsenseundershownformsrangeaddedstillmovedtakenaboveflashfixedoftenotherviewschecklegalriveritemsquickshapehumanexistgoingmoviethirdbasicpeacestagewidthloginideaswrotepagesusersdrivestorebreaksouthvoicesitesmonthwherebuildwhichearthforumthreesportpartyClicklowerlivesclasslayerentrystoryusagesoundcourtyour birthpopuptypesapplyImagebeinguppernoteseveryshowsmeansextramatchtrackknownearlybegansuperpapernorthlearngivennamedendedTermspartsGroupbrandusingwomanfalsereadyaudiotakeswhile.com/livedcasesdailychildgreatjudgethoseunitsneverbroadcoastcoverapplefilescyclesceneplansclickwritequeenpieceemailframeolderphotolimitcachecivilscaleenterthemetheretouchboundroyalaskedwholesincestock namefaithheartemptyofferscopeownedmightalbumthinkbloodarraymajortrustcanonunioncountvalidstoneStyleLoginhappyoccurleft:freshquitefilmsgradeneedsurbanfightbasishoverauto;route.htmlmixedfinalYour slidetopicbrownalonedrawnsplitreachRightdatesmarchquotegoodsLinksdoubtasyncthumballowchiefyouthnovel10px;serveuntilhandsCheckSpacequeryjamesequaltwice0,000Startpanelsongsroundeightshiftworthpostsleadsweeksavoidthesemilesplanesmartalphaplantmarksratesplaysclaimsalestextsstarswrong</h3>thing.org/multiheardPowerstandtokensolid(thisbringshipsstafftriedcallsfullyfactsagentThis //-->adminegyptEvent15px;Emailtrue"crossspentblogsbox">notedleavechinasizesguest</h4>robotheavytrue,sevengrandcrimesignsawaredancephase><!--en_US&#39;200px_namelatinenjoyajax.ationsmithU.S. holdspeterindianav">chainscorecomesdoingpriorShare1990sromanlistsjapanfallstrialowneragree</h2>abusealertopera"-//WcardshillsteamsPhototruthclean.php?saintmetallouismeantproofbriefrow">genretrucklooksValueFrame.net/-->
<try {
var makescostsplainadultquesttrainlaborhelpscausemagicmotortheir250pxleaststepsCountcouldglasssidesfundshotelawardmouthmovesparisgivesdutchtexasfruitnull,||[];top">
<!--POST"ocean<br/>floorspeakdepth sizebankscatchchart20px;aligndealswould50px;url="parksmouseMost ...</amongbrainbody none;basedcarrydraftreferpage_home.meterdelaydreamprovejoint</tr>drugs<!-- aprilidealallenexactforthcodeslogicView seemsblankports (200saved_linkgoalsgrantgreekhomesringsrated30px;whoseparse();" Blocklinuxjonespixel');">);if(-leftdavidhorseFocusraiseboxesTrackement</em>bar">.src=toweralt="cablehenry24px;setupitalysharpminortastewantsthis.resetwheelgirls/css/100%;clubsstuffbiblevotes 1000korea});
bandsqueue= {};80px;cking{
		aheadclockirishlike ratiostatsForm"yahoo)[0];Aboutfinds</h1>debugtasksURL =cells})();12px;primetellsturns0x600.jpg"spainbeachtaxesmicroangel--></giftssteve-linkbody.});
	mount (199FAQ</rogerfrankClass28px;feeds<h1><scotttests22px;drink) || lewisshall#039; for lovedwaste00px;ja:simon<fontreplymeetsuntercheaptightBrand) != dressclipsroomsonkeymobilmain.Name platefunnytreescom/"1.jpgwmodeparamSTARTleft idden, 201);
}
form.viruschairtransworstPagesitionpatch<!--
o-cacfirmstours,000 asiani++){adobe')[0]id=10both;menu .2.mi.png"kevincoachChildbruce2.jpgURL)+.jpg|suitesliceharry120" sweettr>
name=diegopage swiss-->

#fff;">Log.com"treatsheet) && 14px;sleepntentfiledja:id="cName"worseshots-box-delta
&lt;bears:48Z<data-rural</a> spendbakershops= "";php">ction13px;brianhellosize=o=%2F joinmaybe<img img">, fjsimg" ")[0]MTopBType"newlyDanskczechtrailknows</h5>faq">zh-cn10);
-1");type=bluestrulydavis.js';>
<!steel you h2>
form jesus100% menu.
	
walesrisksumentddingb-likteachgif" vegasdanskeestishqipsuomisobredesdeentretodospuedeañosestátienehastaotrospartedondenuevohacerformamismomejormundoaquídíassóloayudafechatodastantomenosdatosotrassitiomuchoahoralugarmayorestoshorastenerantesfotosestaspaísnuevasaludforosmedioquienmesespoderchileserávecesdecirjoséestarventagrupohechoellostengoamigocosasnivelgentemismaairesjuliotemashaciafavorjuniolibrepuntobuenoautorabrilbuenatextomarzosaberlistaluegocómoenerojuegoperúhaberestoynuncamujervalorfueralibrogustaigualvotoscasosguíapuedosomosavisousteddebennochebuscafaltaeurosseriedichocursoclavecasasleónplazolargoobrasvistaapoyojuntotratavistocrearcampohemoscincocargopisosordenhacenáreadiscopedrocercapuedapapelmenorútilclarojorgecalleponertardenadiemarcasigueellassiglocochemotosmadreclaserestoniñoquedapasarbancohijosviajepabloéstevienereinodejarfondocanalnorteletracausatomarmanoslunesautosvillavendopesartipostengamarcollevapadreunidovamoszonasambosbandamariaabusomuchasubirriojavivirgradochicaallíjovendichaestantalessalirsuelopesosfinesllamabuscoéstalleganegroplazahumorpagarjuntadobleislasbolsabañohablaluchaÁreadicenjugarnotasvalleallácargadolorabajoestégustomentemariofirmacostofichaplatahogarartesleyesaquelmuseobasespocosmitadcielochicomiedoganarsantoetapadebesplayaredessietecortecoreadudasdeseoviejodeseaaguas&quot;domaincommonstatuseventsmastersystemactionbannerremovescrollupdateglobalmediumfilternumberchangeresultpublicscreenchoosenormaltravelissuessourcetargetspringmodulemobileswitchphotosborderregionitselfsocialactivecolumnrecordfollowtitle>eitherlengthfamilyfriendlayoutauthorcreatereviewsummerserverplayedplayerexpandpolicyformatdoublepointsseriespersonlivingdesignmonthsforcesuniqueweightpeopleenergynaturesearchfigurehavingcustomoffsetletterwindowsubmitrendergroupsuploadhealthmethodvideosschoolfutureshadowdebatevaluesObjectothersrightsleaguechromesimplenoticesharedendingseasonreportonlinesquarebuttonimagesenablemovinglatestwinterFranceperiodstrongrepeatLondondetailformeddemandsecurepassedtoggleplacesdevicestaticcitiesstreamyellowattackstreetflighthiddeninfo">openedusefulvalleycausesleadersecretseconddamagesportsexceptratingsignedthingseffectfieldsstatesofficevisualeditorvolumeReportmuseummoviesparentaccessmostlymother" id="marketgroundchancesurveybeforesymbolmomentspeechmotioninsidematterCenterobjectexistsmiddleEuropegrowthlegacymannerenoughcareeransweroriginportalclientselectrandomclosedtopicscomingfatheroptionsimplyraisedescapechosenchurchdefinereasoncorneroutputmemoryiframepolicemodelsNumberduringoffersstyleskilledlistedcalledsilvermargindeletebetterbrowselimitsGlobalsinglewidgetcenterbudgetnowrapcreditclaimsenginesafetychoicespirit-stylespreadmakingneededrussiapleaseextentScriptbrokenallowschargedividefactormember-basedtheoryconfigaroundworkedhelpedChurchimpactshouldalwayslogo" bottomlist">){var prefixorangeHeader.push(couplegardenbridgelaunchReviewtakingvisionlittledatingButtonbeautythemesforgotSearchanchoralmostloadedChangereturnstringreloadMobileincomesupplySourceordersviewed&nbsp;courseAbout island<html cookiename="amazonmodernadvicein</a>: The dialoghousesBEGIN MexicostartscentreheightaddingIslandassetsEmpireSchooleffortdirectnearlymanualSelect.

Onejoinedmenu">PhilipawardshandleimportOfficeregardskillsnationSportsdegreeweekly (e.g.behinddoctorloggedunited</b></beginsplantsassistartistissued300px|canadaagencyschemeremainBrazilsamplelogo">beyond-scaleacceptservedmarineFootercamera</h1>
_form"leavesstress" />
.gif" onloadloaderOxfordsistersurvivlistenfemaleDesignsize="appealtext">levelsthankshigherforcedanimalanyoneAfricaagreedrecentPeople<br />wonderpricesturned|| {};main">inlinesundaywrap">failedcensusminutebeaconquotes150px|estateremoteemail"linkedright;signalformal1.htmlsignupprincefloat:.png" forum.AccesspaperssoundsextendHeightsliderUTF-8"&amp; Before. WithstudioownersmanageprofitjQueryannualparamsboughtfamousgooglelongeri++) {israelsayingdecidehome">headerensurebranchpiecesblock;statedtop"><racingresize--&gt;pacitysexualbureau.jpg" 10,000obtaintitlesamount, Inc.comedymenu" lyricstoday.indeedcounty_logo.FamilylookedMarketlse ifPlayerturkey);var forestgivingerrorsDomain}else{insertBlog</footerlogin.fasteragents<body 10px 0pragmafridayjuniordollarplacedcoversplugin5,000 page">boston.test(avatartested_countforumsschemaindex,filledsharesreaderalert(appearSubmitline">body">
* TheThoughseeingjerseyNews</verifyexpertinjurywidth=CookieSTART across_imagethreadnativepocketbox">
System DavidcancertablesprovedApril reallydriveritem">more">boardscolorscampusfirst || [];media.guitarfinishwidth:showedOther .php" assumelayerswilsonstoresreliefswedenCustomeasily your String

Whiltaylorclear:resortfrenchthough") + "<body>buyingbrandsMembername">oppingsector5px;">vspacepostermajor coffeemartinmaturehappen</nav>kansaslink">Images=falsewhile hspace0&amp; 

In  powerPolski-colorjordanBottomStart -count2.htmlnews">01.jpgOnline-rightmillerseniorISBN 00,000 guidesvalue)ectionrepair.xml"  rights.html-blockregExp:hoverwithinvirginphones</tr>
using 
	var >');
	</td>
</tr>
bahasabrasilgalegomagyarpolskisrpskiردو中文简体繁體信息中国我们一个公司管理论坛可以服务时间个人产品自己企业查看工作联系没有网站所有评论中心文章用户首页作者技术问题相关下载搜索使用软件在线主题资料视频回复注册网络收藏内容推荐市场消息空间发布什么好友生活图片发展如果手机新闻最新方式北京提供关于更多这个系统知道游戏广告其他发表安全第一会员进行点击版权电子世界设计免费教育加入活动他们商品博客现在上海如何已经留言详细社区登录本站需要价格支持国际链接国家建设朋友阅读法律位置经济选择这样当前分类排行因为交易最后音乐不能通过行业科技可能设备合作大家社会研究专业全部项目这里还是开始情况电脑文件品牌帮助文化资源大学学习地址浏览投资工程要求怎么时候功能主要目前资讯城市方法电影招聘声明任何健康数据美国汽车介绍但是交流生产所以电话显示一些单位人员分析地图旅游工具学生系列网友帖子密码频道控制地区基本全国网上重要第二喜欢进入友情这些考试发现培训以上政府成为环境香港同时娱乐发送一定开发作品标准欢迎解决地方一下以及责任或者客户代表积分女人数码销售出现离线应用列表不同编辑统计查询不要有关机构很多播放组织政策直接能力来源時間看到热门关键专区非常英语百度希望美女比较知识规定建议部门意见精彩日本提高发言方面基金处理权限影片银行还有分享物品经营添加专家这种话题起来业务公告记录简介质量男人影响引用报告部分快速咨询时尚注意申请学校应该历史只是返回购买名称为了成功说明供应孩子专题程序一般會員只有其它保护而且今天窗口动态状态特别认为必须更新小说我們作为媒体包括那么一样国内是否根据电视学院具有过程由于人才出来不过正在明星故事关系标题商务输入一直基础教学了解建筑结果全球通知计划对于艺术相册发生真的建立等级类型经验实现制作来自标签以下原创无法其中個人一切指南关闭集团第三关注因此照片深圳商业广州日期高级最近综合表示专辑行为交通评价觉得精华家庭完成感觉安装得到邮件制度食品虽然转载报价记者方案行政人民用品东西提出酒店然后付款热点以前完全发帖设置领导工业医院看看经典原因平台各种增加材料新增之后职业效果今年论文我国告诉版主修改参与打印快乐机械观点存在精神获得利用继续你们这么模式语言能够雅虎操作风格一起科学体育短信条件治疗运动产业会议导航先生联盟可是問題结构作用调查資料自动负责农业访问实施接受讨论那个反馈加强女性范围服務休闲今日客服觀看参加的话一点保证图书有效测试移动才能决定股票不断需求不得办法之间采用营销投诉目标爱情摄影有些複製文学机会数字装修购物农村全面精品其实事情水平提示上市谢谢普通教师上传类别歌曲拥有创新配件只要时代資訊达到人生订阅老师展示心理贴子網站主題自然级别简单改革那些来说打开代码删除证券节目重点次數多少规划资金找到以后大全主页最佳回答天下保障现代检查投票小时沒有正常甚至代理目录公开复制金融幸福版本形成准备行情回到思想怎样协议认证最好产生按照服装广东动漫采购新手组图面板参考政治容易天地努力人们升级速度人物调整流行造成文字韩国贸易开展相關表现影视如此美容大小报道条款心情许多法规家居书店连接立即举报技巧奥运登入以来理论事件自由中华办公妈妈真正不错全文合同价值别人监督具体世纪团队创业承担增长有人保持商家维修台湾左右股份答案实际电信经理生命宣传任务正式特色下来协会只能当然重新內容指导运行日志賣家超过土地浙江支付推出站长杭州执行制造之一推广现场描述变化传统歌手保险课程医疗经过过去之前收入年度杂志美丽最高登陆未来加工免责教程版块身体重庆出售成本形式土豆出價东方邮箱南京求职取得职位相信页面分钟网页确定图例网址积极错误目的宝贝机关风险授权病毒宠物除了評論疾病及时求购站点儿童每天中央认识每个天津字体台灣维护本页个性官方常见相机战略应当律师方便校园股市房屋栏目员工导致突然道具本网结合档案劳动另外美元引起改变第四会计說明隐私宝宝规范消费共同忘记体系带来名字發表开放加盟受到二手大量成人数量共享区域女孩原则所在结束通信超级配置当时优秀性感房产遊戲出口提交就业保健程度参数事业整个山东情感特殊分類搜尋属于门户财务声音及其财经坚持干部成立利益考虑成都包装用戶比赛文明招商完整真是眼睛伙伴威望领域卫生优惠論壇公共良好充分符合附件特点不可英文资产根本明显密碼公众民族更加享受同学启动适合原来问答本文美食绿色稳定终于生物供求搜狐力量严重永远写真有限竞争对象费用不好绝对十分促进点评影音优势不少欣赏并且有点方向全新信用设施形象资格突破随着重大于是毕业智能化工完美商城统一出版打造產品概况用于保留因素中國存储贴图最愛长期口价理财基地安排武汉里面创建天空首先完善驱动下面不再诚信意义阳光英国漂亮军事玩家群众农民即可名稱家具动画想到注明小学性能考研硬件观看清楚搞笑首頁黄金适用江苏真实主管阶段註冊翻译权利做好似乎通讯施工狀態也许环保培养概念大型机票理解匿名cuandoenviarmadridbuscariniciotiempoporquecuentaestadopuedenjuegoscontraestánnombretienenperfilmaneraamigosciudadcentroaunquepuedesdentroprimerpreciosegúnbuenosvolverpuntossemanahabíaagostonuevosunidoscarlosequiponiñosmuchosalgunacorreoimagenpartirarribamaríahombreempleoverdadcambiomuchasfueronpasadolíneaparecenuevascursosestabaquierolibroscuantoaccesomiguelvarioscuatrotienesgruposseráneuropamediosfrenteacercademásofertacochesmodeloitalialetrasalgúncompracualesexistecuerposiendoprensallegarviajesdineromurciapodrápuestodiariopuebloquieremanuelpropiocrisisciertoseguromuertefuentecerrargrandeefectopartesmedidapropiaofrecetierrae-mailvariasformasfuturoobjetoseguirriesgonormasmismosúnicocaminositiosrazóndebidopruebatoledoteníajesúsesperococinaorigentiendacientocádizhablarseríalatinafuerzaestiloguerraentraréxitolópezagendavídeoevitarpaginametrosjavierpadresfácilcabezaáreassalidaenvíojapónabusosbienestextosllevarpuedanfuertecomúnclaseshumanotenidobilbaounidadestáseditarcreadoдлячтокакилиэтовсеегопритакещеужеКакбезбылониВсеподЭтотомчемнетлетразонагдемнеДляПринаснихтемктогодвоттамСШАмаяЧтовасвамемуТакдванамэтиэтуВамтехпротутнаддняВоттринейВаснимсамтотрубОнимирнееОООлицэтаОнанемдоммойдвеоносудकेहैकीसेकाकोऔरपरनेएककिभीइसकरतोहोआपहीयहयातकथाjagranआजजोअबदोगईजागएहमइनवहयेथेथीघरजबदीकईजीवेनईनएहरउसमेकमवोलेसबमईदेओरआमबसभरबनचलमनआगसीलीعلىإلىهذاآخرعددالىهذهصورغيركانولابينعرضذلكهنايومقالعليانالكنحتىقبلوحةاخرفقطعبدركنإذاكمااحدإلافيهبعضكيفبحثومنوهوأناجدالهاسلمعندليسعبرصلىمنذبهاأنهمثلكنتالاحيثمصرشرححولوفياذالكلمرةانتالفأبوخاصأنتانهاليعضووقدابنخيربنتلكمشاءوهيابوقصصومارقمأحدنحنعدمرأياحةكتبدونيجبمنهتحتجهةسنةيتمكرةغزةنفسبيتللهلناتلكقلبلماعنهأولشيءنورأمافيكبكلذاترتببأنهمسانكبيعفقدحسنلهمشعرأهلشهرقطرطلبprofileservicedefaulthimselfdetailscontentsupportstartedmessagesuccessfashion<title>countryaccountcreatedstoriesresultsrunningprocesswritingobjectsvisiblewelcomearticleunknownnetworkcompanydynamicbrowserprivacyproblemServicerespectdisplayrequestreservewebsitehistoryfriendsoptionsworkingversionmillionchannelwindow.addressvisitedweathercorrectproductedirectforwardyou canremovedsubjectcontrolarchivecurrentreadinglibrarylimitedmanagerfurthersummarymachineminutesprivatecontextprogramsocietynumberswrittenenabledtriggersourcesloadingelementpartnerfinallyperfectmeaningsystemskeepingculture&quot;,journalprojectsurfaces&quot;expiresreviewsbalanceEnglishContentthroughPlease opinioncontactaverageprimaryvillageSpanishgallerydeclinemeetingmissionpopularqualitymeasuregeneralspeciessessionsectionwriterscounterinitialreportsfiguresmembersholdingdisputeearlierexpressdigitalpictureAnothermarriedtrafficleadingchangedcentralvictoryimages/reasonsstudiesfeaturelistingmust beschoolsVersionusuallyepisodeplayinggrowingobviousoverlaypresentactions</ul>
wrapperalreadycertainrealitystorageanotherdesktopofferedpatternunusualDigitalcapitalWebsitefailureconnectreducedAndroiddecadesregular &amp; animalsreleaseAutomatgettingmethodsnothingPopularcaptionletterscapturesciencelicensechangesEngland=1&amp;History = new CentralupdatedSpecialNetworkrequirecommentwarningCollegetoolbarremainsbecauseelectedDeutschfinanceworkersquicklybetweenexactlysettingdiseaseSocietyweaponsexhibit&lt;!--Controlclassescoveredoutlineattacksdevices(windowpurposetitle="Mobile killingshowingItaliandroppedheavilyeffects-1']);
confirmCurrentadvancesharingopeningdrawingbillionorderedGermanyrelated</form>includewhetherdefinedSciencecatalogArticlebuttonslargestuniformjourneysidebarChicagoholidayGeneralpassage,&quot;animatefeelingarrivedpassingnaturalroughly.

The but notdensityBritainChineselack oftributeIreland" data-factorsreceivethat isLibraryhusbandin factaffairsCharlesradicalbroughtfindinglanding:lang="return leadersplannedpremiumpackageAmericaEdition]&quot;Messageneed tovalue="complexlookingstationbelievesmaller-mobilerecordswant tokind ofFirefoxyou aresimilarstudiedmaximumheadingrapidlyclimatekingdomemergedamountsfoundedpioneerformuladynastyhow to SupportrevenueeconomyResultsbrothersoldierlargelycalling.&quot;AccountEdward segmentRobert effortsPacificlearnedup withheight:we haveAngelesnations_searchappliedacquiremassivegranted: falsetreatedbiggestbenefitdrivingStudiesminimumperhapsmorningsellingis usedreversevariant role="missingachievepromotestudentsomeoneextremerestorebottom:evolvedall thesitemapenglishway to  AugustsymbolsCompanymattersmusicalagainstserving})();
paymenttroubleconceptcompareparentsplayersregionsmonitor ''The winningexploreadaptedGalleryproduceabilityenhancecareers). The collectSearch ancientexistedfooter handlerprintedconsoleEasternexportswindowsChannelillegalneutralsuggest_headersigning.html">settledwesterncausing-webkitclaimedJusticechaptervictimsThomas mozillapromisepartieseditionoutside:false,hundredOlympic_buttonauthorsreachedchronicdemandssecondsprotectadoptedprepareneithergreatlygreateroverallimprovecommandspecialsearch.worshipfundingthoughthighestinsteadutilityquarterCulturetestingclearlyexposedBrowserliberal} catchProjectexamplehide();FloridaanswersallowedEmperordefenseseriousfreedomSeveral-buttonFurtherout of != nulltrainedDenmarkvoid(0)/all.jspreventRequestStephen

When observe</h2>
Modern provide" alt="borders.

For 

Many artistspoweredperformfictiontype ofmedicalticketsopposedCouncilwitnessjusticeGeorge Belgium...</a>twitternotablywaitingwarfare Other rankingphrasesmentionsurvivescholar</p>
 Countryignoredloss ofjust asGeorgiastrange<head><stopped1']);
islandsnotableborder:list ofcarried100,000</h3>
 severalbecomesselect wedding00.htmlmonarchoff theteacherhighly biologylife ofor evenrise of&raquo;plusonehunting(thoughDouglasjoiningcirclesFor theAncientVietnamvehiclesuch ascrystalvalue =Windowsenjoyeda smallassumed<a id="foreign All rihow theDisplayretiredhoweverhidden;battlesseekingcabinetwas notlook atconductget theJanuaryhappensturninga:hoverOnline French lackingtypicalextractenemieseven ifgeneratdecidedare not/searchbeliefs-image:locatedstatic.login">convertviolententeredfirst">circuitFinlandchemistshe was10px;">as suchdivided</span>will beline ofa greatmystery/index.fallingdue to railwaycollegemonsterdescentit withnuclearJewish protestBritishflowerspredictreformsbutton who waslectureinstantsuicidegenericperiodsmarketsSocial fishingcombinegraphicwinners<br /><by the NaturalPrivacycookiesoutcomeresolveSwedishbrieflyPersianso muchCenturydepictscolumnshousingscriptsnext tobearingmappingrevisedjQuery(-width:title">tooltipSectiondesignsTurkishyounger.match(})();

burningoperatedegreessource=Richardcloselyplasticentries</tr>
color:#ul id="possessrollingphysicsfailingexecutecontestlink toDefault<br />
: true,chartertourismclassicproceedexplain</h1>
online.?xml vehelpingdiamonduse theairlineend -->).attr(readershosting#ffffffrealizeVincentsignals src="/ProductdespitediversetellingPublic held inJoseph theatreaffects<style>a largedoesn'tlater, ElementfaviconcreatorHungaryAirportsee theso thatMichaelSystemsPrograms, and  width=e&quot;tradingleft">
personsGolden Affairsgrammarformingdestroyidea ofcase ofoldest this is.src = cartoonregistrCommonsMuslimsWhat isin manymarkingrevealsIndeed,equally/show_aoutdoorescape(Austriageneticsystem,In the sittingHe alsoIslandsAcademy
		<!--Daniel bindingblock">imposedutilizeAbraham(except{width:putting).html(|| [];
DATA[ *kitchenmountedactual dialectmainly _blank'installexpertsif(typeIt also&copy; ">Termsborn inOptionseasterntalkingconcerngained ongoingjustifycriticsfactoryits ownassaultinvitedlastinghis ownhref="/" rel="developconcertdiagramdollarsclusterphp?id=alcohol);})();using a><span>vesselsrevivalAddressamateurandroidallegedillnesswalkingcentersqualifymatchesunifiedextinctDefensedied in
	<!-- customslinkingLittle Book ofeveningmin.js?are thekontakttoday's.html" target=wearingAll Rig;
})();raising Also, crucialabout">declare-->
<scfirefoxas muchappliesindex, s, but type = 

<!--towardsRecordsPrivateForeignPremierchoicesVirtualreturnsCommentPoweredinline;povertychamberLiving volumesAnthonylogin" RelatedEconomyreachescuttinggravitylife inChapter-shadowNotable</td>
 returnstadiumwidgetsvaryingtravelsheld bywho arework infacultyangularwho hadairporttown of

Some 'click'chargeskeywordit willcity of(this);Andrew unique checkedor more300px; return;rsion="pluginswithin herselfStationFederalventurepublishsent totensionactresscome tofingersDuke ofpeople,exploitwhat isharmonya major":"httpin his menu">
monthlyofficercouncilgainingeven inSummarydate ofloyaltyfitnessand wasemperorsupremeSecond hearingRussianlongestAlbertalateralset of small">.appenddo withfederalbank ofbeneathDespiteCapitalgrounds), and percentit fromclosingcontainInsteadfifteenas well.yahoo.respondfighterobscurereflectorganic= Math.editingonline paddinga wholeonerroryear ofend of barrierwhen itheader home ofresumedrenamedstrong>heatingretainscloudfrway of March 1knowingin partBetweenlessonsclosestvirtuallinks">crossedEND -->famous awardedLicenseHealth fairly wealthyminimalAfricancompetelabel">singingfarmersBrasil)discussreplaceGregoryfont copursuedappearsmake uproundedboth ofblockedsaw theofficescoloursif(docuwhen heenforcepush(fuAugust UTF-8">Fantasyin mostinjuredUsuallyfarmingclosureobject defenceuse of Medical<body>
evidentbe usedkeyCodesixteenIslamic#000000entire widely active (typeofone cancolor =speakerextendsPhysicsterrain<tbody>funeralviewingmiddle cricketprophetshifteddoctorsRussell targetcompactalgebrasocial-bulk ofman and</td>
 he left).val()false);logicalbankinghome tonaming Arizonacredits);
});
founderin turnCollinsbefore But thechargedTitle">CaptainspelledgoddessTag -->Adding:but wasRecent patientback in=false&Lincolnwe knowCounterJudaismscript altered']);
  has theunclearEvent',both innot all

<!-- placinghard to centersort ofclientsstreetsBernardassertstend tofantasydown inharbourFreedomjewelry/about..searchlegendsis mademodern only ononly toimage" linear painterand notrarely acronymdelivershorter00&amp;as manywidth="/* <![Ctitle =of the lowest picked escapeduses ofpeoples PublicMatthewtacticsdamagedway forlaws ofeasy to windowstrong  simple}catch(seventhinfoboxwent topaintedcitizenI don'tretreat. Some ww.");
bombingmailto:made in. Many carries||{};wiwork ofsynonymdefeatsfavoredopticalpageTraunless sendingleft"><comScorAll thejQuery.touristClassicfalse" Wilhelmsuburbsgenuinebishops.split(global followsbody ofnominalContactsecularleft tochiefly-hidden-banner</li>

. When in bothdismissExplorealways via thespañolwelfareruling arrangecaptainhis sonrule ofhe tookitself,=0&amp;(calledsamplesto makecom/pagMartin Kennedyacceptsfull ofhandledBesides//--></able totargetsessencehim to its by common.mineralto takeways tos.org/ladvisedpenaltysimple:if theyLettersa shortHerbertstrikes groups.lengthflightsoverlapslowly lesser social </p>
		it intoranked rate oful>
  attemptpair ofmake itKontaktAntoniohaving ratings activestreamstrapped").css(hostilelead tolittle groups,Picture-->

 rows=" objectinverse<footerCustomV><\/scrsolvingChamberslaverywoundedwhereas!= 'undfor allpartly -right:Arabianbacked centuryunit ofmobile-Europe,is homerisk ofdesiredClintoncost ofage of become none ofp&quot;Middle ead')[0Criticsstudios>&copy;group">assemblmaking pressedwidget.ps:" ? rebuiltby someFormer editorsdelayedCanonichad thepushingclass="but arepartialBabylonbottom carrierCommandits useAs withcoursesa thirddenotesalso inHouston20px;">accuseddouble goal ofFamous ).bind(priests Onlinein Julyst + "gconsultdecimalhelpfulrevivedis veryr'+'iptlosing femalesis alsostringsdays ofarrivalfuture <objectforcingString(" />
		here isencoded.  The balloondone by/commonbgcolorlaw of Indianaavoidedbut the2px 3pxjquery.after apolicy.men andfooter-= true;for usescreen.Indian image =family,http:// &nbsp;driverseternalsame asnoticedviewers})();
 is moreseasonsformer the newis justconsent Searchwas thewhy theshippedbr><br>width: height=made ofcuisineis thata very Admiral fixed;normal MissionPress, ontariocharsettry to invaded="true"spacingis mosta more totallyfall of});
  immensetime inset outsatisfyto finddown tolot of Playersin Junequantumnot thetime todistantFinnishsrc = (single help ofGerman law andlabeledforestscookingspace">header-well asStanleybridges/globalCroatia About [0];
  it, andgroupedbeing a){throwhe madelighterethicalFFFFFF"bottom"like a employslive inas seenprintermost ofub-linkrejectsand useimage">succeedfeedingNuclearinformato helpWomen'sNeitherMexicanprotein<table by manyhealthylawsuitdevised.push({sellerssimply Through.cookie Image(older">us.js"> Since universlarger open to!-- endlies in']);
  marketwho is ("DOMComanagedone fortypeof Kingdomprofitsproposeto showcenter;made itdressedwere inmixtureprecisearisingsrc = 'make a securedBaptistvoting 
		var March 2grew upClimate.removeskilledway the</head>face ofacting right">to workreduceshas haderectedshow();action=book ofan area== "htt<header
<html>conformfacing cookie.rely onhosted .customhe wentbut forspread Family a meansout theforums.footage">MobilClements" id="as highintense--><!--female is seenimpliedset thea stateand hisfastestbesidesbutton_bounded"><img Infoboxevents,a youngand areNative cheaperTimeoutand hasengineswon the(mostlyright: find a -bottomPrince area ofmore ofsearch_nature,legallyperiod,land ofor withinducedprovingmissilelocallyAgainstthe wayk&quot;px;">
pushed abandonnumeralCertainIn thismore inor somename isand, incrownedISBN 0-createsOctobermay notcenter late inDefenceenactedwish tobroadlycoolingonload=it. TherecoverMembersheight assumes<html>
people.in one =windowfooter_a good reklamaothers,to this_cookiepanel">London,definescrushedbaptismcoastalstatus title" move tolost inbetter impliesrivalryservers SystemPerhapses and contendflowinglasted rise inGenesisview ofrising seem tobut in backinghe willgiven agiving cities.flow of Later all butHighwayonly bysign ofhe doesdiffersbattery&amp;lasinglesthreatsintegertake onrefusedcalled =US&ampSee thenativesby thissystem.head of:hover,lesbiansurnameand allcommon/header__paramsHarvard/pixel.removalso longrole ofjointlyskyscraUnicodebr />
AtlantanucleusCounty,purely count">easily build aonclicka givenpointerh&quot;events else {
ditionsnow the, with man whoorg/Webone andcavalryHe diedseattle00,000 {windowhave toif(windand itssolely m&quot;renewedDetroitamongsteither them inSenatorUs</a><King ofFrancis-produche usedart andhim andused byscoringat hometo haverelatesibilityfactionBuffalolink"><what hefree toCity ofcome insectorscountedone daynervoussquare };if(goin whatimg" alis onlysearch/tuesdaylooselySolomonsexual - <a hrmedium"DO NOT France,with a war andsecond take a >


market.highwaydone inctivity"last">obligedrise to"undefimade to Early praisedin its for hisathleteJupiterYahoo! termed so manyreally s. The a woman?value=direct right" bicycleacing="day andstatingRather,higher Office are nowtimes, when a pay foron this-link">;borderaround annual the Newput the.com" takin toa brief(in thegroups.; widthenzymessimple in late{returntherapya pointbanninginks">
();" rea place\u003Caabout atr>
		ccount gives a<SCRIPTRailwaythemes/toolboxById("xhumans,watchesin some if (wicoming formats Under but hashanded made bythan infear ofdenoted/iframeleft involtagein eacha&quot;base ofIn manyundergoregimesaction </p>
<ustomVa;&gt;</importsor thatmostly &amp;re size="</a></ha classpassiveHost = WhetherfertileVarious=[];(fucameras/></td>acts asIn some>

<!organis <br />Beijingcatalàdeutscheuropeueuskaragaeilgesvenskaespañamensajeusuariotrabajoméxicopáginasiempresistemaoctubreduranteañadirempresamomentonuestroprimeratravésgraciasnuestraprocesoestadoscalidadpersonanúmeroacuerdomúsicamiembroofertasalgunospaísesejemploderechoademásprivadoagregarenlacesposiblehotelessevillaprimeroúltimoeventosarchivoculturamujeresentradaanuncioembargomercadograndesestudiomejoresfebrerodiseñoturismocódigoportadaespaciofamiliaantoniopermiteguardaralgunaspreciosalguiensentidovisitastítuloconocersegundoconsejofranciaminutossegundatenemosefectosmálagasesiónrevistagranadacompraringresogarcíaacciónecuadorquienesinclusodeberámateriahombresmuestrapodríamañanaúltimaestamosoficialtambienningúnsaludospodemosmejorarpositionbusinesshomepagesecuritylanguagestandardcampaignfeaturescategoryexternalchildrenreservedresearchexchangefavoritetemplatemilitaryindustryservicesmaterialproductsz-index:commentssoftwarecompletecalendarplatformarticlesrequiredmovementquestionbuildingpoliticspossiblereligionphysicalfeedbackregisterpicturesdisabledprotocolaudiencesettingsactivityelementslearninganythingabstractprogressoverviewmagazineeconomictrainingpressurevarious <strong>propertyshoppingtogetheradvancedbehaviordownloadfeaturedfootballselectedLanguagedistanceremembertrackingpasswordmodifiedstudentsdirectlyfightingnortherndatabasefestivalbreakinglocationinternetdropdownpracticeevidencefunctionmarriageresponseproblemsnegativeprogramsanalysisreleasedbanner">purchasepoliciesregionalcreativeargumentbookmarkreferrerchemicaldivisioncallbackseparateprojectsconflicthardwareinterestdeliverymountainobtained= false;for(var acceptedcapacitycomputeridentityaircraftemployedproposeddomesticincludesprovidedhospitalverticalcollapseapproachpartnerslogo"><adaughterauthor" culturalfamilies/images/assemblypowerfulteachingfinisheddistrictcriticalcgi-bin/purposesrequireselectionbecomingprovidesacademicexerciseactuallymedicineconstantaccidentMagazinedocumentstartingbottom">observed: &quot;extendedpreviousSoftwarecustomerdecisionstrengthdetailedslightlyplanningtextareacurrencyeveryonestraighttransferpositiveproducedheritageshippingabsolutereceivedrelevantbutton" violenceanywherebenefitslaunchedrecentlyalliancefollowedmultiplebulletinincludedoccurredinternal$(this).republic><tr><tdcongressrecordedultimatesolution<ul id="discoverHome</a>websitesnetworksalthoughentirelymemorialmessagescontinueactive">somewhatvictoriaWestern  title="LocationcontractvisitorsDownloadwithout right">
measureswidth = variableinvolvedvirginianormallyhappenedaccountsstandingnationalRegisterpreparedcontrolsaccuratebirthdaystrategyofficialgraphicscriminalpossiblyconsumerPersonalspeakingvalidateachieved.jpg" />machines</h2>
  keywordsfriendlybrotherscombinedoriginalcomposedexpectedadequatepakistanfollow" valuable</label>relativebringingincreasegovernorplugins/List of Header">" name=" (&quot;graduate</head>
commercemalaysiadirectormaintain;height:schedulechangingback to catholicpatternscolor: #greatestsuppliesreliable</ul>
		<select citizensclothingwatching<li id="specificcarryingsentence<center>contrastthinkingcatch(e)southernMichael merchantcarouselpadding:interior.split("lizationOctober ){returnimproved--&gt;

coveragechairman.png" />subjectsRichard whateverprobablyrecoverybaseballjudgmentconnect..css" /> websitereporteddefault"/></a>
electricscotlandcreationquantity. ISBN 0did not instance-search-" lang="speakersComputercontainsarchivesministerreactiondiscountItalianocriteriastrongly: 'http:'script'coveringofferingappearedBritish identifyFacebooknumerousvehiclesconcernsAmericanhandlingdiv id="William provider_contentaccuracysection andersonflexibleCategorylawrence<script>layout="approved maximumheader"></table>Serviceshamiltoncurrent canadianchannels/themes//articleoptionalportugalvalue=""intervalwirelessentitledagenciesSearch" measuredthousandspending&hellip;new Date" size="pageNamemiddle" " /></a>hidden">sequencepersonaloverflowopinionsillinoislinks">
	<title>versionssaturdayterminalitempropengineersectionsdesignerproposal="false"Españolreleasessubmit" er&quot;additionsymptomsorientedresourceright"><pleasurestationshistory.leaving  border=contentscenter">.

Some directedsuitablebulgaria.show();designedGeneral conceptsExampleswilliamsOriginal"><span>search">operatorrequestsa &quot;allowingDocumentrevision. 

The yourselfContact michiganEnglish columbiapriorityprintingdrinkingfacilityreturnedContent officersRussian generate-8859-1"indicatefamiliar qualitymargin:0 contentviewportcontacts-title">portable.length eligibleinvolvesatlanticonload="default.suppliedpaymentsglossary

After guidance</td><tdencodingmiddle">came to displaysscottishjonathanmajoritywidgets.clinicalthailandteachers<head>
	affectedsupportspointer;toString</small>oklahomawill be investor0" alt="holidaysResourcelicensed (which . After considervisitingexplorerprimary search" android"quickly meetingsestimate;return ;color:# height=approval, &quot; checked.min.js"magnetic></a></hforecast. While thursdaydvertise&eacute;hasClassevaluateorderingexistingpatients Online coloradoOptions"campbell<!-- end</span><<br />
_popups|sciences,&quot; quality Windows assignedheight: <b classle&quot; value=" Companyexamples<iframe believespresentsmarshallpart of properly).

The taxonomymuch of </span>
" data-srtuguêsscrollTo project<head>
attorneyemphasissponsorsfancyboxworld's wildlifechecked=sessionsprogrammpx;font- Projectjournalsbelievedvacationthompsonlightingand the special border=0checking</tbody><button Completeclearfix
<head>
article <sectionfindingsrole in popular  Octoberwebsite exposureused to  changesoperatedclickingenteringcommandsinformed numbers  </div>creatingonSubmitmarylandcollegesanalyticlistingscontact.loggedInadvisorysiblingscontent"s&quot;)s. This packagescheckboxsuggestspregnanttomorrowspacing=icon.pngjapanesecodebasebutton">gamblingsuch as , while </span> missourisportingtop:1px .</span>tensionswidth="2lazyloadnovemberused in height="cript">
&nbsp;</<tr><td height:2/productcountry include footer" &lt;!-- title"></jquery.</form>
(简体)(繁體)hrvatskiitalianoromânătürkçeاردوtambiénnoticiasmensajespersonasderechosnacionalserviciocontactousuariosprogramagobiernoempresasanunciosvalenciacolombiadespuésdeportesproyectoproductopúbliconosotroshistoriapresentemillonesmediantepreguntaanteriorrecursosproblemasantiagonuestrosopiniónimprimirmientrasaméricavendedorsociedadrespectorealizarregistropalabrasinterésentoncesespecialmiembrosrealidadcórdobazaragozapáginassocialesbloqueargestiónalquilersistemascienciascompletoversióncompletaestudiospúblicaobjetivoalicantebuscadorcantidadentradasaccionesarchivossuperiormayoríaalemaniafunciónúltimoshaciendoaquellosediciónfernandoambientefacebooknuestrasclientesprocesosbastantepresentareportarcongresopublicarcomerciocontratojóvenesdistritotécnicaconjuntoenergíatrabajarasturiasrecienteutilizarboletínsalvadorcorrectatrabajosprimerosnegocioslibertaddetallespantallapróximoalmeríaanimalesquiénescorazónsecciónbuscandoopcionesexteriorconceptotodavíagaleríaescribirmedicinalicenciaconsultaaspectoscríticadólaresjusticiadeberánperíodonecesitamantenerpequeñorecibidatribunaltenerifecancióncanariasdescargadiversosmallorcarequieretécnicodeberíaviviendafinanzasadelantefuncionaconsejosdifícilciudadesantiguasavanzadatérminounidadessánchezcampañasoftonicrevistascontienesectoresmomentosfacultadcréditodiversassupuestofactoressegundospequeñaгодаеслиестьбылобытьэтомЕслитогоменявсехэтойдажебылигодуденьэтотбыласебяодинсебенадосайтфотонегосвоисвойигрытожевсемсвоюлишьэтихпокаднейдомамиралиботемухотядвухсетилюдиделомиретебясвоевидечегоэтимсчеттемыценысталведьтемеводытебевышенамитипатомуправлицаоднагодызнаюмогудругвсейидеткиноодноделаделесрокиюнявесьЕстьразанашиاللهالتيجميعخاصةالذيعليهجديدالآنالردتحكمصفحةكانتاللييكونشبكةفيهابناتحواءأكثرخلالالحبدليلدروساضغطتكونهناكساحةناديالطبعليكشكرايمكنمنهاشركةرئيسنشيطماذاالفنشبابتعبررحمةكافةيقولمركزكلمةأحمدقلبييعنيصورةطريقشاركجوالأخرىمعناابحثعروضبشكلمسجلبنانخالدكتابكليةبدونأيضايوجدفريقكتبتأفضلمطبخاكثرباركافضلاحلىنفسهأيامردودأنهاديناالانمعرضتعلمداخلممكن                      	



	                                                resourcescountriesquestionsequipmentcommunityavailablehighlightDTD/xhtmlmarketingknowledgesomethingcontainerdirectionsubscribeadvertisecharacter" value="</select>Australia" class="situationauthorityfollowingprimarilyoperationchallengedevelopedanonymousfunction functionscompaniesstructureagreement" title="potentialeducationargumentssecondarycopyrightlanguagesexclusivecondition</form>
statementattentionBiography} else {
solutionswhen the Analyticstemplatesdangeroussatellitedocumentspublisherimportantprototypeinfluence&raquo;</effectivegenerallytransformbeautifultransportorganizedpublishedprominentuntil thethumbnailNational .focus();over the migrationannouncedfooter">
exceptionless thanexpensiveformationframeworkterritoryndicationcurrentlyclassNamecriticismtraditionelsewhereAlexanderappointedmaterialsbroadcastmentionedaffiliate</option>treatmentdifferent/default.Presidentonclick="biographyotherwisepermanentFrançaisHollywoodexpansionstandards</style>
reductionDecember preferredCambridgeopponentsBusiness confusion>
<title>presentedexplaineddoes not worldwideinterfacepositionsnewspaper</table>
mountainslike the essentialfinancialselectionaction="/abandonedEducationparseInt(stabilityunable to</title>
relationsNote thatefficientperformedtwo yearsSince thethereforewrapper">alternateincreasedBattle ofperceivedtrying tonecessaryportrayedelectionsElizabeth</iframe>discoveryinsurances.length;legendaryGeographycandidatecorporatesometimesservices.inherited</strong>CommunityreligiouslocationsCommitteebuildingsthe worldno longerbeginningreferencecannot befrequencytypicallyinto the relative;recordingpresidentinitiallytechniquethe otherit can beexistenceunderlinethis timetelephoneitemscopepracticesadvantage);return For otherprovidingdemocracyboth the extensivesufferingsupportedcomputers functionpracticalsaid thatit may beEnglish</from the scheduleddownloads</label>
suspectedmargin: 0spiritual</head>

microsoftgraduallydiscussedhe becameexecutivejquery.jshouseholdconfirmedpurchasedliterallydestroyedup to thevariationremainingit is notcenturiesJapanese among thecompletedalgorithminterestsrebellionundefinedencourageresizableinvolvingsensitiveuniversalprovision(althoughfeaturingconducted), which continued-header">February numerous overflow:componentfragmentsexcellentcolspan="technicalnear the Advanced source ofexpressedHong Kong Facebookmultiple mechanismelevationoffensive</form>
	sponsoreddocument.or &quot;there arethose whomovementsprocessesdifficultsubmittedrecommendconvincedpromoting" width=".replace(classicalcoalitionhis firstdecisionsassistantindicatedevolution-wrapper"enough toalong thedelivered-->
<!--American protectedNovember </style><furnitureInternet  onblur="suspendedrecipientbased on Moreover,abolishedcollectedwere madeemotionalemergencynarrativeadvocatespx;bordercommitteddir="ltr"employeesresearch. selectedsuccessorcustomersdisplayedSeptemberaddClass(Facebook suggestedand lateroperatingelaborateSometimesInstitutecertainlyinstalledfollowersJerusalemthey havecomputinggeneratedprovincesguaranteearbitraryrecognizewanted topx;width:theory ofbehaviourWhile theestimatedbegan to it becamemagnitudemust havemore thanDirectoryextensionsecretarynaturallyoccurringvariablesgiven theplatform.</label><failed tocompoundskinds of societiesalongside --&gt;

southwestthe rightradiationmay have unescape(spoken in" href="/programmeonly the come fromdirectoryburied ina similarthey were</font></Norwegianspecifiedproducingpassenger(new DatetemporaryfictionalAfter theequationsdownload.regularlydeveloperabove thelinked tophenomenaperiod oftooltip">substanceautomaticaspect ofAmong theconnectedestimatesAir Forcesystem ofobjectiveimmediatemaking itpaintingsconqueredare stillproceduregrowth ofheaded byEuropean divisionsmoleculesfranchiseintentionattractedchildhoodalso useddedicatedsingaporedegree offather ofconflicts</a></p>
came fromwere usednote thatreceivingExecutiveeven moreaccess tocommanderPoliticalmusiciansdeliciousprisonersadvent ofUTF-8" /><![CDATA[">ContactSouthern bgcolor="series of. It was in Europepermittedvalidate.appearingofficialsseriously-languageinitiatedextendinglong-terminflationsuch thatgetCookiemarked by</button>implementbut it isincreasesdown the requiringdependent-->
<!-- interviewWith the copies ofconsensuswas builtVenezuela(formerlythe statepersonnelstrategicfavour ofinventionWikipediacontinentvirtuallywhich wasprincipleComplete identicalshow thatprimitiveaway frommolecularpreciselydissolvedUnder theversion=">&nbsp;</It is the This is will haveorganismssome timeFriedrichwas firstthe only fact thatform id="precedingTechnicalphysicistoccurs innavigatorsection">span id="sought tobelow thesurviving}</style>his deathas in thecaused bypartiallyexisting using thewas givena list oflevels ofnotion ofOfficial dismissedscientistresemblesduplicateexplosiverecoveredall othergalleries{padding:people ofregion ofaddressesassociateimg alt="in modernshould bemethod ofreportingtimestampneeded tothe Greatregardingseemed toviewed asimpact onidea thatthe Worldheight ofexpandingThese arecurrent">carefullymaintainscharge ofClassicaladdressedpredictedownership<div id="right">
residenceleave thecontent">are often  })();
probably Professor-button" respondedsays thathad to beplaced inHungarianstatus ofserves asUniversalexecutionaggregatefor whichinfectionagreed tohowever, popular">placed onconstructelectoralsymbol ofincludingreturn toarchitectChristianprevious living ineasier toprofessor
&lt;!-- effect ofanalyticswas takenwhere thetook overbelief inAfrikaansas far aspreventedwork witha special<fieldsetChristmasRetrieved

In the back intonortheastmagazines><strong>committeegoverninggroups ofstored inestablisha generalits firsttheir ownpopulatedan objectCaribbeanallow thedistrictswisconsinlocation.; width: inhabitedSocialistJanuary 1</footer>similarlychoice ofthe same specific business The first.length; desire todeal withsince theuserAgentconceivedindex.phpas &quot;engage inrecently,few yearswere also
<head>
<edited byare knowncities inaccesskeycondemnedalso haveservices,family ofSchool ofconvertednature of languageministers</object>there is a popularsequencesadvocatedThey wereany otherlocation=enter themuch morereflectedwas namedoriginal a typicalwhen theyengineerscould notresidentswednesdaythe third productsJanuary 2what theya certainreactionsprocessorafter histhe last contained"></div>
</a></td>depend onsearch">
pieces ofcompetingReferencetennesseewhich has version=</span> <</header>gives thehistorianvalue="">padding:0view thattogether,the most was foundsubset ofattack onchildren,points ofpersonal position:allegedlyClevelandwas laterand afterare givenwas stillscrollingdesign ofmakes themuch lessAmericans.

After , but theMuseum oflouisiana(from theminnesotaparticlesa processDominicanvolume ofreturningdefensive00px|righmade frommouseover" style="states of(which iscontinuesFranciscobuilding without awith somewho woulda form ofa part ofbefore itknown as  Serviceslocation and oftenmeasuringand it ispaperbackvalues of
<title>= window.determineer&quot; played byand early</center>from thisthe threepower andof &quot;innerHTML<a href="y:inline;Church ofthe eventvery highofficial -height: content="/cgi-bin/to createafrikaansesperantofrançaislatviešulietuviųČeštinačeštinaไทย日本語简体字繁體字한국어为什么计算机笔记本討論區服务器互联网房地产俱乐部出版社排行榜部落格进一步支付宝验证码委员会数据库消费者办公室讨论区深圳市播放器北京市大学生越来越管理员信息网serviciosartículoargentinabarcelonacualquierpublicadoproductospolíticarespuestawikipediasiguientebúsquedacomunidadseguridadprincipalpreguntascontenidorespondervenezuelaproblemasdiciembrerelaciónnoviembresimilaresproyectosprogramasinstitutoactividadencuentraeconomíaimágenescontactardescargarnecesarioatenciónteléfonocomisióncancionescapacidadencontraranálisisfavoritostérminosprovinciaetiquetaselementosfuncionesresultadocarácterpropiedadprincipionecesidadmunicipalcreacióndescargaspresenciacomercialopinionesejercicioeditorialsalamancagonzálezdocumentopelícularecientesgeneralestarragonaprácticanovedadespropuestapacientestécnicasobjetivoscontactosमेंलिएहैंगयासाथएवंरहेकोईकुछरहाबादकहासभीहुएरहीमैंदिनबातdiplodocsसमयरूपनामपताफिरऔसततरहलोगहुआबारदेशहुईखेलयदिकामवेबतीनबीचमौतसाललेखजॉबमददतथानहीशहरअलगकभीनगरपासरातकिएउसेगयीहूँआगेटीमखोजकारअभीगयेतुमवोटदेंअगरऐसेमेललगाहालऊपरचारऐसादेरजिसदिलबंदबनाहूंलाखजीतबटनमिलइसेआनेनयाकुललॉगभागरेलजगहरामलगेपेजहाथइसीसहीकलाठीकहाँदूरतहतसातयादआयापाककौनशामदेखयहीरायखुदलगीcategoriesexperience</title>
Copyright javascriptconditionseverything<p class="technologybackground<a class="management&copy; 201javaScriptcharactersbreadcrumbthemselveshorizontalgovernmentCaliforniaactivitiesdiscoveredNavigationtransitionconnectionnavigationappearance</title><mcheckbox" techniquesprotectionapparentlyas well asunt', 'UA-resolutionoperationstelevisiontranslatedWashingtonnavigator. = window.impression&lt;br&gt;literaturepopulationbgcolor="#especially content="productionnewsletterpropertiesdefinitionleadershipTechnologyParliamentcomparisonul class=".indexOf("conclusiondiscussioncomponentsbiologicalRevolution_containerunderstoodnoscript><permissioneach otheratmosphere onfocus="<form id="processingthis.valuegenerationConferencesubsequentwell-knownvariationsreputationphenomenondisciplinelogo.png" (document,boundariesexpressionsettlementBackgroundout of theenterprise("https:" unescape("password" democratic<a href="/wrapper">
membershiplinguisticpx;paddingphilosophyassistanceuniversityfacilitiesrecognizedpreferenceif (typeofmaintainedvocabularyhypothesis.submit();&amp;nbsp;annotationbehind theFoundationpublisher"assumptionintroducedcorruptionscientistsexplicitlyinstead ofdimensions onClick="considereddepartmentoccupationsoon afterinvestmentpronouncedidentifiedexperimentManagementgeographic" height="link rel=".replace(/depressionconferencepunishmenteliminatedresistanceadaptationoppositionwell knownsupplementdeterminedh1 class="0px;marginmechanicalstatisticscelebratedGovernment

During tdevelopersartificialequivalentoriginatedCommissionattachment<span id="there wereNederlandsbeyond theregisteredjournalistfrequentlyall of thelang="en" </style>
absolute; supportingextremely mainstream</strong> popularityemployment</table>
 colspan="</form>
  conversionabout the </p></div>integrated" lang="enPortuguesesubstituteindividualimpossiblemultimediaalmost allpx solid #apart fromsubject toin Englishcriticizedexcept forguidelinesoriginallyremarkablethe secondh2 class="<a title="(includingparametersprohibited= "http://dictionaryperceptionrevolutionfoundationpx;height:successfulsupportersmillenniumhis fatherthe &quot;no-repeat;commercialindustrialencouragedamount of unofficialefficiencyReferencescoordinatedisclaimerexpeditiondevelopingcalculatedsimplifiedlegitimatesubstring(0" class="completelyillustratefive yearsinstrumentPublishing1" class="psychologyconfidencenumber of absence offocused onjoined thestructurespreviously></iframe>once againbut ratherimmigrantsof course,a group ofLiteratureUnlike the</a>&nbsp;
function it was theConventionautomobileProtestantaggressiveafter the Similarly," /></div>collection
functionvisibilitythe use ofvolunteersattractionunder the threatened*<![CDATA[importancein generalthe latter</form>
</.indexOf('i = 0; i <differencedevoted totraditionssearch forultimatelytournamentattributesso-called }
</style>evaluationemphasizedaccessible</section>successionalong withMeanwhile,industries</a><br />has becomeaspects ofTelevisionsufficientbasketballboth sidescontinuingan article<img alt="adventureshis mothermanchesterprinciplesparticularcommentaryeffects ofdecided to"><strong>publishersJournal ofdifficultyfacilitateacceptablestyle.css"	function innovation>Copyrightsituationswould havebusinessesDictionarystatementsoften usedpersistentin Januarycomprising</title>
	diplomaticcontainingperformingextensionsmay not beconcept of onclick="It is alsofinancial making theLuxembourgadditionalare calledengaged in"script");but it waselectroniconsubmit="
<!-- End electricalofficiallysuggestiontop of theunlike theAustralianOriginallyreferences
</head>
recognisedinitializelimited toAlexandriaretirementAdventuresfour years

&lt;!-- increasingdecorationh3 class="origins ofobligationregulationclassified(function(advantagesbeing the historians<base hrefrepeatedlywilling tocomparabledesignatednominationfunctionalinside therevelationend of thes for the authorizedrefused totake placeautonomouscompromisepolitical restauranttwo of theFebruary 2quality ofswfobject.understandnearly allwritten byinterviews" width="1withdrawalfloat:leftis usuallycandidatesnewspapersmysteriousDepartmentbest knownparliamentsuppressedconvenientremembereddifferent systematichas led topropagandacontrolledinfluencesceremonialproclaimedProtectionli class="Scientificclass="no-trademarksmore than widespreadLiberationtook placeday of theas long asimprisonedAdditional
<head>
<mLaboratoryNovember 2exceptionsIndustrialvariety offloat: lefDuring theassessmenthave been deals withStatisticsoccurrence/ul></div>clearfix">the publicmany yearswhich wereover time,synonymouscontent">
presumablyhis familyuserAgent.unexpectedincluding challengeda minorityundefined"belongs totaken fromin Octoberposition: said to bereligious Federation rowspan="only a fewmeant thatled to the-->
<div <fieldset>Archbishop class="nobeing usedapproachesprivilegesnoscript>
results inmay be theEaster eggmechanismsreasonablePopulationCollectionselected">noscript>
/index.phparrival of-jssdk'));managed toincompletecasualtiescompletionChristiansSeptember arithmeticproceduresmight haveProductionit appearsPhilosophyfriendshipleading togiving thetoward theguaranteeddocumentedcolor:#000video gamecommissionreflectingchange theassociatedsans-serifonkeypress; padding:He was theunderlyingtypically , and the srcElementsuccessivesince the should be networkingaccountinguse of thelower thanshows that</span>
		complaintscontinuousquantitiesastronomerhe did notdue to itsapplied toan averageefforts tothe futureattempt toTherefore,capabilityRepublicanwas formedElectronickilometerschallengespublishingthe formerindigenousdirectionssubsidiaryconspiracydetails ofand in theaffordablesubstancesreason forconventionitemtype="absolutelysupposedlyremained aattractivetravellingseparatelyfocuses onelementaryapplicablefound thatstylesheetmanuscriptstands for no-repeat(sometimesCommercialin Americaundertakenquarter ofan examplepersonallyindex.php?</button>
percentagebest-knowncreating a" dir="ltrLieutenant
<div id="they wouldability ofmade up ofnoted thatclear thatargue thatto anotherchildren'spurpose offormulatedbased uponthe regionsubject ofpassengerspossession.

In the Before theafterwardscurrently across thescientificcommunity.capitalismin Germanyright-wingthe systemSociety ofpoliticiandirection:went on toremoval of New York apartmentsindicationduring theunless thehistoricalhad been adefinitiveingredientattendanceCenter forprominencereadyStatestrategiesbut in theas part ofconstituteclaim thatlaboratorycompatiblefailure of, such as began withusing the to providefeature offrom which/" class="geologicalseveral ofdeliberateimportant holds thating&quot; valign=topthe Germanoutside ofnegotiatedhis careerseparationid="searchwas calledthe fourthrecreationother thanpreventionwhile the education,connectingaccuratelywere builtwas killedagreementsmuch more Due to thewidth: 100some otherKingdom ofthe entirefamous forto connectobjectivesthe Frenchpeople andfeatured">is said tostructuralreferendummost oftena separate->
<div id Official worldwide.aria-labelthe planetand it wasd" value="looking atbeneficialare in themonitoringreportedlythe modernworking onallowed towhere the innovative</a></div>soundtracksearchFormtend to beinput id="opening ofrestrictedadopted byaddressingtheologianmethods ofvariant ofChristian very largeautomotiveby far therange frompursuit offollow thebrought toin Englandagree thataccused ofcomes frompreventingdiv style=his or hertremendousfreedom ofconcerning0 1em 1em;Basketball/style.cssan earliereven after/" title=".com/indextaking thepittsburghcontent">
<script>(fturned outhaving the</span>
 occasionalbecause itstarted tophysically></div>
  created byCurrently, bgcolor="tabindex="disastrousAnalytics also has a><div id="</style>
<called forsinger and.src = "//violationsthis pointconstantlyis locatedrecordingsd from thenederlandsportuguêsעבריתفارسیdesarrollocomentarioeducaciónseptiembreregistradodirecciónubicaciónpublicidadrespuestasresultadosimportantereservadosartículosdiferentessiguientesrepúblicasituaciónministerioprivacidaddirectorioformaciónpoblaciónpresidentecontenidosaccesoriostechnoratipersonalescategoríaespecialesdisponibleactualidadreferenciavalladolidbibliotecarelacionescalendariopolíticasanterioresdocumentosnaturalezamaterialesdiferenciaeconómicatransporterodríguezparticiparencuentrandiscusiónestructurafundaciónfrecuentespermanentetotalmenteможнобудетможетвремятакжечтобыболееоченьэтогокогдапослевсегосайтечерезмогутсайтажизнимеждубудутПоискздесьвидеосвязинужносвоейлюдейпорномногодетейсвоихправатакойместоимеетжизньоднойлучшепередчастичастьработновыхправособойпотомменеечисленовыеуслугоколоназадтакоетогдапочтиПослетакиеновыйстоиттакихсразуСанктфорумКогдакнигислованашейнайтисвоимсвязьлюбойчастосредиКромеФорумрынкесталипоисктысячмесяццентртрудасамыхрынкаНовыйчасовместафильммартастранместетекстнашихминутимениимеютномергородсамомэтомуконцесвоемкакойАрхивمنتدىإرسالرسالةالعامكتبهابرامجاليومالصورجديدةالعضوإضافةالقسمالعابتحميلملفاتملتقىتعديلالشعرأخبارتطويرعليكمإرفاقطلباتاللغةترتيبالناسالشيخمنتديالعربالقصصافلامعليهاتحديثاللهمالعملمكتبةيمكنكالطفلفيديوإدارةتاريخالصحةتسجيلالوقتعندمامدينةتصميمأرشيفالذينعربيةبوابةألعابالسفرمشاكلتعالىالأولالسنةجامعةالصحفالدينكلماتالخاصالملفأعضاءكتابةالخيررسائلالقلبالأدبمقاطعمراسلمنطقةالكتبالرجلاشتركالقدميعطيكsByTagName(.jpg" alt="1px solid #.gif" alt="transparentinformationapplication" onclick="establishedadvertising.png" alt="environmentperformanceappropriate&amp;mdash;immediately</strong></rather thantemperaturedevelopmentcompetitionplaceholdervisibility:copyright">0" height="even thoughreplacementdestinationCorporation<ul class="AssociationindividualsperspectivesetTimeout(url(http://mathematicsmargin-top:eventually description) no-repeatcollections.JPG|thumb|participate/head><bodyfloat:left;<li class="hundreds of

However, compositionclear:both;cooperationwithin the label for="border-top:New Zealandrecommendedphotographyinteresting&lt;sup&gt;controversyNetherlandsalternativemaxlength="switzerlandDevelopmentessentially

Although </textarea>thunderbirdrepresented&amp;ndash;speculationcommunitieslegislationelectronics
	<div id="illustratedengineeringterritoriesauthoritiesdistributed6" height="sans-serif;capable of disappearedinteractivelooking forit would beAfghanistanwas createdMath.floor(surroundingcan also beobservationmaintenanceencountered<h2 class="more recentit has beeninvasion of).getTime()fundamentalDespite the"><div id="inspirationexaminationpreparationexplanation<input id="</a></span>versions ofinstrumentsbefore the  = 'http://Descriptionrelatively .substring(each of theexperimentsinfluentialintegrationmany peopledue to the combinationdo not haveMiddle East<noscript><copyright" perhaps theinstitutionin Decemberarrangementmost famouspersonalitycreation oflimitationsexclusivelysovereignty-content">
<td class="undergroundparallel todoctrine ofoccupied byterminologyRenaissancea number ofsupport forexplorationrecognitionpredecessor<img src="/<h1 class="publicationmay also bespecialized</fieldset>progressivemillions ofstates thatenforcementaround the one another.parentNodeagricultureAlternativeresearcherstowards theMost of themany other (especially<td width=";width:100%independent<h3 class=" onchange=").addClass(interactionOne of the daughter ofaccessoriesbranches of
<div id="the largestdeclarationregulationsInformationtranslationdocumentaryin order to">
<head>
<" height="1across the orientation);</script>implementedcan be seenthere was ademonstratecontainer">connectionsthe Britishwas written!important;px; margin-followed byability to complicatedduring the immigrationalso called<h4 class="distinctionreplaced bygovernmentslocation ofin Novemberwhether the</p>
</div>acquisitioncalled the persecutiondesignation{font-size:appeared ininvestigateexperiencedmost likelywidely useddiscussionspresence of (document.extensivelyIt has beenit does notcontrary toinhabitantsimprovementscholarshipconsumptioninstructionfor exampleone or morepx; paddingthe currenta series ofare usuallyrole in thepreviously derivativesevidence ofexperiencescolorschemestated thatcertificate</a></div>
 selected="high schoolresponse tocomfortableadoption ofthree yearsthe countryin Februaryso that thepeople who provided by<param nameaffected byin terms ofappointmentISO-8859-1"was born inhistorical regarded asmeasurementis based on and other : function(significantcelebrationtransmitted/js/jquery.is known astheoretical tabindex="it could be<noscript>
having been
<head>
< &quot;The compilationhe had beenproduced byphilosopherconstructedintended toamong othercompared toto say thatEngineeringa differentreferred todifferencesbelief thatphotographsidentifyingHistory of Republic ofnecessarilyprobabilitytechnicallyleaving thespectacularfraction ofelectricityhead of therestaurantspartnershipemphasis onmost recentshare with saying thatfilled withdesigned toit is often"></iframe>as follows:merged withthrough thecommercial pointed outopportunityview of therequirementdivision ofprogramminghe receivedsetInterval"></span></in New Yorkadditional compression

<div id="incorporate;</script><attachEventbecame the " target="_carried outSome of thescience andthe time ofContainer">maintainingChristopherMuch of thewritings of" height="2size of theversion of mixture of between theExamples ofeducationalcompetitive onsubmit="director ofdistinctive/DTD XHTML relating totendency toprovince ofwhich woulddespite thescientific legislature.innerHTML allegationsAgriculturewas used inapproach tointelligentyears later,sans-serifdeterminingPerformanceappearances, which is foundationsabbreviatedhigher thans from the individual composed ofsupposed toclaims thatattributionfont-size:1elements ofHistorical his brotherat the timeanniversarygoverned byrelated to ultimately innovationsit is stillcan only bedefinitionstoGMTStringA number ofimg class="Eventually,was changedoccurred inneighboringdistinguishwhen he wasintroducingterrestrialMany of theargues thatan Americanconquest ofwidespread were killedscreen and In order toexpected todescendantsare locatedlegislativegenerations backgroundmost peopleyears afterthere is nothe highestfrequently they do notargued thatshowed thatpredominanttheologicalby the timeconsideringshort-lived</span></a>can be usedvery littleone of the had alreadyinterpretedcommunicatefeatures ofgovernment,</noscript>entered the" height="3Independentpopulationslarge-scale. Although used in thedestructionpossibilitystarting intwo or moreexpressionssubordinatelarger thanhistory and</option>
Continentaleliminatingwill not bepractice ofin front ofsite of theensure thatto create amississippipotentiallyoutstandingbetter thanwhat is nowsituated inmeta name="TraditionalsuggestionsTranslationthe form ofatmosphericideologicalenterprisescalculatingeast of theremnants ofpluginspage/index.php?remained intransformedHe was alsowas alreadystatisticalin favor ofMinistry ofmovement offormulationis required<link rel="This is the <a href="/popularizedinvolved inare used toand severalmade by theseems to belikely thatPalestiniannamed afterit had beenmost commonto refer tobut this isconsecutivetemporarilyIn general,conventionstakes placesubdivisionterritorialoperationalpermanentlywas largelyoutbreak ofin the pastfollowing a xmlns:og="><a class="class="textConversion may be usedmanufactureafter beingclearfix">
question ofwas electedto become abecause of some peopleinspired bysuccessful a time whenmore commonamongst thean officialwidth:100%;technology,was adoptedto keep thesettlementslive birthsindex.html"Connecticutassigned to&amp;times;account foralign=rightthe companyalways beenreturned toinvolvementBecause thethis period" name="q" confined toa result ofvalue="" />is actuallyEnvironment
</head>
Conversely,>
<div id="0" width="1is probablyhave becomecontrollingthe problemcitizens ofpoliticiansreached theas early as:none; over<table cellvalidity ofdirectly toonmousedownwhere it iswhen it wasmembers of relation toaccommodatealong with In the latethe Englishdelicious">this is notthe presentif they areand finallya matter of
	</div>

</script>faster thanmajority ofafter whichcomparativeto maintainimprove theawarded theer" class="frameborderrestorationin the sameanalysis oftheir firstDuring the continentalsequence offunction(){font-size: work on the</script>
<begins withjavascript:constituentwas foundedequilibriumassume thatis given byneeds to becoordinatesthe variousare part ofonly in thesections ofis a commontheories ofdiscoveriesassociationedge of thestrength ofposition inpresent-dayuniversallyto form thebut insteadcorporationattached tois commonlyreasons for &quot;the can be madewas able towhich meansbut did notonMouseOveras possibleoperated bycoming fromthe primaryaddition offor severaltransferreda period ofare able tohowever, itshould havemuch larger
	</script>adopted theproperty ofdirected byeffectivelywas broughtchildren ofProgramminglonger thanmanuscriptswar againstby means ofand most ofsimilar to proprietaryoriginatingprestigiousgrammaticalexperience.to make theIt was alsois found incompetitorsin the U.S.replace thebrought thecalculationfall of thethe generalpracticallyin honor ofreleased inresidentialand some ofking of thereaction to1st Earl ofculture andprincipally</title>
  they can beback to thesome of hisexposure toare similarform of theaddFavoritecitizenshippart in thepeople within practiceto continue&amp;minus;approved by the first allowed theand for thefunctioningplaying thesolution toheight="0" in his bookmore than afollows thecreated thepresence in&nbsp;</td>nationalistthe idea ofa characterwere forced class="btndays of thefeatured inshowing theinterest inin place ofturn of thethe head ofLord of thepoliticallyhas its ownEducationalapproval ofsome of theeach other,behavior ofand becauseand anotherappeared onrecorded inblack&quot;may includethe world'scan lead torefers to aborder="0" government winning theresulted in while the Washington,the subjectcity in the></div>
		reflect theto completebecame moreradioactiverejected bywithout anyhis father,which couldcopy of theto indicatea politicalaccounts ofconstitutesworked wither</a></li>of his lifeaccompaniedclientWidthprevent theLegislativedifferentlytogether inhas severalfor anothertext of thefounded thee with the is used forchanged theusually theplace wherewhereas the> <a href=""><a href="themselves,although hethat can betraditionalrole of theas a resultremoveChilddesigned bywest of theSome peopleproduction,side of thenewslettersused by thedown to theaccepted bylive in theattempts tooutside thefrequenciesHowever, inprogrammersat least inapproximatealthough itwas part ofand variousGovernor ofthe articleturned into><a href="/the economyis the mostmost widelywould laterand perhapsrise to theoccurs whenunder whichconditions.the westerntheory thatis producedthe city ofin which heseen in thethe centralbuilding ofmany of hisarea of theis the onlymost of themany of thethe WesternThere is noextended toStatisticalcolspan=2 |short storypossible totopologicalcritical ofreported toa Christiandecision tois equal toproblems ofThis can bemerchandisefor most ofno evidenceeditions ofelements in&quot;. Thecom/images/which makesthe processremains theliterature,is a memberthe popularthe ancientproblems intime of thedefeated bybody of thea few yearsmuch of thethe work ofCalifornia,served as agovernment.concepts ofmovement in		<div id="it" value="language ofas they areproduced inis that theexplain thediv></div>
However thelead to the	<a href="/was grantedpeople havecontinuallywas seen asand relatedthe role ofproposed byof the besteach other.Constantinepeople fromdialects ofto revisionwas renameda source ofthe initiallaunched inprovide theto the westwhere thereand similarbetween twois also theEnglish andconditions,that it wasentitled tothemselves.quantity ofransparencythe same asto join thecountry andthis is theThis led toa statementcontrast tolastIndexOfthrough hisis designedthe term isis providedprotect theng</a></li>The currentthe site ofsubstantialexperience,in the Westthey shouldslovenčinacomentariosuniversidadcondicionesactividadesexperienciatecnologíaproducciónpuntuaciónaplicacióncontraseñacategoríasregistrarseprofesionaltratamientoregístratesecretaríaprincipalesprotecciónimportantesimportanciaposibilidadinteresantecrecimientonecesidadessuscribirseasociacióndisponiblesevaluaciónestudiantesresponsableresoluciónguadalajararegistradosoportunidadcomercialesfotografíaautoridadesingenieríatelevisióncompetenciaoperacionesestablecidosimplementeactualmentenavegaciónconformidadline-height:font-family:" : "http://applicationslink" href="specifically//<![CDATA[
Organizationdistribution0px; height:relationshipdevice-width<div class="<label for="registration</noscript>
/index.html"window.open( !important;application/independence//www.googleorganizationautocompleterequirementsconservative<form name="intellectualmargin-left:18th centuryan importantinstitutionsabbreviation<img class="organisationcivilization19th centuryarchitectureincorporated20th century-container">most notably/></a></div>notification'undefined')Furthermore,believe thatinnerHTML = prior to thedramaticallyreferring tonegotiationsheadquartersSouth AfricaunsuccessfulPennsylvaniaAs a result,<html lang="&lt;/sup&gt;dealing withphiladelphiahistorically);</script>
padding-top:experimentalgetAttributeinstructionstechnologiespart of the =function(){subscriptionl.dtd">
<htgeographicalConstitution', function(supported byagriculturalconstructionpublicationsfont-size: 1a variety of<div style="Encyclopediaiframe src="demonstratedaccomplisheduniversitiesDemographics);</script><dedicated toknowledge ofsatisfactionparticularly</div></div>English (US)appendChild(transmissions. However, intelligence" tabindex="float:right;Commonwealthranging fromin which theat least onereproductionencyclopedia;font-size:1jurisdictionat that time"><a class="In addition,description+conversationcontact withis generallyr" content="representing&lt;math&gt;presentationoccasionally<img width="navigation">compensationchampionshipmedia="all" violation ofreference toreturn true;Strict//EN" transactionsinterventionverificationInformation difficultiesChampionshipcapabilities<![endif]-->}
</script>
Christianityfor example,Professionalrestrictionssuggest thatwas released(such as theremoveClass(unemploymentthe Americanstructure of/index.html published inspan class=""><a href="/introductionbelonging toclaimed thatconsequences<meta name="Guide to theoverwhelmingagainst the concentrated,
.nontouch observations</a>
</div>
f (document.border: 1px {font-size:1treatment of0" height="1modificationIndependencedivided intogreater thanachievementsestablishingJavaScript" neverthelesssignificanceBroadcasting>&nbsp;</td>container">
such as the influence ofa particularsrc='http://navigation" half of the substantial &nbsp;</div>advantage ofdiscovery offundamental metropolitanthe opposite" xml:lang="deliberatelyalign=centerevolution ofpreservationimprovementsbeginning inJesus ChristPublicationsdisagreementtext-align:r, function()similaritiesbody></html>is currentlyalphabeticalis sometimestype="image/many of the flow:hidden;available indescribe theexistence ofall over thethe Internet	<ul class="installationneighborhoodarmed forcesreducing thecontinues toNonetheless,temperatures
		<a href="close to theexamples of is about the(see below)." id="searchprofessionalis availablethe official		</script>

		<div id="accelerationthrough the Hall of Famedescriptionstranslationsinterference type='text/recent yearsin the worldvery popular{background:traditional some of the connected toexploitationemergence ofconstitutionA History ofsignificant manufacturedexpectations><noscript><can be foundbecause the has not beenneighbouringwithout the added to the	<li class="instrumentalSoviet Unionacknowledgedwhich can bename for theattention toattempts to developmentsIn fact, the<li class="aimplicationssuitable formuch of the colonizationpresidentialcancelBubble Informationmost of the is describedrest of the more or lessin SeptemberIntelligencesrc="http://px; height: available tomanufacturerhuman rightslink href="/availabilityproportionaloutside the astronomicalhuman beingsname of the are found inare based onsmaller thana person whoexpansion ofarguing thatnow known asIn the earlyintermediatederived fromScandinavian</a></div>
consider thean estimatedthe National<div id="pagresulting incommissionedanalogous toare required/ul>
</div>
was based onand became a&nbsp;&nbsp;t" value="" was capturedno more thanrespectivelycontinue to >
<head>
<were createdmore generalinformation used for theindependent the Imperialcomponent ofto the northinclude the Constructionside of the would not befor instanceinvention ofmore complexcollectivelybackground: text-align: its originalinto accountthis processan extensivehowever, thethey are notrejected thecriticism ofduring whichprobably thethis article(function(){It should bean agreementaccidentallydiffers fromArchitecturebetter knownarrangementsinfluence onattended theidentical tosouth of thepass throughxml" title="weight:bold;creating thedisplay:nonereplaced the<img src="/ihttps://www.World War IItestimonialsfound in therequired to and that thebetween the was designedconsists of considerablypublished bythe languageConservationconsisted ofrefer to theback to the css" media="People from available onproved to besuggestions"was known asvarieties oflikely to becomprised ofsupport the hands of thecoupled withconnect and border:none;performancesbefore beinglater becamecalculationsoften calledresidents ofmeaning that><li class="evidence forexplanationsenvironments"></a></div>which allowsIntroductiondeveloped bya wide rangeon behalf ofvalign="top"principle ofat the time,</noscript>
said to havein the firstwhile othershypotheticalphilosopherspower of thecontained inperformed byinability towere writtenspan style="input name="the questionintended forrejection ofimplies thatinvented thethe standardwas probablylink betweenprofessor ofinteractionschanging theIndian Ocean class="lastworking with'http://www.years beforeThis was therecreationalentering themeasurementsan extremelyvalue of thestart of the
</script>

an effort toincrease theto the southspacing="0">sufficientlythe Europeanconverted toclearTimeoutdid not haveconsequentlyfor the nextextension ofeconomic andalthough theare producedand with theinsufficientgiven by thestating thatexpenditures</span></a>
thought thaton the basiscellpadding=image of thereturning toinformation,separated byassassinateds" content="authority ofnorthwestern</div>
<div "></div>
  consultationcommunity ofthe nationalit should beparticipants align="leftthe greatestselection ofsupernaturaldependent onis mentionedallowing thewas inventedaccompanyinghis personalavailable atstudy of theon the otherexecution ofHuman Rightsterms of theassociationsresearch andsucceeded bydefeated theand from thebut they arecommander ofstate of theyears of agethe study of<ul class="splace in thewhere he was<li class="fthere are nowhich becamehe publishedexpressed into which thecommissionerfont-weight:territory ofextensions">Roman Empireequal to theIn contrast,however, andis typicallyand his wife(also called><ul class="effectively evolved intoseem to havewhich is thethere was noan excellentall of thesedescribed byIn practice,broadcastingcharged withreflected insubjected tomilitary andto the pointeconomicallysetTargetingare actuallyvictory over();</script>continuouslyrequired forevolutionaryan effectivenorth of the, which was front of theor otherwisesome form ofhad not beengenerated byinformation.permitted toincludes thedevelopment,entered intothe previousconsistentlyare known asthe field ofthis type ofgiven to thethe title ofcontains theinstances ofin the northdue to theirare designedcorporationswas that theone of thesemore popularsucceeded insupport fromin differentdominated bydesigned forownership ofand possiblystandardizedresponseTextwas intendedreceived theassumed thatareas of theprimarily inthe basis ofin the senseaccounts fordestroyed byat least twowas declaredcould not beSecretary ofappear to bemargin-top:1/^\s+|\s+$/ge){throw e};the start oftwo separatelanguage andwho had beenoperation ofdeath of thereal numbers	<link rel="provided thethe story ofcompetitionsenglish (UK)english (US)МонголСрпскисрпскисрпскоلعربية正體中文简体中文繁体中文有限公司人民政府阿里巴巴社会主义操作系统政策法规informaciónherramientaselectrónicodescripciónclasificadosconocimientopublicaciónrelacionadasinformáticarelacionadosdepartamentotrabajadoresdirectamenteayuntamientomercadoLibrecontáctenoshabitacionescumplimientorestaurantesdisposiciónconsecuenciaelectrónicaaplicacionesdesconectadoinstalaciónrealizaciónutilizaciónenciclopediaenfermedadesinstrumentosexperienciasinstituciónparticularessubcategoriaтолькоРоссииработыбольшепростоможетедругихслучаесейчасвсегдаРоссияМоскведругиегородавопросданныхдолжныименноМосквырублейМосквастраныничегоработедолженуслугитеперьОднакопотомуработуапрелявообщеодногосвоегостатьидругойфорумехорошопротивссылкакаждыйвластигруппывместеработасказалпервыйделатьденьгипериодбизнесосновемоменткупитьдолжнарамкахначалоРаботаТолькосовсемвторойначаласписокслужбысистемпечатиновогопомощисайтовпочемупомощьдолжноссылкибыстроданныемногиепроектСейчасмоделитакогоонлайнгородеверсиястранефильмыуровняразныхискатьнеделюянваряменьшемногихданнойзначитнельзяфорумаТеперьмесяцазащитыЛучшиеनहींकरनेअपनेकियाकरेंअन्यक्यागाइडबारेकिसीदियापहलेसिंहभारतअपनीवालेसेवाकरतेमेरेहोनेसकतेबहुतसाइटहोगाजानेमिनटकरताकरनाउनकेयहाँसबसेभाषाआपकेलियेशुरूइसकेघंटेमेरीसकतामेरालेकरअधिकअपनासमाजमुझेकारणहोताकड़ीयहांहोटलशब्दलियाजीवनजाताकैसेआपकावालीदेनेपूरीपानीउसकेहोगीबैठकआपकीवर्षगांवआपकोजिलाजानासहमतहमेंउनकीयाहूदर्जसूचीपसंदसवालहोनाहोतीजैसेवापसजनतानेताजारीघायलजिलेनीचेजांचपत्रगूगलजातेबाहरआपनेवाहनइसकासुबहरहनेइससेसहितबड़ेघटनातलाशपांचश्रीबड़ीहोतेसाईटशायदसकतीजातीवालाहजारपटनारखनेसड़कमिलाउसकीकेवललगताखानाअर्थजहांदेखापहलीनियमबिनाबैंककहींकहनादेताहमलेकाफीजबकितुरतमांगवहींरोज़मिलीआरोपसेनायादवलेनेखाताकरीबउनकाजवाबपूराबड़ासौदाशेयरकियेकहांअकसरबनाएवहांस्थलमिलेलेखकविषयक्रंसमूहथानाتستطيعمشاركةبواسطةالصفحةمواضيعالخاصةالمزيدالعامةالكاتبالردودبرنامجالدولةالعالمالموقعالعربيالسريعالجوالالذهابالحياةالحقوقالكريمالعراقمحفوظةالثانيمشاهدةالمرأةالقرآنالشبابالحوارالجديدالأسرةالعلوممجموعةالرحمنالنقاطفلسطينالكويتالدنيابركاتهالرياضتحياتيبتوقيتالأولىالبريدالكلامالرابطالشخصيسياراتالثالثالصلاةالحديثالزوارالخليجالجميعالعامهالجمالالساعةمشاهدهالرئيسالدخولالفنيةالكتابالدوريالدروساستغرقتصاميمالبناتالعظيمentertainmentunderstanding = function().jpg" width="configuration.png" width="<body class="Math.random()contemporary United Statescircumstances.appendChild(organizations<span class=""><img src="/distinguishedthousands of communicationclear"></div>investigationfavicon.ico" margin-right:based on the Massachusettstable border=internationalalso known aspronunciationbackground:#fpadding-left:For example, miscellaneous&lt;/math&gt;psychologicalin particularearch" type="form method="as opposed toSupreme Courtoccasionally Additionally,North Americapx;backgroundopportunitiesEntertainment.toLowerCase(manufacturingprofessional combined withFor instance,consisting of" maxlength="return false;consciousnessMediterraneanextraordinaryassassinationsubsequently button type="the number ofthe original comprehensiverefers to the</ul>
</div>
philosophicallocation.hrefwas publishedSan Francisco(function(){
<div id="mainsophisticatedmathematical /head>
<bodysuggests thatdocumentationconcentrationrelationshipsmay have been(for example,This article in some casesparts of the definition ofGreat Britain cellpadding=equivalent toplaceholder="; font-size: justificationbelieved thatsuffered fromattempted to leader of thecript" src="/(function() {are available
	<link rel=" src='http://interested inconventional " alt="" /></are generallyhas also beenmost popular correspondingcredited withtyle="border:</a></span></.gif" width="<iframe src="table class="inline-block;according to together withapproximatelyparliamentarymore and moredisplay:none;traditionallypredominantly&nbsp;|&nbsp;&nbsp;</span> cellspacing=<input name="or" content="controversialproperty="og:/x-shockwave-demonstrationsurrounded byNevertheless,was the firstconsiderable Although the collaborationshould not beproportion of<span style="known as the shortly afterfor instance,described as /head>
<body starting withincreasingly the fact thatdiscussion ofmiddle of thean individualdifficult to point of viewhomosexualityacceptance of</span></div>manufacturersorigin of thecommonly usedimportance ofdenominationsbackground: #length of thedeterminationa significant" border="0">revolutionaryprinciples ofis consideredwas developedIndo-Europeanvulnerable toproponents ofare sometimescloser to theNew York City name="searchattributed tocourse of themathematicianby the end ofat the end of" border="0" technological.removeClass(branch of theevidence that![endif]-->
Institute of into a singlerespectively.and thereforeproperties ofis located insome of whichThere is alsocontinued to appearance of &amp;ndash; describes theconsiderationauthor of theindependentlyequipped withdoes not have</a><a href="confused with<link href="/at the age ofappear in theThese includeregardless ofcould be used style=&quot;several timesrepresent thebody>
</html>thought to bepopulation ofpossibilitiespercentage ofaccess to thean attempt toproduction ofjquery/jquerytwo differentbelong to theestablishmentreplacing thedescription" determine theavailable forAccording to wide range of	<div class="more commonlyorganisationsfunctionalitywas completed &amp;mdash; participationthe characteran additionalappears to befact that thean example ofsignificantlyonmouseover="because they async = true;problems withseems to havethe result of src="http://familiar withpossession offunction () {took place inand sometimessubstantially<span></span>is often usedin an attemptgreat deal ofEnvironmentalsuccessfully virtually all20th century,professionalsnecessary to determined bycompatibilitybecause it isDictionary ofmodificationsThe followingmay refer to:Consequently,Internationalalthough somethat would beworld's firstclassified asbottom of the(particularlyalign="left" most commonlybasis for thefoundation ofcontributionspopularity ofcenter of theto reduce thejurisdictionsapproximation onmouseout="New Testamentcollection of</span></a></in the Unitedfilm director-strict.dtd">has been usedreturn to thealthough thischange in theseveral otherbut there areunprecedentedis similar toespecially inweight: bold;is called thecomputationalindicate thatrestricted to	<meta name="are typicallyconflict withHowever, the An example ofcompared withquantities ofrather than aconstellationnecessary forreported thatspecificationpolitical and&nbsp;&nbsp;<references tothe same yearGovernment ofgeneration ofhave not beenseveral yearscommitment to		<ul class="visualization19th century,practitionersthat he wouldand continuedoccupation ofis defined ascentre of thethe amount of><div style="equivalent ofdifferentiatebrought aboutmargin-left: automaticallythought of asSome of these
<div class="input class="replaced withis one of theeducation andinfluenced byreputation as
<meta name="accommodation</div>
</div>large part ofInstitute forthe so-called against the In this case,was appointedclaimed to beHowever, thisDepartment ofthe remainingeffect on theparticularly deal with the
<div style="almost alwaysare currentlyexpression ofphilosophy offor more thancivilizationson the islandselectedIndexcan result in" value="" />the structure /></a></div>Many of thesecaused by theof the Unitedspan class="mcan be tracedis related tobecame one ofis frequentlyliving in thetheoreticallyFollowing theRevolutionarygovernment inis determinedthe politicalintroduced insufficient todescription">short storiesseparation ofas to whetherknown for itswas initiallydisplay:blockis an examplethe principalconsists of arecognized as/body></html>a substantialreconstructedhead of stateresistance toundergraduateThere are twogravitationalare describedintentionallyserved as theclass="headeropposition tofundamentallydominated theand the otheralliance withwas forced torespectively,and politicalin support ofpeople in the20th century.and publishedloadChartbeatto understandmember statesenvironmentalfirst half ofcountries andarchitecturalbe consideredcharacterizedclearIntervalauthoritativeFederation ofwas succeededand there area consequencethe Presidentalso includedfree softwaresuccession ofdeveloped thewas destroyedaway from the;
</script>
<although theyfollowed by amore powerfulresulted in aUniversity ofHowever, manythe presidentHowever, someis thought tountil the endwas announcedare importantalso includes><input type=the center of DO NOT ALTERused to referthemes/?sort=that had beenthe basis forhas developedin the summercomparativelydescribed thesuch as thosethe resultingis impossiblevarious otherSouth Africanhave the sameeffectivenessin which case; text-align:structure and; background:regarding thesupported theis also knownstyle="marginincluding thebahasa Melayunorsk bokmålnorsk nynorskslovenščinainternacionalcalificacióncomunicaciónconstrucción"><div class="disambiguationDomainName', 'administrationsimultaneouslytransportationInternational margin-bottom:responsibility<![endif]-->
</><meta name="implementationinfrastructurerepresentationborder-bottom:</head>
<body>=http%3A%2F%2F<form method="method="post" /favicon.ico" });
</script>
.setAttribute(Administration= new Array();<![endif]-->
display:block;Unfortunately,">&nbsp;</div>/favicon.ico">='stylesheet' identification, for example,<li><a href="/an alternativeas a result ofpt"></script>
type="submit" 
(function() {recommendationform action="/transformationreconstruction.style.display According to hidden" name="along with thedocument.body.approximately Communicationspost" action="meaning &quot;--<![endif]-->Prime Ministercharacteristic</a> <a class=the history of onmouseover="the governmenthref="https://was originallywas introducedclassificationrepresentativeare considered<![endif]-->

depends on theUniversity of in contrast to placeholder="in the case ofinternational constitutionalstyle="border-: function() {Because of the-strict.dtd">
<table class="accompanied byaccount of the<script src="/nature of the the people in in addition tos); js.id = id" width="100%"regarding the Roman Catholican independentfollowing the .gif" width="1the following discriminationarchaeologicalprime minister.js"></script>combination of marginwidth="createElement(w.attachEvent(</a></td></tr>src="https://aIn particular, align="left" Czech RepublicUnited Kingdomcorrespondenceconcluded that.html" title="(function () {comes from theapplication of<span class="sbelieved to beement('script'</a>
</li>
<livery different><span class="option value="(also known as	<li><a href="><input name="separated fromreferred to as valign="top">founder of theattempting to carbon dioxide

<div class="class="search-/body>
</html>opportunity tocommunications</head>
<body style="width:Tiếng Việtchanges in theborder-color:#0" border="0" </span></div><was discovered" type="text" );
</script>

Department of ecclesiasticalthere has beenresulting from</body></html>has never beenthe first timein response toautomatically </div>

<div iwas consideredpercent of the" /></a></div>collection of descended fromsection of theaccept-charsetto be confusedmember of the padding-right:translation ofinterpretation href='http://whether or notThere are alsothere are manya small numberother parts ofimpossible to  class="buttonlocated in the. However, theand eventuallyAt the end of because of itsrepresents the<form action=" method="post"it is possiblemore likely toan increase inhave also beencorresponds toannounced thatalign="right">many countriesfor many yearsearliest knownbecause it waspt"></script>
 valign="top" inhabitants offollowing year
<div class="million peoplecontroversial concerning theargue that thegovernment anda reference totransferred todescribing the style="color:although therebest known forsubmit" name="multiplicationmore than one recognition ofCouncil of theedition of the  <meta name="Entertainment away from the ;margin-right:at the time ofinvestigationsconnected withand many otheralthough it isbeginning with <span class="descendants of<span class="i align="right"</head>
<body aspects of thehas since beenEuropean Unionreminiscent ofmore difficultVice Presidentcomposition ofpassed throughmore importantfont-size:11pxexplanation ofthe concept ofwritten in the	<span class="is one of the resemblance toon the groundswhich containsincluding the defined by thepublication ofmeans that theoutside of thesupport of the<input class="<span class="t(Math.random()most prominentdescription ofConstantinoplewere published<div class="seappears in the1" height="1" most importantwhich includeswhich had beendestruction ofthe population
	<div class="possibility ofsometimes usedappear to havesuccess of theintended to bepresent in thestyle="clear:b
</script>
<was founded ininterview with_id" content="capital of the
<link rel="srelease of thepoint out thatxMLHttpRequestand subsequentsecond largestvery importantspecificationssurface of theapplied to theforeign policy_setDomainNameestablished inis believed toIn addition tomeaning of theis named afterto protect theis representedDeclaration ofmore efficientClassificationother forms ofhe returned to<span class="cperformance of(function() {
if and only ifregions of theleading to therelations withUnited Nationsstyle="height:other than theype" content="Association of
</head>
<bodylocated on theis referred to(including theconcentrationsthe individualamong the mostthan any other/>
<link rel=" return false;the purpose ofthe ability to;color:#fff}
.
<span class="the subject ofdefinitions of>
<link rel="claim that thehave developed<table width="celebration ofFollowing the to distinguish<span class="btakes place inunder the namenoted that the><![endif]-->
style="margin-instead of theintroduced thethe process ofincreasing thedifferences inestimated thatespecially the/div><div id="was eventuallythroughout histhe differencesomething thatspan></span></significantly ></script>

environmental to prevent thehave been usedespecially forunderstand theis essentiallywere the firstis the largesthave been made" src="http://interpreted assecond half ofcrolling="no" is composed ofII, Holy Romanis expected tohave their owndefined as thetraditionally have differentare often usedto ensure thatagreement withcontaining theare frequentlyinformation onexample is theresulting in a</a></li></ul> class="footerand especiallytype="button" </span></span>which included>
<meta name="considered thecarried out byHowever, it isbecame part ofin relation topopular in thethe capital ofwas officiallywhich has beenthe History ofalternative todifferent fromto support thesuggested thatin the process  <div class="the foundationbecause of hisconcerned withthe universityopposed to thethe context of<span class="ptext" name="q"		<div class="the scientificrepresented bymathematicianselected by thethat have been><div class="cdiv id="headerin particular,converted into);
</script>
<philosophical srpskohrvatskitiếng ViệtРусскийрусскийinvestigaciónparticipaciónкоторыеобластикоторыйчеловексистемыНовостикоторыхобластьвременикотораясегодняскачатьновостиУкраинывопросыкоторойсделатьпомощьюсредствобразомстороныучастиетечениеГлавнаяисториисистемарешенияСкачатьпоэтомуследуетсказатьтоваровконечнорешениекотороеоргановкоторомРекламаالمنتدىمنتدياتالموضوعالبرامجالمواقعالرسائلمشاركاتالأعضاءالرياضةالتصميمالاعضاءالنتائجالألعابالتسجيلالأقسامالضغطاتالفيديوالترحيبالجديدةالتعليمالأخبارالافلامالأفلامالتاريخالتقنيةالالعابالخواطرالمجتمعالديكورالسياحةعبداللهالتربيةالروابطالأدبيةالاخبارالمتحدةالاغانيcursor:pointer;</title>
<meta " href="http://"><span class="members of the window.locationvertical-align:/a> | <a href="<!doctype html>media="screen" <option value="favicon.ico" />
		<div class="characteristics" method="get" /body>
</html>
shortcut icon" document.write(padding-bottom:representativessubmit" value="align="center" throughout the science fiction
  <div class="submit" class="one of the most valign="top"><was established);
</script>
return false;">).style.displaybecause of the document.cookie<form action="/}body{margin:0;Encyclopedia ofversion of the .createElement(name" content="</div>
</div>

administrative </body>
</html>history of the "><input type="portion of the as part of the &nbsp;<a href="other countries">
<div class="</span></span><In other words,display: block;control of the introduction of/>
<meta name="as well as the in recent years
	<div class="</div>
	</div>
inspired by thethe end of the compatible withbecame known as style="margin:.js"></script>< International there have beenGerman language style="color:#Communist Partyconsistent withborder="0" cell marginheight="the majority of" align="centerrelated to the many different Orthodox Churchsimilar to the />
<link rel="swas one of the until his death})();
</script>other languagescompared to theportions of thethe Netherlandsthe most commonbackground:url(argued that thescrolling="no" included in theNorth American the name of theinterpretationsthe traditionaldevelopment of frequently useda collection ofvery similar tosurrounding theexample of thisalign="center">would have beenimage_caption =attached to thesuggesting thatin the form of involved in theis derived fromnamed after theIntroduction torestrictions on style="width: can be used to the creation ofmost important information andresulted in thecollapse of theThis means thatelements of thewas replaced byanalysis of theinspiration forregarded as themost successfulknown as &quot;a comprehensiveHistory of the were consideredreturned to theare referred toUnsourced image>
	<div class="consists of thestopPropagationinterest in theavailability ofappears to haveelectromagneticenableServices(function of theIt is important</script></div>function(){var relative to theas a result of the position ofFor example, in method="post" was followed by&amp;mdash; thethe applicationjs"></script>
ul></div></div>after the deathwith respect tostyle="padding:is particularlydisplay:inline; type="submit" is divided into中文 (简体)responsabilidadadministracióninternacionalescorrespondienteउपयोगपूर्वहमारेलोगोंचुनावलेकिनसरकारपुलिसखोजेंचाहिएभेजेंशामिलहमारीजागरणबनानेकुमारब्लॉगमालिकमहिलापृष्ठबढ़तेभाजपाक्लिकट्रेनखिलाफदौरानमामलेमतदानबाजारविकासक्योंचाहतेपहुँचबतायासंवाददेखनेपिछलेविशेषराज्यउत्तरमुंबईदोनोंउपकरणपढ़ेंस्थितफिल्ममुख्यअच्छाछूटतीसंगीतजाएगाविभागघण्टेदूसरेदिनोंहत्यासेक्सगांधीविश्वरातेंदैट्सनक्शासामनेअदालतबिजलीपुरूषहिंदीमित्रकवितारुपयेस्थानकरोड़मुक्तयोजनाकृपयापोस्टघरेलूकार्यविचारसूचनामूल्यदेखेंहमेशास्कूलमैंनेतैयारजिसकेrss+xml" title="-type" content="title" content="at the same time.js"></script>
<" method="post" </span></a></li>vertical-align:t/jquery.min.js">.click(function( style="padding-})();
</script>
</span><a href="<a href="http://); return false;text-decoration: scrolling="no" border-collapse:associated with Bahasa IndonesiaEnglish language<text xml:space=.gif" border="0"</body>
</html>
overflow:hidden;img src="http://addEventListenerresponsible for s.js"></script>
/favicon.ico" />operating system" style="width:1target="_blank">State Universitytext-align:left;
document.write(, including the around the world);
</script>
<" style="height:;overflow:hiddenmore informationan internationala member of the one of the firstcan be found in </div>
		</div>
display: none;">" />
<link rel="
  (function() {the 15th century.preventDefault(large number of Byzantine Empire.jpg|thumb|left|vast majority ofmajority of the  align="center">University Pressdominated by theSecond World Wardistribution of style="position:the rest of the characterized by rel="nofollow">derives from therather than the a combination ofstyle="width:100English-speakingcomputer scienceborder="0" alt="the existence ofDemocratic Party" style="margin-For this reason,.js"></script>
	sByTagName(s)[0]js"></script>
<.js"></script>
link rel="icon" ' alt='' class='formation of theversions of the </a></div></div>/page>
  <page>
<div class="contbecame the firstbahasa Indonesiaenglish (simple)ΕλληνικάхрватскикомпанииявляетсяДобавитьчеловекаразвитияИнтернетОтветитьнапримеринтернеткоторогостраницыкачествеусловияхпроблемыполучитьявляютсянаиболеекомпаниявниманиесредстваالمواضيعالرئيسيةالانتقالمشاركاتكالسياراتالمكتوبةالسعوديةاحصائياتالعالميةالصوتياتالانترنتالتصاميمالإسلاميالمشاركةالمرئياتrobots" content="<div id="footer">the United States<img src="http://.jpg|right|thumb|.js"></script>
<location.protocolframeborder="0" s" />
<meta name="</a></div></div><font-weight:bold;&quot; and &quot;depending on the margin:0;padding:" rel="nofollow" President of the twentieth centuryevision>
  </pageInternet Explorera.async = true;
information about<div id="header">" action="http://<a href="https://<div id="content"</div>
</div>
<derived from the <img src='http://according to the 
</body>
</html>
style="font-size:script language="Arial, Helvetica,</a><span class="</script><script political partiestd></tr></table><href="http://www.interpretation ofrel="stylesheet" document.write('<charset="utf-8">
beginning of the revealed that thetelevision series" rel="nofollow"> target="_blank">claiming that thehttp%3A%2F%2Fwww.manifestations ofPrime Minister ofinfluenced by theclass="clearfix">/div>
</div>

three-dimensionalChurch of Englandof North Carolinasquare kilometres.addEventListenerdistinct from thecommonly known asPhonetic Alphabetdeclared that thecontrolled by theBenjamin Franklinrole-playing gamethe University ofin Western Europepersonal computerProject Gutenbergregardless of thehas been proposedtogether with the></li><li class="in some countriesmin.js"></script>of the populationofficial language<img src="images/identified by thenatural resourcesclassification ofcan be consideredquantum mechanicsNevertheless, themillion years ago</body>
</html>
Ελληνικά
take advantage ofand, according toattributed to theMicrosoft Windowsthe first centuryunder the controldiv class="headershortly after thenotable exceptiontens of thousandsseveral differentaround the world.reaching militaryisolated from theopposition to thethe Old TestamentAfrican Americansinserted into theseparate from themetropolitan areamakes it possibleacknowledged thatarguably the mosttype="text/css">
the InternationalAccording to the pe="text/css" />
coincide with thetwo-thirds of theDuring this time,during the periodannounced that hethe internationaland more recentlybelieved that theconsciousness andformerly known assurrounded by thefirst appeared inoccasionally usedposition:absolute;" target="_blank" position:relative;text-align:center;jax/libs/jquery/1.background-color:#type="application/anguage" content="<meta http-equiv="Privacy Policy</a>e("%3Cscript src='" target="_blank">On the other hand,.jpg|thumb|right|2</div><div class="<div style="float:nineteenth century</body>
</html>
<img src="http://s;text-align:centerfont-weight: bold; According to the difference between" frameborder="0" " style="position:link href="http://html4/loose.dtd">
during this period</td></tr></table>closely related tofor the first time;font-weight:bold;input type="text" <span style="font-onreadystatechange	<div class="cleardocument.location. For example, the a wide variety of <!DOCTYPE html>
<&nbsp;&nbsp;&nbsp;"><a href="http://style="float:left;concerned with the=http%3A%2F%2Fwww.in popular culturetype="text/css" />it is possible to Harvard Universitytylesheet" href="/the main characterOxford University  name="keywords" cstyle="text-align:the United Kingdomfederal government<div style="margin depending on the description of the<div class="header.min.js"></script>destruction of theslightly differentin accordance withtelecommunicationsindicates that theshortly thereafterespecially in the European countriesHowever, there aresrc="http://staticsuggested that the" src="http://www.a large number of Telecommunications" rel="nofollow" tHoly Roman Emperoralmost exclusively" border="0" alt="Secretary of Stateculminating in theCIA World Factbookthe most importantanniversary of thestyle="background-<li><em><a href="/the Atlantic Oceanstrictly speaking,shortly before thedifferent types ofthe Ottoman Empire><img src="http://An Introduction toconsequence of thedeparture from theConfederate Statesindigenous peoplesProceedings of theinformation on thetheories have beeninvolvement in thedivided into threeadjacent countriesis responsible fordissolution of thecollaboration withwidely regarded ashis contemporariesfounding member ofDominican Republicgenerally acceptedthe possibility ofare also availableunder constructionrestoration of thethe general publicis almost entirelypasses through thehas been suggestedcomputer and videoGermanic languages according to the different from theshortly afterwardshref="https://www.recent developmentBoard of Directors<div class="search| <a href="http://In particular, theMultiple footnotesor other substancethousands of yearstranslation of the</div>
</div>

<a href="index.phpwas established inmin.js"></script>
participate in thea strong influencestyle="margin-top:represented by thegraduated from theTraditionally, theElement("script");However, since the/div>
</div>
<div left; margin-left:protection against0; vertical-align:Unfortunately, thetype="image/x-icon/div>
<div class=" class="clearfix"><div class="footer		</div>
		</div>
the motion pictureБългарскибългарскиФедерациинесколькосообщениесообщенияпрограммыОтправитьбесплатноматериалыпозволяетпоследниеразличныхпродукциипрограммаполностьюнаходитсяизбранноенаселенияизменениякатегорииАлександрद्वारामैनुअलप्रदानभारतीयअनुदेशहिन्दीइंडियादिल्लीअधिकारवीडियोचिट्ठेसमाचारजंक्शनदुनियाप्रयोगअनुसारऑनलाइनपार्टीशर्तोंलोकसभाफ़्लैशशर्तेंप्रदेशप्लेयरकेंद्रस्थितिउत्पादउन्हेंचिट्ठायात्राज्यादापुरानेजोड़ेंअनुवादश्रेणीशिक्षासरकारीसंग्रहपरिणामब्रांडबच्चोंउपलब्धमंत्रीसंपर्कउम्मीदमाध्यमसहायताशब्दोंमीडियाआईपीएलमोबाइलसंख्याआपरेशनअनुबंधबाज़ारनवीनतमप्रमुखप्रश्नपरिवारनुकसानसमर्थनआयोजितसोमवारالمشاركاتالمنتدياتالكمبيوترالمشاهداتعددالزوارعددالردودالإسلاميةالفوتوشوبالمسابقاتالمعلوماتالمسلسلاتالجرافيكسالاسلاميةالاتصالاتkeywords" content="w3.org/1999/xhtml"><a target="_blank" text/html; charset=" target="_blank"><table cellpadding="autocomplete="off" text-align: center;to last version by background-color: #" href="http://www./div></div><div id=<a href="#" class=""><img src="http://cript" src="http://
<script language="//EN" "http://www.wencodeURIComponent(" href="javascript:<div class="contentdocument.write('<scposition: absolute;script src="http:// style="margin-top:.min.js"></script>
</div>
<div class="w3.org/1999/xhtml" 

</body>
</html>distinction between/" target="_blank"><link href="http://encoding="utf-8"?>
w.addEventListener?action="http://www.icon" href="http:// style="background:type="text/css" />
meta property="og:t<input type="text"  style="text-align:the development of tylesheet" type="tehtml; charset=utf-8is considered to betable width="100%" In addition to the contributed to the differences betweendevelopment of the It is important to </script>

<script  style="font-size:1></span><span id=gbLibrary of Congress<img src="http://imEnglish translationAcademy of Sciencesdiv style="display:construction of the.getElementById(id)in conjunction withElement('script'); <meta property="og:Български
 type="text" name=">Privacy Policy</a>administered by theenableSingleRequeststyle=&quot;margin:</div></div></div><><img src="http://i style=&quot;float:referred to as the total population ofin Washington, D.C. style="background-among other things,organization of theparticipated in thethe introduction ofidentified with thefictional character Oxford University misunderstanding ofThere are, however,stylesheet" href="/Columbia Universityexpanded to includeusually referred toindicating that thehave suggested thataffiliated with thecorrelation betweennumber of different></td></tr></table>Republic of Ireland
</script>
<script under the influencecontribution to theOfficial website ofheadquarters of thecentered around theimplications of thehave been developedFederal Republic ofbecame increasinglycontinuation of theNote, however, thatsimilar to that of capabilities of theaccordance with theparticipants in thefurther developmentunder the directionis often consideredhis younger brother</td></tr></table><a http-equiv="X-UA-physical propertiesof British Columbiahas been criticized(with the exceptionquestions about thepassing through the0" cellpadding="0" thousands of peopleredirects here. Forhave children under%3E%3C/script%3E"));<a href="http://www.<li><a href="http://site_name" content="text-decoration:nonestyle="display: none<meta http-equiv="X-new Date().getTime() type="image/x-icon"</span><span class="language="javascriptwindow.location.href<a href="javascript:-->
<script type="t<a href='http://www.hortcut icon" href="</div>
<div class="<script src="http://" rel="stylesheet" t</div>
<script type=/a> <a href="http:// allowTransparency="X-UA-Compatible" conrelationship between
</script>
<script </a></li></ul></div>associated with the programming language</a><a href="http://</a></li><li class="form action="http://<div style="display:type="text" name="q"<table width="100%" background-position:" border="0" width="rel="shortcut icon" h6><ul><li><a href="  <meta http-equiv="css" media="screen" responsible for the " type="application/" style="background-html; charset=utf-8" allowtransparency="stylesheet" type="te
<meta http-equiv="></span><span class="0" cellspacing="0">;
</script>
<script sometimes called thedoes not necessarilyFor more informationat the beginning of <!DOCTYPE html><htmlparticularly in the type="hidden" name="javascript:void(0);"effectiveness of the autocomplete="off" generally considered><input type="text" "></script>
<scriptthroughout the worldcommon misconceptionassociation with the</div>
</div>
<div cduring his lifetime,corresponding to thetype="image/x-icon" an increasing numberdiplomatic relationsare often consideredmeta charset="utf-8" <input type="text" examples include the"><img src="http://iparticipation in thethe establishment of
</div>
<div class="&amp;nbsp;&amp;nbsp;to determine whetherquite different frommarked the beginningdistance between thecontributions to theconflict between thewidely considered towas one of the firstwith varying degreeshave speculated that(document.getElementparticipating in theoriginally developedeta charset="utf-8"> type="text/css" />
interchangeably withmore closely relatedsocial and politicalthat would otherwiseperpendicular to thestyle type="text/csstype="submit" name="families residing indeveloping countriescomputer programmingeconomic developmentdetermination of thefor more informationon several occasionsportuguês (Europeu)УкраїнськаукраїнськаРоссийскойматериаловинформацииуправлениянеобходимоинформацияИнформацияРеспубликиколичествоинформациютерриториидостаточноالمتواجدونالاشتراكاتالاقتراحاتhtml; charset=UTF-8" setTimeout(function()display:inline-block;<input type="submit" type = 'text/javascri<img src="http://www." "http://www.w3.org/shortcut icon" href="" autocomplete="off" </a></div><div class=</a></li>
<li class="css" type="text/css" <form action="http://xt/css" href="http://link rel="alternate" 
<script type="text/ onclick="javascript:(new Date).getTime()}height="1" width="1" People's Republic of  <a href="http://www.text-decoration:underthe beginning of the </div>
</div>
</div>
establishment of the </div></div></div></d#viewport{min-height:
<script src="http://option><option value=often referred to as /option>
<option valu<!DOCTYPE html>
<!--[International Airport>
<a href="http://www</a><a href="http://wภาษาไทยქართული正體中文 (繁體)निर्देशडाउनलोडक्षेत्रजानकारीसंबंधितस्थापनास्वीकारसंस्करणसामग्रीचिट्ठोंविज्ञानअमेरिकाविभिन्नगाडियाँक्योंकिसुरक्षापहुँचतीप्रबंधनटिप्पणीक्रिकेटप्रारंभप्राप्तमालिकोंरफ़्तारनिर्माणलिमिटेडdescription" content="document.location.prot.getElementsByTagName(<!DOCTYPE html>
<html <meta charset="utf-8">:url" content="http://.css" rel="stylesheet"style type="text/css">type="text/css" href="w3.org/1999/xhtml" xmltype="text/javascript" method="get" action="link rel="stylesheet"  = document.getElementtype="image/x-icon" />cellpadding="0" cellsp.css" type="text/css" </a></li><li><a href="" width="1" height="1""><a href="http://www.style="display:none;">alternate" type="appli-//W3C//DTD XHTML 1.0 ellspacing="0" cellpad type="hidden" value="/a>&nbsp;<span role="s
<input type="hidden" language="JavaScript"  document.getElementsBg="0" cellspacing="0" ype="text/css" media="type='text/javascript'with the exception of ype="text/css" rel="st height="1" width="1" ='+encodeURIComponent(<link rel="alternate" 
body, tr, input, textmeta name="robots" conmethod="post" action=">
<a href="http://www.css" rel="stylesheet" </div></div><div classlanguage="javascript">aria-hidden="true">·<ript" type="text/javasl=0;})();
(function(){background-image: url(/a></li><li><a href="h		<li><a href="http://ator" aria-hidden="tru> <a href="http://www.language="javascript" /option>
<option value/div></div><div class=rator" aria-hidden="tre=(new Date).getTime()português (do Brasil)организациивозможностьобразованиярегистрациивозможностиобязательна<!DOCTYPE html PUBLIC "nt-Type" content="text/<meta http-equiv="Conteransitional//EN" "http:<html xmlns="http://www-//W3C//DTD XHTML 1.0 TDTD/xhtml1-transitional//www.w3.org/TR/xhtml1/pe = 'text/javascript';<meta name="descriptionparentNode.insertBefore<input type="hidden" najs" type="text/javascri(document).ready(functiscript type="text/javasimage" content="http://UA-Compatible" content=tml; charset=utf-8" />
link rel="shortcut icon<link rel="stylesheet" </script>
<script type== document.createElemen<a target="_blank" href= document.getElementsBinput type="text" name=a.type = 'text/javascrinput type="hidden" namehtml; charset=utf-8" />dtd">
<html xmlns="http-//W3C//DTD HTML 4.01 TentsByTagName('script')input type="hidden" nam<script type="text/javas" style="display:none;">document.getElementById(=document.createElement(' type='text/javascript'input type="text" name="d.getElementsByTagName(snical" href="http://www.C//DTD HTML 4.01 Transit<style type="text/css">

<style type="text/css">ional.dtd">
<html xmlns=http-equiv="Content-Typeding="0" cellspacing="0"html; charset=utf-8" />
 style="display:none;"><<li><a href="http://www. type='text/javascript'>деятельностисоответствиипроизводствабезопасностиपुस्तिकाकांग्रेसउन्होंनेविधानसभाफिक्सिंगसुरक्षितकॉपीराइटविज्ञापनकार्रवाईसक्रियता1 11     111
 1 /  1  1 1
11 1
111  1  
 1 1 	0  1 1 1 
1 111 
1 11111 1  
11  1  111 1 1 1 1111/ 1111 111 1 1 1111 1   1 1111111 1
111 1  / 111	1 
1
 1 1

1   # 1/ 1
1 $1 !  1
1
1 %  1 &  1 ' 11 "11
  1 ( 
1 )1 *11 + 
1
  "1
!1 ,1- 1  !1
11 .11
" 
!  1!11 1"  
 " 
"                              # % * - / 2 4 : > E G N U Z \ c h m r w z |                                                  ,  of the  of s . and  in " to ">
. ] for  a  that ' with  from  by (. The  on  as  is ing 
	:ed =" at ly ,='.com/. This  not er al ful ive less est ize  ous  the e     ;T   	    p   P       0   @   P   `      (             zR x  $      0    FJw ?;*3$"       D                 \   h          p   d             `             \             X                   4      t   BLG A(
 DBBA                                                                                                                                   






		                               $   T               $  T  n             @               (                              
     	     y                          * ? 8 0 ; @                          *                    
                                                                 o    `                                
       K                                       0                                                            	              o          o           o    \      o                                                                                                                                                                6      F            /usr/lib/debug/.dwz/x86_64-linux-gnu/libbrotli1.debug >ץ0p>p3_m^Z  5835e993c63c2c099a561000188b190df888b1.debug    $c .shstrtab .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rela.dyn .rela.plt .init .plt.got .text .fini .rodata .eh_frame_hdr .eh_frame .init_array .fini_array .data.rel.ro .dynamic .got.plt .data .bss .gnu_debugaltlink .gnu_debuglink                                                                                8      8      $                                 o       `      `      D                             (                         h                          0                         K                             8   o       \      \                                  E   o                                                T                                                    ^      B                   0                           h                                                         c                           0                             n             P      P                                   w             `      `      4                             }                         	                                                                                                                  T                                           X     X                                                                                                                                                                                                                 
                                r                                                                            (                                                                                                                                                                    J                                                    d     4                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      